Skip to content

Commit 087f757

Browse files
committed
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> Reviewed-by: Aurelien Aptel <aaptel@suse.com>
1 parent c3f207a commit 087f757

9 files changed

Lines changed: 121 additions & 2 deletions

File tree

fs/cifs/cifs_fs_sb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#define CIFS_MOUNT_MODE_FROM_SID 0x10000000 /* retrieve mode from special ACE */
5656
#define CIFS_MOUNT_RO_CACHE 0x20000000 /* assumes share will not change */
5757
#define CIFS_MOUNT_RW_CACHE 0x40000000 /* assumes only client accessing */
58+
#define CIFS_MOUNT_SHUTDOWN 0x80000000
5859

5960
struct cifs_sb_info {
6061
struct rb_root tlink_tree;

fs/cifs/cifs_ioctl.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,19 @@ struct smb3_notify {
7878
#define CIFS_QUERY_INFO _IOWR(CIFS_IOCTL_MAGIC, 7, struct smb_query_info)
7979
#define CIFS_DUMP_KEY _IOWR(CIFS_IOCTL_MAGIC, 8, struct smb3_key_debug_info)
8080
#define CIFS_IOC_NOTIFY _IOW(CIFS_IOCTL_MAGIC, 9, struct smb3_notify)
81+
#define CIFS_IOC_SHUTDOWN _IOR ('X', 125, __u32)
82+
83+
/*
84+
* Flags for going down operation
85+
*/
86+
#define CIFS_GOING_FLAGS_DEFAULT 0x0 /* going down */
87+
#define CIFS_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */
88+
#define CIFS_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */
89+
90+
static inline bool cifs_forced_shutdown(struct cifs_sb_info *sbi)
91+
{
92+
if (CIFS_MOUNT_SHUTDOWN & sbi->mnt_cifs_flags)
93+
return true;
94+
else
95+
return false;
96+
}

fs/cifs/dir.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "cifs_fs_sb.h"
3535
#include "cifs_unicode.h"
3636
#include "fs_context.h"
37+
#include "cifs_ioctl.h"
3738

3839
static void
3940
renew_parental_timestamps(struct dentry *direntry)
@@ -429,6 +430,9 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
429430
__u32 oplock;
430431
struct cifsFileInfo *file_info;
431432

433+
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
434+
return -EIO;
435+
432436
/*
433437
* Posix open is only called (at lookup time) for file create now. For
434438
* 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,
545549
cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
546550
inode, direntry, direntry);
547551

552+
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
553+
return -EIO;
554+
548555
tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
549556
rc = PTR_ERR(tlink);
550557
if (IS_ERR(tlink))
@@ -582,6 +589,9 @@ int cifs_mknod(struct user_namespace *mnt_userns, struct inode *inode,
582589
return -EINVAL;
583590

584591
cifs_sb = CIFS_SB(inode->i_sb);
592+
if (unlikely(cifs_forced_shutdown(cifs_sb)))
593+
return -EIO;
594+
585595
tlink = cifs_sb_tlink(cifs_sb);
586596
if (IS_ERR(tlink))
587597
return PTR_ERR(tlink);

fs/cifs/file.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "fscache.h"
4646
#include "smbdirect.h"
4747
#include "fs_context.h"
48+
#include "cifs_ioctl.h"
4849

4950
static inline int cifs_convert_flags(unsigned int flags)
5051
{
@@ -542,6 +543,11 @@ int cifs_open(struct inode *inode, struct file *file)
542543
xid = get_xid();
543544

544545
cifs_sb = CIFS_SB(inode->i_sb);
546+
if (unlikely(cifs_forced_shutdown(cifs_sb))) {
547+
free_xid(xid);
548+
return -EIO;
549+
}
550+
545551
tlink = cifs_sb_tlink(cifs_sb);
546552
if (IS_ERR(tlink)) {
547553
free_xid(xid);

fs/cifs/fs_context.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,6 +1642,7 @@ void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb)
16421642
cifs_dbg(VFS, "mount options mfsymlinks and sfu both enabled\n");
16431643
}
16441644
}
1645+
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SHUTDOWN;
16451646

16461647
return;
16471648
}

fs/cifs/inode.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include <linux/sched/signal.h>
2727
#include <linux/wait_bit.h>
2828
#include <linux/fiemap.h>
29-
3029
#include <asm/div64.h>
3130
#include "cifsfs.h"
3231
#include "cifspdu.h"
@@ -38,7 +37,7 @@
3837
#include "cifs_unicode.h"
3938
#include "fscache.h"
4039
#include "fs_context.h"
41-
40+
#include "cifs_ioctl.h"
4241

4342
static void cifs_set_ops(struct inode *inode)
4443
{
@@ -1623,6 +1622,9 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
16231622

16241623
cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry);
16251624

1625+
if (unlikely(cifs_forced_shutdown(cifs_sb)))
1626+
return -EIO;
1627+
16261628
tlink = cifs_sb_tlink(cifs_sb);
16271629
if (IS_ERR(tlink))
16281630
return PTR_ERR(tlink);
@@ -1876,6 +1878,8 @@ int cifs_mkdir(struct user_namespace *mnt_userns, struct inode *inode,
18761878
mode, inode);
18771879

18781880
cifs_sb = CIFS_SB(inode->i_sb);
1881+
if (unlikely(cifs_forced_shutdown(cifs_sb)))
1882+
return -EIO;
18791883
tlink = cifs_sb_tlink(cifs_sb);
18801884
if (IS_ERR(tlink))
18811885
return PTR_ERR(tlink);
@@ -1958,6 +1962,11 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
19581962
}
19591963

19601964
cifs_sb = CIFS_SB(inode->i_sb);
1965+
if (unlikely(cifs_forced_shutdown(cifs_sb))) {
1966+
rc = -EIO;
1967+
goto rmdir_exit;
1968+
}
1969+
19611970
tlink = cifs_sb_tlink(cifs_sb);
19621971
if (IS_ERR(tlink)) {
19631972
rc = PTR_ERR(tlink);
@@ -2092,6 +2101,9 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir,
20922101
return -EINVAL;
20932102

20942103
cifs_sb = CIFS_SB(source_dir->i_sb);
2104+
if (unlikely(cifs_forced_shutdown(cifs_sb)))
2105+
return -EIO;
2106+
20952107
tlink = cifs_sb_tlink(cifs_sb);
20962108
if (IS_ERR(tlink))
20972109
return PTR_ERR(tlink);
@@ -2408,6 +2420,9 @@ int cifs_getattr(struct user_namespace *mnt_userns, const struct path *path,
24082420
struct inode *inode = d_inode(dentry);
24092421
int rc;
24102422

2423+
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
2424+
return -EIO;
2425+
24112426
/*
24122427
* We need to be sure that all dirty pages are written and the server
24132428
* has actual ctime, mtime and file length.
@@ -2480,6 +2495,9 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
24802495
struct cifsFileInfo *cfile;
24812496
int rc;
24822497

2498+
if (unlikely(cifs_forced_shutdown(cifs_sb)))
2499+
return -EIO;
2500+
24832501
/*
24842502
* We need to be sure that all dirty pages are written as they
24852503
* might fill holes on the server.
@@ -2966,6 +2984,9 @@ cifs_setattr(struct user_namespace *mnt_userns, struct dentry *direntry,
29662984
struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb);
29672985
int rc, retries = 0;
29682986

2987+
if (unlikely(cifs_forced_shutdown(cifs_sb)))
2988+
return -EIO;
2989+
29692990
do {
29702991
if (pTcon->unix_ext)
29712992
rc = cifs_setattr_unix(direntry, attrs);

fs/cifs/ioctl.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,56 @@ static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon,
164164
return rc;
165165
}
166166

167+
static int cifs_shutdown(struct super_block *sb, unsigned long arg)
168+
{
169+
struct cifs_sb_info *sbi = CIFS_SB(sb);
170+
__u32 flags;
171+
172+
if (!capable(CAP_SYS_ADMIN))
173+
return -EPERM;
174+
175+
if (get_user(flags, (__u32 __user *)arg))
176+
return -EFAULT;
177+
178+
if (flags > CIFS_GOING_FLAGS_NOLOGFLUSH)
179+
return -EINVAL;
180+
181+
if (cifs_forced_shutdown(sbi))
182+
return 0;
183+
184+
cifs_dbg(VFS, "shut down requested (%d)", flags);
185+
/* trace_cifs_shutdown(sb, flags);*/
186+
187+
/*
188+
* see:
189+
* https://man7.org/linux/man-pages/man2/ioctl_xfs_goingdown.2.html
190+
* for more information and description of original intent of the flags
191+
*/
192+
switch (flags) {
193+
/*
194+
* We could add support later for default flag which requires:
195+
* "Flush all dirty data and metadata to disk"
196+
* would need to call syncfs or equivalent to flush page cache for
197+
* the mount and then issue fsync to server (if nostrictsync not set)
198+
*/
199+
case CIFS_GOING_FLAGS_DEFAULT:
200+
cifs_dbg(FYI, "shutdown with default flag not supported\n");
201+
return -EINVAL;
202+
/*
203+
* FLAGS_LOGFLUSH is easy since it asks to write out metadata (not
204+
* data) but metadata writes are not cached on the client, so can treat
205+
* it similarly to NOLOGFLUSH
206+
*/
207+
case CIFS_GOING_FLAGS_LOGFLUSH:
208+
case CIFS_GOING_FLAGS_NOLOGFLUSH:
209+
sbi->mnt_cifs_flags |= CIFS_MOUNT_SHUTDOWN;
210+
return 0;
211+
default:
212+
return -EINVAL;
213+
}
214+
return 0;
215+
}
216+
167217
long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
168218
{
169219
struct inode *inode = file_inode(filep);
@@ -325,6 +375,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
325375
rc = -EOPNOTSUPP;
326376
cifs_put_tlink(tlink);
327377
break;
378+
case CIFS_IOC_SHUTDOWN:
379+
rc = cifs_shutdown(inode->i_sb, arg);
380+
break;
328381
default:
329382
cifs_dbg(FYI, "unsupported ioctl\n");
330383
break;

fs/cifs/link.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "cifs_fs_sb.h"
3131
#include "cifs_unicode.h"
3232
#include "smb2proto.h"
33+
#include "cifs_ioctl.h"
3334

3435
/*
3536
* M-F Symlink Functions - Begin
@@ -518,6 +519,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
518519
struct TCP_Server_Info *server;
519520
struct cifsInodeInfo *cifsInode;
520521

522+
if (unlikely(cifs_forced_shutdown(cifs_sb)))
523+
return -EIO;
524+
521525
tlink = cifs_sb_tlink(cifs_sb);
522526
if (IS_ERR(tlink))
523527
return PTR_ERR(tlink);
@@ -682,6 +686,9 @@ cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode,
682686
void *page = alloc_dentry_path();
683687
struct inode *newinode = NULL;
684688

689+
if (unlikely(cifs_forced_shutdown(cifs_sb)))
690+
return -EIO;
691+
685692
xid = get_xid();
686693

687694
tlink = cifs_sb_tlink(cifs_sb);

fs/cifs/xattr.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "cifs_debug.h"
3131
#include "cifs_fs_sb.h"
3232
#include "cifs_unicode.h"
33+
#include "cifs_ioctl.h"
3334

3435
#define MAX_EA_VALUE_SIZE CIFSMaxBufSize
3536
#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)
421422
const char *full_path;
422423
void *page;
423424

425+
if (unlikely(cifs_forced_shutdown(cifs_sb)))
426+
return -EIO;
427+
424428
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
425429
return -EOPNOTSUPP;
426430

0 commit comments

Comments
 (0)