linux-cifs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] cifs: add shutdown support
@ 2021-04-29  5:33 Steve French
  2021-04-29  9:29 ` Aurélien Aptel
  0 siblings, 1 reply; 5+ messages in thread
From: Steve French @ 2021-04-29  5:33 UTC (permalink / raw)
  To: CIFS

[-- Attachment #1: Type: text/plain, Size: 21393 bytes --]

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 <stfrench@microsoft.com>
---
 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 <linux/sched/signal.h>
 #include <linux/wait_bit.h>
 #include <linux/fiemap.h>
-
 #include <asm/div64.h>
 #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;
 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 <stfrench@microsoft.com>
---
 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 <linux/sched/signal.h>
 #include <linux/wait_bit.h>
 #include <linux/fiemap.h>
-
 #include <asm/div64.h>
 #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;

+ 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;


-- 
Thanks,

Steve

[-- Attachment #2: 0001-cifs-add-shutdown-support.patch --]
[-- Type: text/x-patch, Size: 10950 bytes --]

From e6e3c8dd9861fc977969d71703e776b51cf7fd4a Mon Sep 17 00:00:00 2001
From: Steve French <stfrench@microsoft.com>
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 <stfrench@microsoft.com>
---
 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 <linux/sched/signal.h>
 #include <linux/wait_bit.h>
 #include <linux/fiemap.h>
-
 #include <asm/div64.h>
 #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


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] cifs: add shutdown support
  2021-04-29  5:33 [PATCH] cifs: add shutdown support Steve French
@ 2021-04-29  9:29 ` Aurélien Aptel
  2021-04-29 18:39   ` Steve French
  0 siblings, 1 reply; 5+ messages in thread
From: Aurélien Aptel @ 2021-04-29  9:29 UTC (permalink / raw)
  To: Steve French, CIFS


Do we need to add code to clear the flag on remount or is it implicitely
cleared by not copying it?

Steve French <smfrench@gmail.com> writes:
>  #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

While I totally understand wanting to remove the "cifs" name, those
flags are specific to the kernel & filesystem and have nothing to do
with the wire protocol so in this case I would rather use CIFS_ prefix
because SMB3_ is misleading and all the other flags are already using CIFS_.

One day we should do s/CIFS/SMBFS/i on the whole tree where CIFS refers
to kernel stuff (not protocol) and rename the module smbfs. But that's a
story for another day I guess.

>
>  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)

Same

> +
> +/*
> + * 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

Same

> flush log nor data */
> +
> +static inline bool smb3_forced_shutdown(struct cifs_sb_info *sbi)

Same

> +	cifs_dbg(VFS, "shut down requested (%d)", flags); /* BB FIXME */
> +/*	trace_smb3_shutdown(sb, flags);*/

What is there to fix? It's doing like ext4 so it's fine no?

> +
> +	/*
> +	 * 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");

Should this be removed, less verbose or more info should be printed?

Cheers,
-- 
Aurélien Aptel / SUSE Labs Samba Team
GPG: 1839 CB5F 9F5B FB9B AA97  8C99 03C8 A49B 521B D5D3
SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg, DE
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah HRB 247165 (AG München)


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] cifs: add shutdown support
  2021-04-29  9:29 ` Aurélien Aptel
@ 2021-04-29 18:39   ` Steve French
  2021-04-30  0:07     ` Steve French
  0 siblings, 1 reply; 5+ messages in thread
From: Steve French @ 2021-04-29 18:39 UTC (permalink / raw)
  To: Aurélien Aptel; +Cc: CIFS

You are correct - I have to add the code to clear the bit on remount

I have added your other changes and will send updated patch after lunch

root@smfrench-ThinkPad-P52:~# mount | grep cifs
//localhost/test on /mnt1 type cifs
(rw,relatime,vers=3.1.1,cache=strict,username=smfrench,uid=0,noforceuid,gid=0,noforcegid,addr=127.0.0.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,noperm,rsize=4194304,wsize=4194304,bsize=1048576,echo_interval=60,actimeo=1)
root@smfrench-ThinkPad-P52:~# touch /mnt1/file
root@smfrench-ThinkPad-P52:~# ~smfrench/xfstests-dev/src/godown /mnt1/
root@smfrench-ThinkPad-P52:~# touch /mnt1/file
touch: cannot touch '/mnt1/file': Input/output error
root@smfrench-ThinkPad-P52:~# mount -o remount /mnt1
root@smfrench-ThinkPad-P52:~# touch /mnt1/file
touch: cannot touch '/mnt1/file': Input/output error

On Thu, Apr 29, 2021 at 4:29 AM Aurélien Aptel <aaptel@suse.com> wrote:
>
>
> Do we need to add code to clear the flag on remount or is it implicitely
> cleared by not copying it?
>
> Steve French <smfrench@gmail.com> writes:
> >  #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
>
> While I totally understand wanting to remove the "cifs" name, those
> flags are specific to the kernel & filesystem and have nothing to do
> with the wire protocol so in this case I would rather use CIFS_ prefix
> because SMB3_ is misleading and all the other flags are already using CIFS_.
>
> One day we should do s/CIFS/SMBFS/i on the whole tree where CIFS refers
> to kernel stuff (not protocol) and rename the module smbfs. But that's a
> story for another day I guess.
>
> >
> >  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)
>
> Same
>
> > +
> > +/*
> > + * 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
>
> Same
>
> > flush log nor data */
> > +
> > +static inline bool smb3_forced_shutdown(struct cifs_sb_info *sbi)
>
> Same
>
> > +     cifs_dbg(VFS, "shut down requested (%d)", flags); /* BB FIXME */
> > +/*   trace_smb3_shutdown(sb, flags);*/
>
> What is there to fix? It's doing like ext4 so it's fine no?
>
> > +
> > +     /*
> > +      * 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");
>
> Should this be removed, less verbose or more info should be printed?
>
> Cheers,
> --
> Aurélien Aptel / SUSE Labs Samba Team
> GPG: 1839 CB5F 9F5B FB9B AA97  8C99 03C8 A49B 521B D5D3
> SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg, DE
> GF: Felix Imendörffer, Mary Higgins, Sri Rasiah HRB 247165 (AG München)
>


-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] cifs: add shutdown support
  2021-04-29 18:39   ` Steve French
@ 2021-04-30  0:07     ` Steve French
  2021-04-30 16:41       ` Aurélien Aptel
  0 siblings, 1 reply; 5+ messages in thread
From: Steve French @ 2021-04-30  0:07 UTC (permalink / raw)
  To: Aurélien Aptel; +Cc: CIFS

[-- Attachment #1: Type: text/plain, Size: 5269 bytes --]

Updated patch attached.   Fixed the remount issue (remount should
clear the shutdown flag). See below simple demonstration:

root@smfrench-ThinkPad-P52:~# mount | grep cifs
//localhost/test on /mnt1 type cifs
(rw,relatime,vers=3.1.1,cache=strict,username=smfrench,uid=0,noforceuid,gid=0,noforcegid,addr=127.0.0.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,noperm,rsize=4194304,wsize=4194304,bsize=1048576,echo_interval=60,actimeo=1)
root@smfrench-ThinkPad-P52:~# touch /mnt1/file
root@smfrench-ThinkPad-P52:~# ~smfrench/xfstests-dev/src/godown /mnt1/
root@smfrench-ThinkPad-P52:~# touch /mnt1/file
touch: cannot touch '/mnt1/file': Input/output error
root@smfrench-ThinkPad-P52:~# mount -t cifs //localhost/test /mnt1 -o remount
root@smfrench-ThinkPad-P52:~# touch /mnt1/file

On Thu, Apr 29, 2021 at 1:39 PM Steve French <smfrench@gmail.com> wrote:
>
> You are correct - I have to add the code to clear the bit on remount
>
> I have added your other changes and will send updated patch after lunch
>
> root@smfrench-ThinkPad-P52:~# mount | grep cifs
> //localhost/test on /mnt1 type cifs
> (rw,relatime,vers=3.1.1,cache=strict,username=smfrench,uid=0,noforceuid,gid=0,noforcegid,addr=127.0.0.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,noperm,rsize=4194304,wsize=4194304,bsize=1048576,echo_interval=60,actimeo=1)
> root@smfrench-ThinkPad-P52:~# touch /mnt1/file
> root@smfrench-ThinkPad-P52:~# ~smfrench/xfstests-dev/src/godown /mnt1/
> root@smfrench-ThinkPad-P52:~# touch /mnt1/file
> touch: cannot touch '/mnt1/file': Input/output error
> root@smfrench-ThinkPad-P52:~# mount -o remount /mnt1
> root@smfrench-ThinkPad-P52:~# touch /mnt1/file
> touch: cannot touch '/mnt1/file': Input/output error
>
> On Thu, Apr 29, 2021 at 4:29 AM Aurélien Aptel <aaptel@suse.com> wrote:
> >
> >
> > Do we need to add code to clear the flag on remount or is it implicitely
> > cleared by not copying it?
> >
> > Steve French <smfrench@gmail.com> writes:
> > >  #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
> >
> > While I totally understand wanting to remove the "cifs" name, those
> > flags are specific to the kernel & filesystem and have nothing to do
> > with the wire protocol so in this case I would rather use CIFS_ prefix
> > because SMB3_ is misleading and all the other flags are already using CIFS_.
> >
> > One day we should do s/CIFS/SMBFS/i on the whole tree where CIFS refers
> > to kernel stuff (not protocol) and rename the module smbfs. But that's a
> > story for another day I guess.
> >
> > >
> > >  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)
> >
> > Same
> >
> > > +
> > > +/*
> > > + * 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
> >
> > Same
> >
> > > flush log nor data */
> > > +
> > > +static inline bool smb3_forced_shutdown(struct cifs_sb_info *sbi)
> >
> > Same
> >
> > > +     cifs_dbg(VFS, "shut down requested (%d)", flags); /* BB FIXME */
> > > +/*   trace_smb3_shutdown(sb, flags);*/
> >
> > What is there to fix? It's doing like ext4 so it's fine no?
> >
> > > +
> > > +     /*
> > > +      * 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");
> >
> > Should this be removed, less verbose or more info should be printed?
> >
> > Cheers,
> > --
> > Aurélien Aptel / SUSE Labs Samba Team
> > GPG: 1839 CB5F 9F5B FB9B AA97  8C99 03C8 A49B 521B D5D3
> > SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg, DE
> > GF: Felix Imendörffer, Mary Higgins, Sri Rasiah HRB 247165 (AG München)
> >
>
>
> --
> Thanks,
>
> Steve



-- 
Thanks,

Steve

[-- Attachment #2: 0001-cifs-add-shutdown-support.patch --]
[-- Type: text/x-patch, Size: 11366 bytes --]

From 6f47a4965985f4ccb2984165ffbecec6f2c2bdf8 Mon Sep 17 00:00:00 2001
From: Steve French <stfrench@microsoft.com>
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 <stfrench@microsoft.com>
---
 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/fs_context.c |  1 +
 fs/cifs/inode.c      | 25 +++++++++++++++++++--
 fs/cifs/ioctl.c      | 53 ++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/link.c       |  7 ++++++
 fs/cifs/xattr.c      |  4 ++++
 9 files changed, 121 insertions(+), 2 deletions(-)

diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 2a5325a7ae49..9c45b3a82ad9 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 CIFS_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..f262c64516bc 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 CIFS_IOC_SHUTDOWN _IOR ('X', 125, __u32)
+
+/*
+ * Flags for going down operation
+ */
+#define CIFS_GOING_FLAGS_DEFAULT                0x0     /* going down */
+#define CIFS_GOING_FLAGS_LOGFLUSH               0x1     /* flush log but not data */
+#define CIFS_GOING_FLAGS_NOLOGFLUSH             0x2     /* don't flush log nor data */
+
+static inline bool cifs_forced_shutdown(struct cifs_sb_info *sbi)
+{
+	if (CIFS_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..263720131986 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(cifs_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(cifs_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(cifs_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..919c82d4713d 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(cifs_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/fs_context.c b/fs/cifs/fs_context.c
index 3e0d016849e3..1d6e0e15b034 100644
--- a/fs/cifs/fs_context.c
+++ b/fs/cifs/fs_context.c
@@ -1642,6 +1642,7 @@ void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb)
 			cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
 		}
 	}
+	cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SHUTDOWN;
 
 	return;
 }
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index baa9ffb4c446..591f18e3e933 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -26,7 +26,6 @@
 #include <linux/sched/signal.h>
 #include <linux/wait_bit.h>
 #include <linux/fiemap.h>
-
 #include <asm/div64.h>
 #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(cifs_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(cifs_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(cifs_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(cifs_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(cifs_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(cifs_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(cifs_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..ef41fa878793 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 cifs_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 > CIFS_GOING_FLAGS_NOLOGFLUSH)
+		return -EINVAL;
+
+	if (cifs_forced_shutdown(sbi))
+		return 0;
+
+	cifs_dbg(VFS, "shut down requested (%d)", flags);
+/*	trace_cifs_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 CIFS_GOING_FLAGS_DEFAULT:
+		cifs_dbg(FYI, "shutdown with default flag not supported\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 CIFS_GOING_FLAGS_LOGFLUSH:
+	case CIFS_GOING_FLAGS_NOLOGFLUSH:
+		sbi->mnt_cifs_flags |= CIFS_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 CIFS_IOC_SHUTDOWN:
+			rc = cifs_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..1cbe7ec73728 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(cifs_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(cifs_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..aa3e8ca0457c 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(cifs_forced_shutdown(cifs_sb)))
+		return -EIO;
+
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 		return -EOPNOTSUPP;
 
-- 
2.27.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] cifs: add shutdown support
  2021-04-30  0:07     ` Steve French
@ 2021-04-30 16:41       ` Aurélien Aptel
  0 siblings, 0 replies; 5+ messages in thread
From: Aurélien Aptel @ 2021-04-30 16:41 UTC (permalink / raw)
  To: Steve French; +Cc: CIFS

Hi,

Steve French <smfrench@gmail.com> writes:
> Updated patch attached.   Fixed the remount issue (remount should
> clear the shutdown flag). See below simple demonstration:

I think it looks OK

Reviewed-by: Aurelien Aptel <aaptel@suse.com>

Cheers,
-- 
Aurélien Aptel / SUSE Labs Samba Team
GPG: 1839 CB5F 9F5B FB9B AA97  8C99 03C8 A49B 521B D5D3
SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nürnberg, DE
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah HRB 247165 (AG München)


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-04-30 16:42 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-29  5:33 [PATCH] cifs: add shutdown support Steve French
2021-04-29  9:29 ` Aurélien Aptel
2021-04-29 18:39   ` Steve French
2021-04-30  0:07     ` Steve French
2021-04-30 16:41       ` Aurélien Aptel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).