From patchwork Tue Feb 19 11:51:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boaz Harrosh X-Patchwork-Id: 10819747 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D2E1F17E9 for ; Tue, 19 Feb 2019 11:52:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BE6522BBD7 for ; Tue, 19 Feb 2019 11:52:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B26912B923; Tue, 19 Feb 2019 11:52:11 +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,DKIM_SIGNED, DKIM_VALID,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 A1DFD2B923 for ; Tue, 19 Feb 2019 11:52:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728008AbfBSLwK (ORCPT ); Tue, 19 Feb 2019 06:52:10 -0500 Received: from mail-wm1-f65.google.com ([209.85.128.65]:37229 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726384AbfBSLwJ (ORCPT ); Tue, 19 Feb 2019 06:52:09 -0500 Received: by mail-wm1-f65.google.com with SMTP id x10so2282295wmg.2 for ; Tue, 19 Feb 2019 03:52:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=plexistor-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Ek0UTe/5hS6ONixlaKo76wBynNt6MfB4arJwREr9zy8=; b=r3tkZ6FFfKoaIcn6qa4hf3+7MwHzKQVaNoJKngxBPS3lRUX0yqmclXLMU/s+C3eO2D 9VBK3+qjdmMsvvvaNmLv93QmIe5khfJPAxAM/Bg8IqZCEG673zxrSB4Tiy/ijYfEtTH5 A2OJiIIrH6SJrlvVMoWyNNWL9JKBwmIPKfmf1xePOb83jYP02nXnFYM7SL+f8xmdi4VU YyZtjd12sArDAW5/HkRZMfo726tr1OUdQ8lJgOpXOmE7MdcxYxNc6pQyePXEMLsjWTBW SARdV4nknYgmrLeiFggDmfRDPv4F9Yxe3eUPmHEv5cMmO/QAgApWdv0FqtQBkOrXFf3I fZbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Ek0UTe/5hS6ONixlaKo76wBynNt6MfB4arJwREr9zy8=; b=EQ0XKpcw23DDhlz+I0coG9QSpYxnpGZ62eEMn+s5BKp/QYNf5bqvngFOIC2qeI5Md5 C22ag2vOAdG/e/BuLJ5X2q0GRwwZsNa1x07Vft5oMSaKFG5J33cSwEtVFkVYRD1Ge16C 1ZfB7DkNYuJbYAoRXxjVDWn95STQk2bOcySLK0WNeIyS5xeUV0KJEalxg0A44Sx0dotA +HnieE1yqZw2EZFu2O/g/YAFd08UhboGQmmgt62TKwymWaxDV5VvKicePP660po3vnID YqQ8MS6bmPXMrJhHusS/Z1aCMq+l5RplSlkn3XS4lwlDXhmRuuqXuzX8MA9jMRURpqAs Ghhg== X-Gm-Message-State: AHQUAub0/uuheEEbk9uI8drXxmxhld/CbFH7MbssFnqviktdNCg6tfww t6BsSZxewtDMGYRtwDKSl6JQjf/U3fA= X-Google-Smtp-Source: AHgI3IbjNwcC5SIFYojW0OT7C32dXDnCk2Wn7bR7IOCnqDhb6iwCcIKiNfI3fcg84uDHfOIH19fpbQ== X-Received: by 2002:adf:ec8f:: with SMTP id z15mr19840564wrn.290.1550577126114; Tue, 19 Feb 2019 03:52:06 -0800 (PST) Received: from Bfire.plexistor.com ([207.232.55.62]) by smtp.gmail.com with ESMTPSA id t18sm3605830wmt.8.2019.02.19.03.52.04 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Tue, 19 Feb 2019 03:52:05 -0800 (PST) From: Boaz harrosh To: linux-fsdevel , Anna Schumaker , Al Viro Cc: Ric Wheeler , Miklos Szeredi , Steven Whitehouse , Jefff moyer , Amir Goldstein , Amit Golander , Sagi Manole Subject: [RFC PATCH 13/17] zuf: ioctl implementation Date: Tue, 19 Feb 2019 13:51:32 +0200 Message-Id: <20190219115136.29952-14-boaz@plexistor.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190219115136.29952-1-boaz@plexistor.com> References: <20190219115136.29952-1-boaz@plexistor.com> MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Boaz Harrosh * support for some generic IOCTLs: FS_IOC_GETFLAGS, FS_IOC_SETFLAGS, FS_IOC_GETVERSION, FS_IOC_SETVERSION * Simple support for zusFS defined IOCTLs We only support flat structures (no emmbedded pointers within the IOCTL structures) We try to deduce the size of the IOCTL from the _IOC_SIZE(cmd) If zusFS needs a bigger copy it will send a retry with the new size. So bad defined IOCTLs always do 2 trips to userland Signed-off-by: Boaz Harrosh --- fs/zuf/Makefile | 2 +- fs/zuf/_extern.h | 5 + fs/zuf/directory.c | 4 + fs/zuf/file.c | 4 + fs/zuf/ioctl.c | 282 +++++++++++++++++++++++++++++++++++++++++++++ fs/zuf/zuf-core.c | 1 + fs/zuf/zus_api.h | 16 +++ 7 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 fs/zuf/ioctl.c diff --git a/fs/zuf/Makefile b/fs/zuf/Makefile index 970062d6b13f..5304aba901b2 100644 --- a/fs/zuf/Makefile +++ b/fs/zuf/Makefile @@ -17,6 +17,6 @@ zuf-y += md.o t1.o t2.o zuf-y += zuf-core.o zuf-root.o # Main FS -zuf-y += rw.o mmap.o +zuf-y += rw.o mmap.o ioctl.o zuf-y += super.o inode.o directory.o namei.o file.o symlink.o zuf-y += module.o diff --git a/fs/zuf/_extern.h b/fs/zuf/_extern.h index 5029f865655a..b8e24c6a66d9 100644 --- a/fs/zuf/_extern.h +++ b/fs/zuf/_extern.h @@ -46,6 +46,11 @@ bool zuf_dir_emit(struct super_block *sb, struct dir_context *ctx, uint zuf_prepare_symname(struct zufs_ioc_new_inode *ioc_new_inode, const char *symname, ulong len, struct page *pages[2]); +/* ioctl.c */ +long zuf_ioctl(struct file *filp, uint cmd, ulong arg); +#ifdef CONFIG_COMPAT +long zuf_compat_ioctl(struct file *file, uint cmd, ulong arg); +#endif /* mmap.c */ int zuf_file_mmap(struct file *file, struct vm_area_struct *vma); diff --git a/fs/zuf/directory.c b/fs/zuf/directory.c index 645dd367fd8c..11fcbe0ba6ff 100644 --- a/fs/zuf/directory.c +++ b/fs/zuf/directory.c @@ -160,4 +160,8 @@ const struct file_operations zuf_dir_operations = { .read = generic_read_dir, .iterate_shared = zuf_readdir, .fsync = noop_fsync, + .unlocked_ioctl = zuf_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = zuf_compat_ioctl, +#endif }; diff --git a/fs/zuf/file.c b/fs/zuf/file.c index 392b1a0d5881..48b339cb5f8f 100644 --- a/fs/zuf/file.c +++ b/fs/zuf/file.c @@ -507,7 +507,11 @@ const struct file_operations zuf_file_operations = { .fsync = zuf_fsync, .flush = zuf_flush, .release = zuf_file_release, + .unlocked_ioctl = zuf_ioctl, .fallocate = zuf_fallocate, +#ifdef CONFIG_COMPAT + .compat_ioctl = zuf_compat_ioctl, +#endif .copy_file_range = zuf_copy_file_range, .remap_file_range = zuf_clone_file_range, }; diff --git a/fs/zuf/ioctl.c b/fs/zuf/ioctl.c new file mode 100644 index 000000000000..13ce65764c38 --- /dev/null +++ b/fs/zuf/ioctl.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * BRIEF DESCRIPTION + * + * Ioctl operations. + * + * Copyright (c) 2018 NetApp Inc. All rights reserved. + * + * ZUFS-License: GPL-2.0. See module.c for LICENSE details. + * + * Authors: + * Boaz Harrosh + * Sagi Manole " + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zuf.h" + +#define ZUFS_SUPPORTED_FS_FLAGS (FS_SYNC_FL | FS_APPEND_FL | FS_IMMUTABLE_FL | \ + FS_NOATIME_FL | FS_DIRTY_FL) + +#define ZUS_IOCTL_MAX_PAGES 8 + +static int _ioctl_dispatch(struct inode *inode, uint cmd, ulong arg) +{ + struct _ioctl_info { + struct zufs_ioc_ioctl ctl; + char buf[900]; + } ctl_alloc = {}; + enum big_alloc_type bat; + struct zufs_ioc_ioctl *ioc_ioctl; + size_t ioc_size = _IOC_SIZE(cmd); + void __user *parg = (void __user *)arg; + struct timespec64 time = current_time(inode); + size_t size; + bool retry = false; + int err; + +again: + size = sizeof(*ioc_ioctl) + ioc_size; + + zuf_dbg_vfs("[%ld] cmd=0x%x arg=0x%lx size=0x%zx IOC(%d, %d, %zd)\n", + inode->i_ino, cmd, arg, size, _IOC_TYPE(cmd), + _IOC_NR(cmd), ioc_size); + + ioc_ioctl = big_alloc(size, sizeof(ctl_alloc), &ctl_alloc, GFP_KERNEL, + &bat); + if (unlikely(!ioc_ioctl)) + return -ENOMEM; + + memset(ioc_ioctl, 0, sizeof(*ioc_ioctl)); + ioc_ioctl->hdr.in_len = size; + ioc_ioctl->hdr.out_start = offsetof(struct zufs_ioc_ioctl, arg); + ioc_ioctl->hdr.out_max = size; + ioc_ioctl->hdr.out_len = 0; + ioc_ioctl->hdr.operation = ZUFS_OP_IOCTL; + ioc_ioctl->zus_ii = ZUII(inode)->zus_ii; + ioc_ioctl->cmd = cmd; + timespec_to_mt(&ioc_ioctl->time, &time); + + if (arg && ioc_size) { + if (copy_from_user(ioc_ioctl->arg, parg, ioc_size)) { + err = -EFAULT; + goto out; + } + } + + err = zufc_dispatch(ZUF_ROOT(SBI(inode->i_sb)), &ioc_ioctl->hdr, + NULL, 0); + + if (!retry && err == -EZUFS_RETRY) { + ioc_size = ioc_ioctl->new_size - sizeof(*ioc_ioctl); + big_free(ioc_ioctl, bat); + retry = true; + goto again; + } + + if (unlikely(err)) { + zuf_dbg_err("zufc_dispatch failed => %d IOC(%d, %d, %zd)\n", + err, _IOC_TYPE(cmd), _IOC_NR(cmd), ioc_size); + goto out; + } + + if (ioc_ioctl->hdr.out_len) { + if (copy_to_user(parg, ioc_ioctl->arg, + ioc_ioctl->hdr.out_len)) { + err = -EFAULT; + goto out; + } + } + +out: + big_free(ioc_ioctl, bat); + + return err; +} + +static uint _translate_to_ioc_flags(struct zus_inode *zi) +{ + uint zi_flags = le16_to_cpu(zi->i_flags); + uint ioc_flags = 0; + + if (zi_flags & S_SYNC) + ioc_flags |= FS_SYNC_FL; + if (zi_flags & S_APPEND) + ioc_flags |= FS_APPEND_FL; + if (zi_flags & S_IMMUTABLE) + ioc_flags |= FS_IMMUTABLE_FL; + if (zi_flags & S_NOATIME) + ioc_flags |= FS_NOATIME_FL; + if (zi_flags & S_DIRSYNC) + ioc_flags |= FS_DIRSYNC_FL; + + return ioc_flags; +} + +static int _ioc_getflags(struct inode *inode, uint __user *parg) +{ + struct zus_inode *zi = zus_zi(inode); + uint flags = _translate_to_ioc_flags(zi); + + return put_user(flags, parg); +} + +static void _translate_to_zi_flags(struct zus_inode *zi, unsigned int flags) +{ + uint zi_flags = le16_to_cpu(zi->i_flags); + + zi_flags &= + ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | S_DIRSYNC); + + if (flags & FS_SYNC_FL) + zi_flags |= S_SYNC; + if (flags & FS_APPEND_FL) + zi_flags |= S_APPEND; + if (flags & FS_IMMUTABLE_FL) + zi_flags |= S_IMMUTABLE; + if (flags & FS_NOATIME_FL) + zi_flags |= S_NOATIME; + if (flags & FS_DIRSYNC_FL) + zi_flags |= S_DIRSYNC; + + zi->i_flags = cpu_to_le16(zi_flags); +} + +/* use statx ioc to flush zi changes to fs */ +static int __ioc_dispatch_zi_update(struct inode *inode, uint flags) +{ + struct zufs_ioc_attr ioc_attr = { + .hdr.in_len = sizeof(ioc_attr), + .hdr.out_len = sizeof(ioc_attr), + .hdr.operation = ZUFS_OP_SETATTR, + .zus_ii = ZUII(inode)->zus_ii, + .zuf_attr = flags, + }; + int err; + + err = zufc_dispatch(ZUF_ROOT(SBI(inode->i_sb)), &ioc_attr.hdr, NULL, 0); + if (unlikely(err && err != -EINTR)) + zuf_err("zufc_dispatch failed => %d\n", err); + + return err; +} + +static int _ioc_setflags(struct inode *inode, uint __user *parg) +{ + struct zus_inode *zi = zus_zi(inode); + uint flags, oldflags; + int err; + + if (!inode_owner_or_capable(inode)) + return -EPERM; + + if (get_user(flags, parg)) + return -EFAULT; + + if (flags & ~ZUFS_SUPPORTED_FS_FLAGS) + return -EOPNOTSUPP; + + inode_lock(inode); + + oldflags = le32_to_cpu(zi->i_flags); + + if ((flags ^ oldflags) & + (FS_APPEND_FL | FS_IMMUTABLE_FL)) { + if (!capable(CAP_LINUX_IMMUTABLE)) { + inode_unlock(inode); + return -EPERM; + } + } + + if (!S_ISDIR(inode->i_mode)) + flags &= ~FS_DIRSYNC_FL; + + flags = flags & FS_FL_USER_MODIFIABLE; + flags |= oldflags & ~FS_FL_USER_MODIFIABLE; + inode->i_ctime = current_time(inode); + timespec_to_mt(&zi->i_ctime, &inode->i_ctime); + _translate_to_zi_flags(zi, flags); + zuf_set_inode_flags(inode, zi); + + err = __ioc_dispatch_zi_update(inode, ZUFS_STATX_FLAGS | STATX_CTIME); + + inode_unlock(inode); + return err; +} + +static int _ioc_setversion(struct inode *inode, uint __user *parg) +{ + struct zus_inode *zi = zus_zi(inode); + __u32 generation; + int err; + + if (!inode_owner_or_capable(inode)) + return -EPERM; + + if (get_user(generation, parg)) + return -EFAULT; + + inode_lock(inode); + + inode->i_ctime = current_time(inode); + inode->i_generation = generation; + timespec_to_mt(&zi->i_ctime, &inode->i_ctime); + zi->i_generation = cpu_to_le32(inode->i_generation); + + err = __ioc_dispatch_zi_update(inode, ZUFS_STATX_VERSION | STATX_CTIME); + + inode_unlock(inode); + return err; +} + +long zuf_ioctl(struct file *filp, unsigned int cmd, ulong arg) +{ + struct inode *inode = filp->f_inode; + void __user *parg = (void __user *)arg; + + switch (cmd) { + case FS_IOC_GETFLAGS: + return _ioc_getflags(inode, parg); + case FS_IOC_SETFLAGS: + return _ioc_setflags(inode, parg); + case FS_IOC_GETVERSION: + return put_user(inode->i_generation, (int __user *)arg); + case FS_IOC_SETVERSION: + return _ioc_setversion(inode, parg); + default: + return _ioctl_dispatch(inode, cmd, arg); + } +} + +#ifdef CONFIG_COMPAT +long zuf_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case FS_IOC32_GETFLAGS: + cmd = FS_IOC_GETFLAGS; + break; + case FS_IOC32_SETFLAGS: + cmd = FS_IOC_SETFLAGS; + break; + case FS_IOC32_GETVERSION: + cmd = FS_IOC_GETVERSION; + break; + case FS_IOC32_SETVERSION: + cmd = FS_IOC_SETVERSION; + break; + default: + return -ENOIOCTLCMD; + } + return zuf_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + diff --git a/fs/zuf/zuf-core.c b/fs/zuf/zuf-core.c index 86f624031d8d..09ad210318f8 100644 --- a/fs/zuf/zuf-core.c +++ b/fs/zuf/zuf-core.c @@ -787,6 +787,7 @@ const char *zuf_op_name(enum e_zufs_operation op) CASE_ENUM_NAME(ZUFS_OP_SYNC ); CASE_ENUM_NAME(ZUFS_OP_FALLOCATE ); CASE_ENUM_NAME(ZUFS_OP_LLSEEK ); + CASE_ENUM_NAME(ZUFS_OP_IOCTL ); CASE_ENUM_NAME(ZUFS_OP_BREAK ); default: return "UNKNOWN"; diff --git a/fs/zuf/zus_api.h b/fs/zuf/zus_api.h index 3d6481768308..f32ee615b937 100644 --- a/fs/zuf/zus_api.h +++ b/fs/zuf/zus_api.h @@ -350,6 +350,7 @@ enum e_zufs_operation { ZUFS_OP_SYNC, ZUFS_OP_FALLOCATE, ZUFS_OP_LLSEEK, + ZUFS_OP_IOCTL, ZUFS_OP_BREAK, /* Kernel telling Server to exit */ ZUFS_OP_MAX_OPT, @@ -586,6 +587,21 @@ struct zufs_ioc_seek { __u64 offset_out; }; +/* ZUFS_OP_IOCTL */ +struct zufs_ioc_ioctl { + struct zufs_ioc_hdr hdr; + /* IN */ + struct zus_inode_info *zus_ii; + __u32 cmd; + __u64 time; + + /* OUT */ + union { + __u32 new_size; + char arg[0]; + }; +}; + /* ~~~~ io_map structures && IOCTL(s) ~~~~ */ /* * These set of structures and helpers are used in return of zufs_ioc_IO and