From patchwork Fri May 18 02:54:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Misono Tomohiro X-Patchwork-Id: 10408089 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id AAF8A601C8 for ; Fri, 18 May 2018 02:53:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9D48326E78 for ; Fri, 18 May 2018 02:53:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 926F528409; Fri, 18 May 2018 02:53:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7D17126E78 for ; Fri, 18 May 2018 02:53:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751986AbeERCwv (ORCPT ); Thu, 17 May 2018 22:52:51 -0400 Received: from mgwkm03.jp.fujitsu.com ([202.219.69.170]:31281 "EHLO mgwkm03.jp.fujitsu.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751914AbeERCwu (ORCPT ); Thu, 17 May 2018 22:52:50 -0400 Received: from kw-mxoi2.gw.nic.fujitsu.com (unknown [192.168.231.133]) by mgwkm03.jp.fujitsu.com with smtp id 7cd3_469c_7835aaa6_91d5_4ce3_9479_ca1d14400b25; Fri, 18 May 2018 11:52:45 +0900 Received: from g01jpfmpwkw03.exch.g01.fujitsu.local (g01jpfmpwkw03.exch.g01.fujitsu.local [10.0.193.57]) by kw-mxoi2.gw.nic.fujitsu.com (Postfix) with ESMTP id 13DA0AC0279 for ; Fri, 18 May 2018 11:52:45 +0900 (JST) Received: from G01JPEXCHKW17.g01.fujitsu.local (G01JPEXCHKW17.g01.fujitsu.local [10.0.194.56]) by g01jpfmpwkw03.exch.g01.fujitsu.local (Postfix) with ESMTP id 3E308BD647D for ; Fri, 18 May 2018 11:52:44 +0900 (JST) Received: from luna3.soft.fujitsu.com (10.124.196.199) by G01JPEXCHKW17.g01.fujitsu.local (10.0.194.56) with Microsoft SMTP Server id 14.3.352.0; Fri, 18 May 2018 11:52:44 +0900 From: Tomohiro Misono To: Subject: [PATCH v6 2/3] btrfs: Add unprivileged ioctl which returns subvolume's ROOT_REF Date: Fri, 18 May 2018 11:54:47 +0900 Message-ID: X-Mailer: git-send-email 2.14.3 In-Reply-To: References: MIME-Version: 1.0 X-SecurityPolicyCheck-GC: OK by FENCE-Mail X-TM-AS-MML: disable Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add unprivileged ioctl BTRFS_IOC_GET_SUBVOL_ROOTREF which returns ROOT_REF information of the subvolume containing this inode except the subvolume name (this is because to prevent potential name leak). The subvolume name will be gained by user version of ino_lookup ioctl (BTRFS_IOC_INO_LOOKUP_USER) which also performs permission check. The min id of root ref's subvolume to be searched is specified by @min_id in struct btrfs_ioctl_get_subvol_rootref_args. After the search ends, @min_id is set to the last searched root ref's subvolid + 1. Also, if there are more root refs than BTRFS_MAX_ROOTREF_BUFFER_NUM, -EOVERFLOW is returned. Therefore the caller can just call this ioctl again without changing the argument to continue search. Reviewed-by: Qu Wenruo Signed-off-by: Tomohiro Misono Tested-by: Gu Jinxiang --- v4 -> v5 - Update error handling of btrfs_next_leaf() to cover all cases - Use btrfs_next_item() to reduce the call of btrfs_search_slot() fs/btrfs/ioctl.c | 102 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/btrfs.h | 16 +++++++ 2 files changed, 118 insertions(+) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 31af6e91c614..463ddedd90da 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2365,6 +2365,106 @@ static noinline int btrfs_ioctl_get_subvol_info(struct file *file, return ret; } +/* + * Return ROOT_REF information of the subvolume containing this inode + * except the subvolume name. + */ +static noinline int btrfs_ioctl_get_subvol_rootref(struct file *file, + void __user *argp) +{ + struct btrfs_ioctl_get_subvol_rootref_args *rootrefs; + struct btrfs_root_ref *rref; + struct btrfs_root *root; + struct btrfs_path *path; + struct btrfs_key key; + + struct extent_buffer *l; + int slot; + + struct inode *inode; + int ret; + u64 objectid; + u8 found; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + rootrefs = memdup_user(argp, sizeof(*rootrefs)); + if (!rootrefs) { + btrfs_free_path(path); + return -ENOMEM; + } + + inode = file_inode(file); + root = BTRFS_I(inode)->root->fs_info->tree_root; + objectid = BTRFS_I(inode)->root->root_key.objectid; + + key.objectid = objectid; + key.type = BTRFS_ROOT_REF_KEY; + key.offset = rootrefs->min_id; + found = 0; + + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); + if (ret < 0) { + goto out; + } else if (path->slots[0] >= + btrfs_header_nritems(path->nodes[0])) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) { + goto out; + } else if (ret > 0) { + ret = -EUCLEAN; + goto out; + } + } + while (1) { + l = path->nodes[0]; + slot = path->slots[0]; + + btrfs_item_key_to_cpu(l, &key, slot); + if (key.objectid != objectid || + key.type != BTRFS_ROOT_REF_KEY) { + ret = 0; + goto out; + } + + if (found == BTRFS_MAX_ROOTREF_BUFFER_NUM) { + ret = -EOVERFLOW; + goto out; + } + + rref = btrfs_item_ptr(l, slot, struct btrfs_root_ref); + rootrefs->rootref[found].subvolid = key.offset; + rootrefs->rootref[found].dirid = + btrfs_root_ref_dirid(l, rref); + found++; + + ret = btrfs_next_item(root, path); + if (ret < 0) { + goto out; + } else if (ret > 0) { + ret = -EUCLEAN; + goto out; + } + } + +out: + if (!ret || ret == -EOVERFLOW) { + rootrefs->num_items = found; + /* update min_id for next search */ + if (found) + rootrefs->min_id = + rootrefs->rootref[found - 1].subvolid + 1; + if (copy_to_user(argp, rootrefs, sizeof(*rootrefs))) + ret = -EFAULT; + } + + btrfs_free_path(path); + kfree(rootrefs); + return ret; +} + static noinline int btrfs_ioctl_snap_destroy(struct file *file, void __user *arg) { @@ -5499,6 +5599,8 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_set_features(file, argp); case BTRFS_IOC_GET_SUBVOL_INFO: return btrfs_ioctl_get_subvol_info(file, argp); + case BTRFS_IOC_GET_SUBVOL_ROOTREF: + return btrfs_ioctl_get_subvol_rootref(file, argp); } return -ENOTTY; diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index 02cd1f1994e8..b6633f5d4847 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h @@ -774,6 +774,20 @@ struct btrfs_ioctl_get_subvol_info_args { __u64 reserved[8]; }; +#define BTRFS_MAX_ROOTREF_BUFFER_NUM 255 +struct btrfs_ioctl_get_subvol_rootref_args { + /* in/out, min id of rootref's subvolid to be searched */ + __u64 min_id; + /* out */ + struct { + __u64 subvolid; + __u64 dirid; + } rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM]; + /* out, number of found items */ + __u8 num_items; + __u8 align[7]; +}; + /* Error codes as returned by the kernel */ enum btrfs_err_code { BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, @@ -894,5 +908,7 @@ enum btrfs_err_code { struct btrfs_ioctl_logical_ino_args) #define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ struct btrfs_ioctl_get_subvol_info_args) +#define BTRFS_IOC_GET_SUBVOL_ROOTREF _IOWR(BTRFS_IOCTL_MAGIC, 61, \ + struct btrfs_ioctl_get_subvol_rootref_args) #endif /* _UAPI_LINUX_BTRFS_H */