Message ID | 20190417063410.6371-1-lsahlber@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | cifs: add SEEK_HOLE/SEEK_DATA support | expand |
-- Best regards, Pavel Shilovsky вт, 16 апр. 2019 г. в 23:35, Ronnie Sahlberg <lsahlber@redhat.com>: > > Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> > --- > fs/cifs/cifsfs.c | 9 ++++++++ > fs/cifs/cifsglob.h | 2 ++ > fs/cifs/smb2ops.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > fs/cifs/smb2pdu.c | 7 +++++- > fs/cifs/smb2pdu.h | 5 +++++ > fs/cifs/smbfsctl.h | 2 +- > 6 files changed, 88 insertions(+), 2 deletions(-) > > diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c > index 07fdf1771add..a00ef6c6a988 100644 > --- a/fs/cifs/cifsfs.c > +++ b/fs/cifs/cifsfs.c > @@ -884,6 +884,9 @@ static ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) > > static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) > { > + struct cifsFileInfo *cfile = file->private_data; > + struct cifs_tcon *tcon; > + > /* > * whence == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate > * the cached file length > @@ -915,6 +918,12 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) > if (rc < 0) > return (loff_t)rc; > } > + if (cfile && cfile->tlink) { > + tcon = tlink_tcon(cfile->tlink); > + if (tcon->ses->server->ops->llseek) > + return tcon->ses->server->ops->llseek(file, tcon, > + offset, whence); > + } > return generic_file_llseek(file, offset, whence); > } > > diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h > index 0dc55f4e6929..828772da5fa4 100644 > --- a/fs/cifs/cifsglob.h > +++ b/fs/cifs/cifsglob.h > @@ -493,6 +493,8 @@ struct smb_version_operations { > char *full_path, > umode_t mode, > dev_t device_number); > + /* version specific llseek implementation */ > + loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int); > }; > > struct smb_version_values { > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c > index 2824b97c5869..dc36316b9bd5 100644 > --- a/fs/cifs/smb2ops.c > +++ b/fs/cifs/smb2ops.c > @@ -2872,6 +2872,69 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, > return rc; > } > > +static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offset, int whence) > +{ > + struct cifsFileInfo *cfile = file->private_data; > + struct cifsInodeInfo *cifsi; > + struct inode *inode; > + int rc = 0; > + struct fsctl_query_allocate_ranges in_data, *out_data = NULL; > + u32 out_data_len; > + unsigned int xid; > + > + if (whence != SEEK_HOLE && whence != SEEK_DATA) > + return generic_file_llseek(file, offset, whence); > + > + inode = d_inode(cfile->dentry); > + cifsi = CIFS_I(inode); > + > + if (offset < 0 || offset > i_size_read(inode)) > + return -ENXIO; > + > + if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) { > + if (whence == SEEK_HOLE) > + offset = i_size_read(inode); > + else > + offset = offset; > + goto lseek_exit; > + } > + > + in_data.file_offset = cpu_to_le64(offset); > + in_data.length = cpu_to_le64(i_size_read(inode)); > + > + xid = get_xid(); > + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, > + cfile->fid.volatile_fid, > + FSCTL_QUERY_ALLOCATED_RANGES, true, > + (char *)&in_data, sizeof(in_data), > + sizeof(struct fsctl_query_allocate_ranges), > + (char **)&out_data, &out_data_len); > + free_xid(xid); > + if (rc == -E2BIG) > + rc = 0; > + if (rc) > + goto lseek_exit; > + > + if (out_data_len < sizeof(struct fsctl_query_allocate_ranges)) { > + rc = -EINVAL; > + goto lseek_exit; > + } > + if (whence == SEEK_DATA) { > + offset = le64_to_cpu(out_data->file_offset); > + goto lseek_exit; > + } > + if (offset < le64_to_cpu(out_data->file_offset)) > + goto lseek_exit; > + > + offset = le64_to_cpu(out_data->file_offset) + le64_to_cpu(out_data->length); > + > + lseek_exit: > + kfree(out_data); > + if (!rc) > + return vfs_setpos(file, offset, inode->i_sb->s_maxbytes); > + else > + return rc; > +} > > static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode, > loff_t off, loff_t len) > @@ -4247,6 +4310,7 @@ struct smb_version_operations smb30_operations = { > .next_header = smb2_next_header, > .ioctl_query_info = smb2_ioctl_query_info, > .make_node = smb2_make_node, > + .llseek = smb3_llseek, > }; > > struct smb_version_operations smb311_operations = { > @@ -4356,6 +4420,7 @@ struct smb_version_operations smb311_operations = { > .next_header = smb2_next_header, > .ioctl_query_info = smb2_ioctl_query_info, > .make_node = smb2_make_node, > + .llseek = smb3_llseek, > }; > > struct smb_version_values smb20_values = { > diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c > index 99a015e980d2..ac92d066c724 100644 > --- a/fs/cifs/smb2pdu.c > +++ b/fs/cifs/smb2pdu.c > @@ -2625,7 +2625,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, > trace_smb3_fsctl_err(xid, persistent_fid, tcon->tid, > ses->Suid, 0, opcode, rc); > > - if ((rc != 0) && (rc != -EINVAL)) { > + if ((rc != 0) && (rc != -EINVAL) && (rc != -E2BIG)) { > cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); > goto ioctl_exit; > } else if (rc == -EINVAL) { > @@ -2634,6 +2634,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, > cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); > goto ioctl_exit; > } > + } else if (rc == -E2BIG) { > + if (opcode != FSCTL_QUERY_ALLOCATED_RANGES) { > + cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); > + goto ioctl_exit; > + } > } > > /* check if caller wants to look at return data or just return rc */ > diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h > index ee8977688e21..3a29db740fe6 100644 > --- a/fs/cifs/smb2pdu.h > +++ b/fs/cifs/smb2pdu.h > @@ -842,6 +842,11 @@ struct fsctl_get_integrity_information_rsp { > __le32 ClusterSizeInBytes; > } __packed; > > +struct fsctl_query_allocate_ranges { This describes one range, so should be fsctl_query_allocate_range or even file_allocated_range_buffer as specified here: https://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_file_allocated_range_buffer > + __le64 file_offset; > + __le64 length; > +} __packed; > + > /* Integrity ChecksumAlgorithm choices for above */ > #define CHECKSUM_TYPE_NONE 0x0000 > #define CHECKSUM_TYPE_CRC64 0x0002 > diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h > index 9b3459b9a5ce..08628e6a42ac 100644 > --- a/fs/cifs/smbfsctl.h > +++ b/fs/cifs/smbfsctl.h > @@ -103,7 +103,7 @@ > #define FSCTL_SET_ZERO_ON_DEALLOC 0x00090194 /* BB add struct */ > #define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */ > #define FSCTL_GET_INTEGRITY_INFORMATION 0x0009027C > -#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF /* BB add struct */ > +#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF > #define FSCTL_SET_DEFECT_MANAGEMENT 0x00098134 /* BB add struct */ > #define FSCTL_FILE_LEVEL_TRIM 0x00098208 /* BB add struct */ > #define FSCTL_DUPLICATE_EXTENTS_TO_FILE 0x00098344 > -- > 2.13.6 >
----- Original Message ----- > From: "Pavel Shilovsky" <piastryyy@gmail.com> > To: "Ronnie Sahlberg" <lsahlber@redhat.com> > Cc: "linux-cifs" <linux-cifs@vger.kernel.org>, "Steve French" <smfrench@gmail.com> > Sent: Thursday, 18 April, 2019 7:41:44 AM > Subject: Re: [PATCH] cifs: add SEEK_HOLE/SEEK_DATA support > > -- > Best regards, > Pavel Shilovsky > > вт, 16 апр. 2019 г. в 23:35, Ronnie Sahlberg <lsahlber@redhat.com>: > > > > Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> > > --- > > fs/cifs/cifsfs.c | 9 ++++++++ > > fs/cifs/cifsglob.h | 2 ++ > > fs/cifs/smb2ops.c | 65 > > ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > > fs/cifs/smb2pdu.c | 7 +++++- > > fs/cifs/smb2pdu.h | 5 +++++ > > fs/cifs/smbfsctl.h | 2 +- > > 6 files changed, 88 insertions(+), 2 deletions(-) > > > > diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c > > index 07fdf1771add..a00ef6c6a988 100644 > > --- a/fs/cifs/cifsfs.c > > +++ b/fs/cifs/cifsfs.c > > @@ -884,6 +884,9 @@ static ssize_t cifs_file_write_iter(struct kiocb *iocb, > > struct iov_iter *from) > > > > static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) > > { > > + struct cifsFileInfo *cfile = file->private_data; > > + struct cifs_tcon *tcon; > > + > > /* > > * whence == SEEK_END || SEEK_DATA || SEEK_HOLE => we must > > revalidate > > * the cached file length > > @@ -915,6 +918,12 @@ static loff_t cifs_llseek(struct file *file, loff_t > > offset, int whence) > > if (rc < 0) > > return (loff_t)rc; > > } > > + if (cfile && cfile->tlink) { > > + tcon = tlink_tcon(cfile->tlink); > > + if (tcon->ses->server->ops->llseek) > > + return tcon->ses->server->ops->llseek(file, tcon, > > + offset, > > whence); > > + } > > return generic_file_llseek(file, offset, whence); > > } > > > > diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h > > index 0dc55f4e6929..828772da5fa4 100644 > > --- a/fs/cifs/cifsglob.h > > +++ b/fs/cifs/cifsglob.h > > @@ -493,6 +493,8 @@ struct smb_version_operations { > > char *full_path, > > umode_t mode, > > dev_t device_number); > > + /* version specific llseek implementation */ > > + loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int); > > }; > > > > struct smb_version_values { > > diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c > > index 2824b97c5869..dc36316b9bd5 100644 > > --- a/fs/cifs/smb2ops.c > > +++ b/fs/cifs/smb2ops.c > > @@ -2872,6 +2872,69 @@ static long smb3_simple_falloc(struct file *file, > > struct cifs_tcon *tcon, > > return rc; > > } > > > > +static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, > > loff_t offset, int whence) > > +{ > > + struct cifsFileInfo *cfile = file->private_data; > > + struct cifsInodeInfo *cifsi; > > + struct inode *inode; > > + int rc = 0; > > + struct fsctl_query_allocate_ranges in_data, *out_data = NULL; > > + u32 out_data_len; > > + unsigned int xid; > > + > > + if (whence != SEEK_HOLE && whence != SEEK_DATA) > > + return generic_file_llseek(file, offset, whence); > > + > > + inode = d_inode(cfile->dentry); > > + cifsi = CIFS_I(inode); > > + > > + if (offset < 0 || offset > i_size_read(inode)) > > + return -ENXIO; > > + > > + if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) { > > + if (whence == SEEK_HOLE) > > + offset = i_size_read(inode); > > + else > > + offset = offset; > > + goto lseek_exit; > > + } > > + > > + in_data.file_offset = cpu_to_le64(offset); > > + in_data.length = cpu_to_le64(i_size_read(inode)); > > + > > + xid = get_xid(); > > + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, > > + cfile->fid.volatile_fid, > > + FSCTL_QUERY_ALLOCATED_RANGES, true, > > + (char *)&in_data, sizeof(in_data), > > + sizeof(struct fsctl_query_allocate_ranges), > > + (char **)&out_data, &out_data_len); > > + free_xid(xid); > > + if (rc == -E2BIG) > > + rc = 0; > > + if (rc) > > + goto lseek_exit; > > + > > + if (out_data_len < sizeof(struct fsctl_query_allocate_ranges)) { > > + rc = -EINVAL; > > + goto lseek_exit; > > + } > > + if (whence == SEEK_DATA) { > > + offset = le64_to_cpu(out_data->file_offset); > > + goto lseek_exit; > > + } > > + if (offset < le64_to_cpu(out_data->file_offset)) > > + goto lseek_exit; > > + > > + offset = le64_to_cpu(out_data->file_offset) + > > le64_to_cpu(out_data->length); > > + > > + lseek_exit: > > + kfree(out_data); > > + if (!rc) > > + return vfs_setpos(file, offset, inode->i_sb->s_maxbytes); > > + else > > + return rc; > > +} > > > > static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int > > mode, > > loff_t off, loff_t len) > > @@ -4247,6 +4310,7 @@ struct smb_version_operations smb30_operations = { > > .next_header = smb2_next_header, > > .ioctl_query_info = smb2_ioctl_query_info, > > .make_node = smb2_make_node, > > + .llseek = smb3_llseek, > > }; > > > > struct smb_version_operations smb311_operations = { > > @@ -4356,6 +4420,7 @@ struct smb_version_operations smb311_operations = { > > .next_header = smb2_next_header, > > .ioctl_query_info = smb2_ioctl_query_info, > > .make_node = smb2_make_node, > > + .llseek = smb3_llseek, > > }; > > > > struct smb_version_values smb20_values = { > > diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c > > index 99a015e980d2..ac92d066c724 100644 > > --- a/fs/cifs/smb2pdu.c > > +++ b/fs/cifs/smb2pdu.c > > @@ -2625,7 +2625,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon > > *tcon, u64 persistent_fid, > > trace_smb3_fsctl_err(xid, persistent_fid, tcon->tid, > > ses->Suid, 0, opcode, rc); > > > > - if ((rc != 0) && (rc != -EINVAL)) { > > + if ((rc != 0) && (rc != -EINVAL) && (rc != -E2BIG)) { > > cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); > > goto ioctl_exit; > > } else if (rc == -EINVAL) { > > @@ -2634,6 +2634,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon > > *tcon, u64 persistent_fid, > > cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); > > goto ioctl_exit; > > } > > + } else if (rc == -E2BIG) { > > + if (opcode != FSCTL_QUERY_ALLOCATED_RANGES) { > > + cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); > > + goto ioctl_exit; > > + } > > } > > > > /* check if caller wants to look at return data or just return rc > > */ > > diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h > > index ee8977688e21..3a29db740fe6 100644 > > --- a/fs/cifs/smb2pdu.h > > +++ b/fs/cifs/smb2pdu.h > > @@ -842,6 +842,11 @@ struct fsctl_get_integrity_information_rsp { > > __le32 ClusterSizeInBytes; > > } __packed; > > > > +struct fsctl_query_allocate_ranges { > > This describes one range, so should be fsctl_query_allocate_range or > even file_allocated_range_buffer as specified here: > > https://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_file_allocated_range_buffer Thanks. Will resend with this change. > > > + __le64 file_offset; > > + __le64 length; > > +} __packed; > > + > > /* Integrity ChecksumAlgorithm choices for above */ > > #define CHECKSUM_TYPE_NONE 0x0000 > > #define CHECKSUM_TYPE_CRC64 0x0002 > > diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h > > index 9b3459b9a5ce..08628e6a42ac 100644 > > --- a/fs/cifs/smbfsctl.h > > +++ b/fs/cifs/smbfsctl.h > > @@ -103,7 +103,7 @@ > > #define FSCTL_SET_ZERO_ON_DEALLOC 0x00090194 /* BB add struct */ > > #define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */ > > #define FSCTL_GET_INTEGRITY_INFORMATION 0x0009027C > > -#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF /* BB add struct */ > > +#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF > > #define FSCTL_SET_DEFECT_MANAGEMENT 0x00098134 /* BB add struct */ > > #define FSCTL_FILE_LEVEL_TRIM 0x00098208 /* BB add struct */ > > #define FSCTL_DUPLICATE_EXTENTS_TO_FILE 0x00098344 > > -- > > 2.13.6 > > >
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 07fdf1771add..a00ef6c6a988 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -884,6 +884,9 @@ static ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) { + struct cifsFileInfo *cfile = file->private_data; + struct cifs_tcon *tcon; + /* * whence == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate * the cached file length @@ -915,6 +918,12 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) if (rc < 0) return (loff_t)rc; } + if (cfile && cfile->tlink) { + tcon = tlink_tcon(cfile->tlink); + if (tcon->ses->server->ops->llseek) + return tcon->ses->server->ops->llseek(file, tcon, + offset, whence); + } return generic_file_llseek(file, offset, whence); } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 0dc55f4e6929..828772da5fa4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -493,6 +493,8 @@ struct smb_version_operations { char *full_path, umode_t mode, dev_t device_number); + /* version specific llseek implementation */ + loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int); }; struct smb_version_values { diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 2824b97c5869..dc36316b9bd5 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2872,6 +2872,69 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, return rc; } +static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offset, int whence) +{ + struct cifsFileInfo *cfile = file->private_data; + struct cifsInodeInfo *cifsi; + struct inode *inode; + int rc = 0; + struct fsctl_query_allocate_ranges in_data, *out_data = NULL; + u32 out_data_len; + unsigned int xid; + + if (whence != SEEK_HOLE && whence != SEEK_DATA) + return generic_file_llseek(file, offset, whence); + + inode = d_inode(cfile->dentry); + cifsi = CIFS_I(inode); + + if (offset < 0 || offset > i_size_read(inode)) + return -ENXIO; + + if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) { + if (whence == SEEK_HOLE) + offset = i_size_read(inode); + else + offset = offset; + goto lseek_exit; + } + + in_data.file_offset = cpu_to_le64(offset); + in_data.length = cpu_to_le64(i_size_read(inode)); + + xid = get_xid(); + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, + FSCTL_QUERY_ALLOCATED_RANGES, true, + (char *)&in_data, sizeof(in_data), + sizeof(struct fsctl_query_allocate_ranges), + (char **)&out_data, &out_data_len); + free_xid(xid); + if (rc == -E2BIG) + rc = 0; + if (rc) + goto lseek_exit; + + if (out_data_len < sizeof(struct fsctl_query_allocate_ranges)) { + rc = -EINVAL; + goto lseek_exit; + } + if (whence == SEEK_DATA) { + offset = le64_to_cpu(out_data->file_offset); + goto lseek_exit; + } + if (offset < le64_to_cpu(out_data->file_offset)) + goto lseek_exit; + + offset = le64_to_cpu(out_data->file_offset) + le64_to_cpu(out_data->length); + + lseek_exit: + kfree(out_data); + if (!rc) + return vfs_setpos(file, offset, inode->i_sb->s_maxbytes); + else + return rc; +} static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode, loff_t off, loff_t len) @@ -4247,6 +4310,7 @@ struct smb_version_operations smb30_operations = { .next_header = smb2_next_header, .ioctl_query_info = smb2_ioctl_query_info, .make_node = smb2_make_node, + .llseek = smb3_llseek, }; struct smb_version_operations smb311_operations = { @@ -4356,6 +4420,7 @@ struct smb_version_operations smb311_operations = { .next_header = smb2_next_header, .ioctl_query_info = smb2_ioctl_query_info, .make_node = smb2_make_node, + .llseek = smb3_llseek, }; struct smb_version_values smb20_values = { diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 99a015e980d2..ac92d066c724 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2625,7 +2625,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, trace_smb3_fsctl_err(xid, persistent_fid, tcon->tid, ses->Suid, 0, opcode, rc); - if ((rc != 0) && (rc != -EINVAL)) { + if ((rc != 0) && (rc != -EINVAL) && (rc != -E2BIG)) { cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); goto ioctl_exit; } else if (rc == -EINVAL) { @@ -2634,6 +2634,11 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); goto ioctl_exit; } + } else if (rc == -E2BIG) { + if (opcode != FSCTL_QUERY_ALLOCATED_RANGES) { + cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE); + goto ioctl_exit; + } } /* check if caller wants to look at return data or just return rc */ diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index ee8977688e21..3a29db740fe6 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -842,6 +842,11 @@ struct fsctl_get_integrity_information_rsp { __le32 ClusterSizeInBytes; } __packed; +struct fsctl_query_allocate_ranges { + __le64 file_offset; + __le64 length; +} __packed; + /* Integrity ChecksumAlgorithm choices for above */ #define CHECKSUM_TYPE_NONE 0x0000 #define CHECKSUM_TYPE_CRC64 0x0002 diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h index 9b3459b9a5ce..08628e6a42ac 100644 --- a/fs/cifs/smbfsctl.h +++ b/fs/cifs/smbfsctl.h @@ -103,7 +103,7 @@ #define FSCTL_SET_ZERO_ON_DEALLOC 0x00090194 /* BB add struct */ #define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */ #define FSCTL_GET_INTEGRITY_INFORMATION 0x0009027C -#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF /* BB add struct */ +#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF #define FSCTL_SET_DEFECT_MANAGEMENT 0x00098134 /* BB add struct */ #define FSCTL_FILE_LEVEL_TRIM 0x00098208 /* BB add struct */ #define FSCTL_DUPLICATE_EXTENTS_TO_FILE 0x00098344
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> --- fs/cifs/cifsfs.c | 9 ++++++++ fs/cifs/cifsglob.h | 2 ++ fs/cifs/smb2ops.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.c | 7 +++++- fs/cifs/smb2pdu.h | 5 +++++ fs/cifs/smbfsctl.h | 2 +- 6 files changed, 88 insertions(+), 2 deletions(-)