From patchwork Thu Apr 29 05:33:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve French X-Patchwork-Id: 12230465 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 91EC8C433B4 for ; Thu, 29 Apr 2021 05:33:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5D3B46144E for ; Thu, 29 Apr 2021 05:33:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229814AbhD2FeR (ORCPT ); Thu, 29 Apr 2021 01:34:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34536 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229792AbhD2FeQ (ORCPT ); Thu, 29 Apr 2021 01:34:16 -0400 Received: from mail-lj1-x22e.google.com (mail-lj1-x22e.google.com [IPv6:2a00:1450:4864:20::22e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 48DD6C06138B for ; Wed, 28 Apr 2021 22:33:30 -0700 (PDT) Received: by mail-lj1-x22e.google.com with SMTP id u25so36635181ljg.7 for ; Wed, 28 Apr 2021 22:33:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=TbCx5PpvMEkGWQ+Nv9B8cWd5H/ikr18Ez55l+pk0yW0=; b=ddwB9LfH35YoLitsDbaO3AcpOG9f41VP3MIY8B4fH2W83AgJ3tbOa3uba2K2sqUAZD ByXe3caCFCzBiOQodz4ugrqrutQmEHF5dLZSsU69V+x9MSmavMrRkIVqnx3qTpaTFcju T1cjFmmJthYIZqNmpHgK3vwSM7fKj3elvVljoLHNKYuSYcrknrVcPdzElUgciptd84jN oZsyE/U6s5hudn0u0d0xi2A7376IHLPFUGt6Ua/mN0QOlqpE0v5y5CqQ2e4LrpsoCpMp nb3te5ZXniLhvVWcxKDeitb7c5g5KgEbBUHcmVRz8IT2M1KwFn2th2Z9CpO1uK/2PLDa zblA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=TbCx5PpvMEkGWQ+Nv9B8cWd5H/ikr18Ez55l+pk0yW0=; b=O7icGnVb8Uq50cthwkw7ztGpUC4GSMfq2MnzRG9HkfwPJrfgCogzakV9odOy/cOLSP AfjfmSdO4AhzusWxZtCqTK9q4N2K0NCJYKbvNKpU6jUc9iEGS9np/wxT0fSRjvnsLRl8 jj+3bVl4T2aYV3oLXxCPOPcWYa3Nuo95YD0D6+RH0siisZ8vyoHS8qKZyN1gNQE0daCn dUGR4bZuN7wLDbiZr3BbaA4athO6t9B/ai2Sxk1CFPjaAvu+xpUt9z6sVbMhrwyEpJpg pBI0F6hu5kr424Xta0gWeP+jEa9fHUZN6NobPkHXpVrvpjdn1C1S1deyU6nUnM2dnY5P P5FA== X-Gm-Message-State: AOAM530guDkAQoOi2RrKMaxIq6TDVWoFIK4z6oLXIezPUnLKaQ5+aLzj 8E2ba+xrRuA7Dx+c5An3N5brTliIPQbNTxl84xT+V2UAWWg= X-Google-Smtp-Source: ABdhPJx8PtRpan6GxbJE8d6/xs6jgLo+wPv8fTmDAPQXCz2WKFKzjCwW1Jz0XitAECeJUY23/L8CBTsP9vCPwQ52r2c= X-Received: by 2002:a2e:a78b:: with SMTP id c11mr23830627ljf.6.1619674408083; Wed, 28 Apr 2021 22:33:28 -0700 (PDT) MIME-Version: 1.0 From: Steve French Date: Thu, 29 Apr 2021 00:33:17 -0500 Message-ID: Subject: [PATCH] cifs: add shutdown support To: CIFS Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org Various filesystem support the shutdown ioctl which is used by various xfstests. The shutdown ioctl sets a flag on the superblock which prevents open, unlink, symlink, hardlink, rmdir, create etc. on the file system until unmount and remounted. The two flags supported in this patch are: FSOP_GOING_FLAGS_LOGFLUSH and FSOP_GOING_FLAGS_NOLOGFLUSH which require very little other than blocking new operations (since we do not cache writes to metadata on the client with cifs.ko). FSOP_GOING_FLAGS_DEFAULT is not supported yet, but could be added in the future but would need to call syncfs or equivalent to write out pending data on the mount. See https://man7.org/linux/man-pages/man2/ioctl_xfs_goingdown.2.html for a description of the flags With this patch various xfstests now work including tests 043 through 046 for example. Signed-off-by: Steve French Reviewed-by: Aurelien Aptel --- fs/cifs/cifs_fs_sb.h | 1 + fs/cifs/cifs_ioctl.h | 16 +++++++++++++ fs/cifs/dir.c | 10 +++++++++ fs/cifs/file.c | 6 +++++ fs/cifs/inode.c | 25 +++++++++++++++++++-- fs/cifs/ioctl.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/link.c | 7 ++++++ fs/cifs/xattr.c | 4 ++++ 8 files changed, 120 insertions(+), 2 deletions(-) From e6e3c8dd9861fc977969d71703e776b51cf7fd4a Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 29 Apr 2021 00:18:43 -0500 Subject: [PATCH] cifs: add shutdown support Various filesystem support the shutdown ioctl which is used by various xfstests. The shutdown ioctl sets a flag on the superblock which prevents open, unlink, symlink, hardlink, rmdir, create etc. on the file system until unmount and remounted. The two flags supported in this patch are: FSOP_GOING_FLAGS_LOGFLUSH and FSOP_GOING_FLAGS_NOLOGFLUSH which require very little other than blocking new operations (since we do not cache writes to metadata on the client with cifs.ko). FSOP_GOING_FLAGS_DEFAULT is not supported yet, but could be added in the future but would need to call syncfs or equivalent to write out pending data on the mount. With this patch various xfstests now work including tests 043 through 046 for example. Signed-off-by: Steve French --- fs/cifs/cifs_fs_sb.h | 1 + fs/cifs/cifs_ioctl.h | 16 +++++++++++++ fs/cifs/dir.c | 10 +++++++++ fs/cifs/file.c | 6 +++++ fs/cifs/inode.c | 25 +++++++++++++++++++-- fs/cifs/ioctl.c | 53 ++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/link.c | 7 ++++++ fs/cifs/xattr.c | 4 ++++ 8 files changed, 120 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 2a5325a7ae49..05de08143fcd 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -55,6 +55,7 @@ #define CIFS_MOUNT_MODE_FROM_SID 0x10000000 /* retrieve mode from special ACE */ #define CIFS_MOUNT_RO_CACHE 0x20000000 /* assumes share will not change */ #define CIFS_MOUNT_RW_CACHE 0x40000000 /* assumes only client accessing */ +#define SMB3_MOUNT_SHUTDOWN 0x80000000 struct cifs_sb_info { struct rb_root tlink_tree; diff --git a/fs/cifs/cifs_ioctl.h b/fs/cifs/cifs_ioctl.h index 153d5c842a9b..a744022d2a71 100644 --- a/fs/cifs/cifs_ioctl.h +++ b/fs/cifs/cifs_ioctl.h @@ -78,3 +78,19 @@ struct smb3_notify { #define CIFS_QUERY_INFO _IOWR(CIFS_IOCTL_MAGIC, 7, struct smb_query_info) #define CIFS_DUMP_KEY _IOWR(CIFS_IOCTL_MAGIC, 8, struct smb3_key_debug_info) #define CIFS_IOC_NOTIFY _IOW(CIFS_IOCTL_MAGIC, 9, struct smb3_notify) +#define SMB3_IOC_SHUTDOWN _IOR ('X', 125, __u32) + +/* + * Flags for going down operation + */ +#define SMB3_GOING_FLAGS_DEFAULT 0x0 /* going down */ +#define SMB3_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */ +#define SMB3_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ + +static inline bool smb3_forced_shutdown(struct cifs_sb_info *sbi) +{ + if (SMB3_MOUNT_SHUTDOWN & sbi->mnt_cifs_flags) + return true; + else + return false; +} diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 03afad8b24af..bc06a2dc6057 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -34,6 +34,7 @@ #include "cifs_fs_sb.h" #include "cifs_unicode.h" #include "fs_context.h" +#include "cifs_ioctl.h" static void renew_parental_timestamps(struct dentry *direntry) @@ -429,6 +430,9 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, __u32 oplock; struct cifsFileInfo *file_info; + if (unlikely(smb3_forced_shutdown(CIFS_SB(inode->i_sb)))) + return -EIO; + /* * Posix open is only called (at lookup time) for file create now. For * opens (rather than creates), because we do not know if it is a file @@ -545,6 +549,9 @@ int cifs_create(struct user_namespace *mnt_userns, struct inode *inode, cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n", inode, direntry, direntry); + if (unlikely(smb3_forced_shutdown(CIFS_SB(inode->i_sb)))) + return -EIO; + tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb)); rc = PTR_ERR(tlink); if (IS_ERR(tlink)) @@ -582,6 +589,9 @@ int cifs_mknod(struct user_namespace *mnt_userns, struct inode *inode, return -EINVAL; cifs_sb = CIFS_SB(inode->i_sb); + if (unlikely(smb3_forced_shutdown(cifs_sb))) + return -EIO; + tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5058252eeae6..bddeca06da08 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -45,6 +45,7 @@ #include "fscache.h" #include "smbdirect.h" #include "fs_context.h" +#include "cifs_ioctl.h" static inline int cifs_convert_flags(unsigned int flags) { @@ -542,6 +543,11 @@ int cifs_open(struct inode *inode, struct file *file) xid = get_xid(); cifs_sb = CIFS_SB(inode->i_sb); + if (unlikely(smb3_forced_shutdown(cifs_sb))) { + free_xid(xid); + return -EIO; + } + tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { free_xid(xid); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index baa9ffb4c446..35020686c66a 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -26,7 +26,6 @@ #include #include #include - #include #include "cifsfs.h" #include "cifspdu.h" @@ -38,7 +37,7 @@ #include "cifs_unicode.h" #include "fscache.h" #include "fs_context.h" - +#include "cifs_ioctl.h" static void cifs_set_ops(struct inode *inode) { @@ -1623,6 +1622,9 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry); + if (unlikely(smb3_forced_shutdown(cifs_sb))) + return -EIO; + tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); @@ -1876,6 +1878,8 @@ int cifs_mkdir(struct user_namespace *mnt_userns, struct inode *inode, mode, inode); cifs_sb = CIFS_SB(inode->i_sb); + if (unlikely(smb3_forced_shutdown(cifs_sb))) + return -EIO; tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); @@ -1958,6 +1962,11 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) } cifs_sb = CIFS_SB(inode->i_sb); + if (unlikely(smb3_forced_shutdown(cifs_sb))) { + rc = -EIO; + goto rmdir_exit; + } + tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) { rc = PTR_ERR(tlink); @@ -2092,6 +2101,9 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir, return -EINVAL; cifs_sb = CIFS_SB(source_dir->i_sb); + if (unlikely(smb3_forced_shutdown(cifs_sb))) + return -EIO; + tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); @@ -2409,6 +2421,9 @@ int cifs_getattr(struct user_namespace *mnt_userns, const struct path *path, struct inode *inode = d_inode(dentry); int rc; + if (unlikely(smb3_forced_shutdown(CIFS_SB(inode->i_sb)))) + return -EIO; + /* * We need to be sure that all dirty pages are written and the server * has actual ctime, mtime and file length. @@ -2481,6 +2496,9 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start, struct cifsFileInfo *cfile; int rc; + if (unlikely(smb3_forced_shutdown(cifs_sb))) + return -EIO; + /* * We need to be sure that all dirty pages are written as they * might fill holes on the server. @@ -2967,6 +2985,9 @@ cifs_setattr(struct user_namespace *mnt_userns, struct dentry *direntry, struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb); int rc, retries = 0; + if (unlikely(smb3_forced_shutdown(cifs_sb))) + return -EIO; + do { if (pTcon->unix_ext) rc = cifs_setattr_unix(direntry, attrs); diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 08d99fec593e..b34fa6a51a7b 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -164,6 +164,56 @@ static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon, return rc; } +static int smb3_shutdown(struct super_block *sb, unsigned long arg) +{ + struct cifs_sb_info *sbi = CIFS_SB(sb); + __u32 flags; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (get_user(flags, (__u32 __user *)arg)) + return -EFAULT; + + if (flags > SMB3_GOING_FLAGS_NOLOGFLUSH) + return -EINVAL; + + if (smb3_forced_shutdown(sbi)) + return 0; + + cifs_dbg(VFS, "shut down requested (%d)", flags); /* BB FIXME */ +/* trace_smb3_shutdown(sb, flags);*/ + + /* + * see: + * https://man7.org/linux/man-pages/man2/ioctl_xfs_goingdown.2.html + * for more information and description of original intent of the flags + */ + switch (flags) { + /* + * We could add support later for default flag which requires: + * "Flush all dirty data and metadata to disk" + * would need to call syncfs or equivalent to flush page cache for + * the mount and then issue fsync to server (if nostrictsync not set) + */ + case SMB3_GOING_FLAGS_DEFAULT: + cifs_dbg(VFS, "default flags\n"); + return -EINVAL; + /* + * FLAGS_LOGFLUSH is easy since it asks to write out metadata (not + * data) but metadata writes are not cached on the client, so can treat + * it similarly to NOLOGFLUSH + */ + case SMB3_GOING_FLAGS_LOGFLUSH: + case SMB3_GOING_FLAGS_NOLOGFLUSH: + sbi->mnt_cifs_flags |= SMB3_MOUNT_SHUTDOWN; + return 0; + default: + return -EINVAL; + } + return 0; +} + long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) { struct inode *inode = file_inode(filep); @@ -325,6 +375,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) rc = -EOPNOTSUPP; cifs_put_tlink(tlink); break; + case SMB3_IOC_SHUTDOWN: + rc = smb3_shutdown(inode->i_sb, arg); + break; default: cifs_dbg(FYI, "unsupported ioctl\n"); break; diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 616e1bc0cc0a..ef2e9d2c155d 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -30,6 +30,7 @@ #include "cifs_fs_sb.h" #include "cifs_unicode.h" #include "smb2proto.h" +#include "cifs_ioctl.h" /* * M-F Symlink Functions - Begin @@ -518,6 +519,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, struct TCP_Server_Info *server; struct cifsInodeInfo *cifsInode; + if (unlikely(smb3_forced_shutdown(cifs_sb))) + return -EIO; + tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); @@ -682,6 +686,9 @@ cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode, void *page = alloc_dentry_path(); struct inode *newinode = NULL; + if (unlikely(smb3_forced_shutdown(cifs_sb))) + return -EIO; + xid = get_xid(); tlink = cifs_sb_tlink(cifs_sb); diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index e351b945135b..c13f93e0e81b 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -30,6 +30,7 @@ #include "cifs_debug.h" #include "cifs_fs_sb.h" #include "cifs_unicode.h" +#include "cifs_ioctl.h" #define MAX_EA_VALUE_SIZE CIFSMaxBufSize #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" /* DACL only */ @@ -421,6 +422,9 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) const char *full_path; void *page; + if (unlikely(smb3_forced_shutdown(cifs_sb))) + return -EIO; + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) return -EOPNOTSUPP; -- 2.27.0