summaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2ops.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--fs/cifs/smb2ops.c95
1 files changed, 82 insertions, 13 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index f522193b7184..96b5d40a2ece 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -176,10 +176,11 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
{
struct mid_q_entry *mid;
struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
+ __u64 wire_mid = le64_to_cpu(hdr->MessageId);
spin_lock(&GlobalMid_Lock);
list_for_each_entry(mid, &server->pending_mid_q, qhead) {
- if ((mid->mid == hdr->MessageId) &&
+ if ((mid->mid == wire_mid) &&
(mid->mid_state == MID_REQUEST_SUBMITTED) &&
(mid->command == hdr->Command)) {
spin_unlock(&GlobalMid_Lock);
@@ -265,15 +266,18 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
NULL /* no data input */, 0 /* no data input */,
(char **)&out_buf, &ret_data_len);
-
- if ((rc == 0) && (ret_data_len > 0)) {
+ if (rc != 0)
+ cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
+ else if (ret_data_len < sizeof(struct network_interface_info_ioctl_rsp)) {
+ cifs_dbg(VFS, "server returned bad net interface info buf\n");
+ rc = -EINVAL;
+ } else {
/* Dump info on first interface */
cifs_dbg(FYI, "Adapter Capability 0x%x\t",
le32_to_cpu(out_buf->Capability));
cifs_dbg(FYI, "Link Speed %lld\n",
le64_to_cpu(out_buf->LinkSpeed));
- } else
- cifs_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
+ }
return rc;
}
@@ -597,7 +601,7 @@ smb2_clone_range(const unsigned int xid,
goto cchunk_out;
/* For now array only one chunk long, will make more flexible later */
- pcchunk->ChunkCount = __constant_cpu_to_le32(1);
+ pcchunk->ChunkCount = cpu_to_le32(1);
pcchunk->Reserved = 0;
pcchunk->Reserved2 = 0;
@@ -711,23 +715,23 @@ smb2_read_data_length(char *buf)
static int
-smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
+smb2_sync_read(const unsigned int xid, struct cifs_fid *pfid,
struct cifs_io_parms *parms, unsigned int *bytes_read,
char **buf, int *buf_type)
{
- parms->persistent_fid = cfile->fid.persistent_fid;
- parms->volatile_fid = cfile->fid.volatile_fid;
+ parms->persistent_fid = pfid->persistent_fid;
+ parms->volatile_fid = pfid->volatile_fid;
return SMB2_read(xid, parms, bytes_read, buf, buf_type);
}
static int
-smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
+smb2_sync_write(const unsigned int xid, struct cifs_fid *pfid,
struct cifs_io_parms *parms, unsigned int *written,
struct kvec *iov, unsigned long nr_segs)
{
- parms->persistent_fid = cfile->fid.persistent_fid;
- parms->volatile_fid = cfile->fid.volatile_fid;
+ parms->persistent_fid = pfid->persistent_fid;
+ parms->volatile_fid = pfid->volatile_fid;
return SMB2_write(xid, parms, written, iov, nr_segs);
}
@@ -1099,6 +1103,64 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
return rc;
}
+static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
+ loff_t off, loff_t len, bool keep_size)
+{
+ struct inode *inode;
+ struct cifsInodeInfo *cifsi;
+ struct cifsFileInfo *cfile = file->private_data;
+ long rc = -EOPNOTSUPP;
+ unsigned int xid;
+
+ xid = get_xid();
+
+ inode = cfile->dentry->d_inode;
+ cifsi = CIFS_I(inode);
+
+ /* if file not oplocked can't be sure whether asking to extend size */
+ if (!CIFS_CACHE_READ(cifsi))
+ if (keep_size == false)
+ return -EOPNOTSUPP;
+
+ /*
+ * Files are non-sparse by default so falloc may be a no-op
+ * Must check if file sparse. If not sparse, and not extending
+ * then no need to do anything since file already allocated
+ */
+ if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) == 0) {
+ if (keep_size == true)
+ return 0;
+ /* check if extending file */
+ else if (i_size_read(inode) >= off + len)
+ /* not extending file and already not sparse */
+ return 0;
+ /* BB: in future add else clause to extend file */
+ else
+ return -EOPNOTSUPP;
+ }
+
+ if ((keep_size == true) || (i_size_read(inode) >= off + len)) {
+ /*
+ * Check if falloc starts within first few pages of file
+ * and ends within a few pages of the end of file to
+ * ensure that most of file is being forced to be
+ * fallocated now. If so then setting whole file sparse
+ * ie potentially making a few extra pages at the beginning
+ * or end of the file non-sparse via set_sparse is harmless.
+ */
+ if ((off > 8192) || (off + len + 8192 < i_size_read(inode)))
+ return -EOPNOTSUPP;
+
+ rc = smb2_set_sparse(xid, tcon, cfile, inode, false);
+ }
+ /* BB: else ... in future add code to extend file and set sparse */
+
+
+ free_xid(xid);
+ return rc;
+}
+
+
static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
loff_t off, loff_t len)
{
@@ -1109,7 +1171,10 @@ static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
if (mode & FALLOC_FL_KEEP_SIZE)
return smb3_zero_range(file, tcon, off, len, true);
return smb3_zero_range(file, tcon, off, len, false);
- }
+ } else if (mode == FALLOC_FL_KEEP_SIZE)
+ return smb3_simple_falloc(file, tcon, off, len, true);
+ else if (mode == 0)
+ return smb3_simple_falloc(file, tcon, off, len, false);
return -EOPNOTSUPP;
}
@@ -1452,6 +1517,8 @@ struct smb_version_operations smb21_operations = {
.rename = smb2_rename_path,
.create_hardlink = smb2_create_hardlink,
.query_symlink = smb2_query_symlink,
+ .query_mf_symlink = smb3_query_mf_symlink,
+ .create_mf_symlink = smb3_create_mf_symlink,
.open = smb2_open_file,
.set_fid = smb2_set_fid,
.close = smb2_close_file,
@@ -1531,6 +1598,8 @@ struct smb_version_operations smb30_operations = {
.rename = smb2_rename_path,
.create_hardlink = smb2_create_hardlink,
.query_symlink = smb2_query_symlink,
+ .query_mf_symlink = smb3_query_mf_symlink,
+ .create_mf_symlink = smb3_create_mf_symlink,
.open = smb2_open_file,
.set_fid = smb2_set_fid,
.close = smb2_close_file,