From patchwork Thu Apr 25 06:45:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 1090612 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 44qSPH6GyYz9s6w for ; Thu, 25 Apr 2019 16:45:39 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727558AbfDYGpj (ORCPT ); Thu, 25 Apr 2019 02:45:39 -0400 Received: from mx1.redhat.com ([209.132.183.28]:35082 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725970AbfDYGpi (ORCPT ); Thu, 25 Apr 2019 02:45:38 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D86F7356F2; Thu, 25 Apr 2019 06:45:37 +0000 (UTC) Received: from test1135.test.redhat.com (vpn2-54-54.bne.redhat.com [10.64.54.54]) by smtp.corp.redhat.com (Postfix) with ESMTP id 41C585DC1B; Thu, 25 Apr 2019 06:45:37 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French , Pavel Shilovsky , Ronnie Sahlberg Subject: [PATCH] cifs: add fiemap support Date: Thu, 25 Apr 2019 16:45:29 +1000 Message-Id: <20190425064529.19357-2-lsahlber@redhat.com> In-Reply-To: <20190425064529.19357-1-lsahlber@redhat.com> References: <20190425064529.19357-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Thu, 25 Apr 2019 06:45:37 +0000 (UTC) Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Signed-off-by: Ronnie Sahlberg --- fs/cifs/cifsfs.c | 1 + fs/cifs/cifsfs.h | 2 ++ fs/cifs/cifsglob.h | 3 +++ fs/cifs/inode.c | 37 ++++++++++++++++++++++++++ fs/cifs/smb2ops.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smb2pdu.c | 7 ++++- fs/cifs/smb2pdu.h | 5 ++++ fs/cifs/smbfsctl.h | 2 +- 8 files changed, 132 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 07fdf1771add..e38be1f37efa 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -992,6 +992,7 @@ const struct inode_operations cifs_file_inode_ops = { .getattr = cifs_getattr, .permission = cifs_permission, .listxattr = cifs_listxattr, + .fiemap = cifs_fiemap, }; const struct inode_operations cifs_symlink_inode_ops = { diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 5c0298b9998f..c47d93d74d75 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -84,6 +84,8 @@ extern int cifs_revalidate_mapping(struct inode *inode); extern int cifs_zap_mapping(struct inode *inode); extern int cifs_getattr(const struct path *, struct kstat *, u32, unsigned int); extern int cifs_setattr(struct dentry *, struct iattr *); +extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start, + u64 len); extern const struct inode_operations cifs_file_inode_ops; extern const struct inode_operations cifs_symlink_inode_ops; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 621640195713..c608752048eb 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -494,6 +494,9 @@ struct smb_version_operations { char *full_path, umode_t mode, dev_t device_number); + /* version specific fiemap implementation */ + int (*fiemap)(struct cifs_tcon *tcon, struct cifsFileInfo *, + struct fiemap_extent_info *, u64, u64); }; struct smb_version_values { diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 538fd7d807e4..d7cc62252634 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -2116,6 +2116,43 @@ int cifs_getattr(const struct path *path, struct kstat *stat, return rc; } +int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start, + u64 len) +{ + struct cifsInodeInfo *cifs_i = CIFS_I(inode); + struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_i->vfs_inode.i_sb); + struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); + struct TCP_Server_Info *server = tcon->ses->server; + struct cifsFileInfo *cfile; + int rc; + + /* + * We need to be sure that all dirty pages are written as they + * might fill holes on the server. + */ + if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping && + inode->i_mapping->nrpages != 0) { + rc = filemap_fdatawait(inode->i_mapping); + if (rc) { + mapping_set_error(inode->i_mapping, rc); + return rc; + } + } + + cfile = find_readable_file(cifs_i, false); + if (cfile == NULL) + return -EINVAL; + + if (server->ops->fiemap) { + rc = server->ops->fiemap(tcon, cfile, fei, start, len); + cifsFileInfo_put(cfile); + return rc; + } + + cifsFileInfo_put(cfile); + return -ENOTSUPP; +} + static int cifs_truncate_page(struct address_space *mapping, loff_t from) { pgoff_t index = from >> PAGE_SHIFT; diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index f8cfcba797f3..3be75ca0f990 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -2977,6 +2977,79 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, return rc; } +static int smb3_fiemap(struct cifs_tcon *tcon, + struct cifsFileInfo *cfile, + struct fiemap_extent_info *fei, u64 start, u64 len) +{ + unsigned int xid; + struct file_allocated_range_buffer in_data, *out_data; + u32 out_data_len; + int i, num, rc, flags, last_blob; + u64 next; + + if (fiemap_check_flags(fei, FIEMAP_FLAG_SYNC)) + return -EBADR; + + xid = get_xid(); + again: + in_data.file_offset = cpu_to_le64(start); + in_data.length = cpu_to_le64(len); + + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, + FSCTL_QUERY_ALLOCATED_RANGES, true, + (char *)&in_data, sizeof(in_data), + 1024 * sizeof(struct file_allocated_range_buffer), + (char **)&out_data, &out_data_len); + if (rc == -E2BIG) { + last_blob = 0; + rc = 0; + } else + last_blob = 1; + if (rc) + goto out; + + if (out_data_len < sizeof(struct file_allocated_range_buffer)) { + rc = -EINVAL; + goto out; + } + if (out_data_len % sizeof(struct file_allocated_range_buffer)) { + rc = -EINVAL; + goto out; + } + + num = out_data_len / sizeof(struct file_allocated_range_buffer); + for (i = 0; i < num; i++) { + flags = 0; + if (i == num - 1 && last_blob) + flags |= FIEMAP_EXTENT_LAST; + + rc = fiemap_fill_next_extent(fei, + le64_to_cpu(out_data[i].file_offset), + le64_to_cpu(out_data[i].file_offset), + le64_to_cpu(out_data[i].length), + flags); + if (rc < 0) + goto out; + if (rc == 1) { + rc = 0; + goto out; + } + } + + if (!last_blob) { + next = le64_to_cpu(out_data[num - 1].file_offset) + + le64_to_cpu(out_data[num - 1].length); + len = len - (next - start); + start = next; + goto again; + } + + out: + free_xid(xid); + kfree(out_data); + return rc; +} static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode, loff_t off, loff_t len) @@ -4145,6 +4218,7 @@ struct smb_version_operations smb20_operations = { .next_header = smb2_next_header, .ioctl_query_info = smb2_ioctl_query_info, .make_node = smb2_make_node, + .fiemap = smb3_fiemap, }; struct smb_version_operations smb21_operations = { @@ -4244,6 +4318,7 @@ struct smb_version_operations smb21_operations = { .next_header = smb2_next_header, .ioctl_query_info = smb2_ioctl_query_info, .make_node = smb2_make_node, + .fiemap = smb3_fiemap, }; struct smb_version_operations smb30_operations = { @@ -4352,6 +4427,7 @@ struct smb_version_operations smb30_operations = { .next_header = smb2_next_header, .ioctl_query_info = smb2_ioctl_query_info, .make_node = smb2_make_node, + .fiemap = smb3_fiemap, }; struct smb_version_operations smb311_operations = { @@ -4461,6 +4537,7 @@ struct smb_version_operations smb311_operations = { .next_header = smb2_next_header, .ioctl_query_info = smb2_ioctl_query_info, .make_node = smb2_make_node, + .fiemap = smb3_fiemap, }; struct smb_version_values smb20_values = { diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 463c9298cd67..3999ec5a6bb9 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2622,7 +2622,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) { @@ -2631,6 +2631,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 9e535a80313f..e0725e98f175 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -868,6 +868,11 @@ struct fsctl_get_integrity_information_rsp { __le32 ClusterSizeInBytes; } __packed; +struct 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