Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Deepin-Kernel-SIG] [linux-6.6.y] [Upstream] exfat: Implement sops->shutdown and ioctl #476

Merged
merged 1 commit into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions fs/exfat/exfat_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/ratelimit.h>
#include <linux/nls.h>
#include <linux/blkdev.h>
#include <uapi/linux/exfat.h>

#define EXFAT_ROOT_INO 1

Expand Down Expand Up @@ -149,6 +150,9 @@ enum {
#define DIR_CACHE_SIZE \
(DIV_ROUND_UP(EXFAT_DEN_TO_B(ES_MAX_ENTRY_NUM), SECTOR_SIZE) + 1)

/* Superblock flags */
#define EXFAT_FLAGS_SHUTDOWN 1

struct exfat_dentry_namebuf {
char *lfn;
int lfnbuf_len; /* usually MAX_UNINAME_BUF_SIZE */
Expand Down Expand Up @@ -265,6 +269,8 @@ struct exfat_sb_info {
unsigned int clu_srch_ptr; /* cluster search pointer */
unsigned int used_clusters; /* number of used clusters */

unsigned long s_exfat_flags; /* Exfat superblock flags */

struct mutex s_lock; /* superblock lock */
struct mutex bitmap_lock; /* bitmap lock */
struct exfat_mount_options options;
Expand Down Expand Up @@ -334,6 +340,11 @@ static inline struct exfat_inode_info *EXFAT_I(struct inode *inode)
return container_of(inode, struct exfat_inode_info, vfs_inode);
}

static inline int exfat_forced_shutdown(struct super_block *sb)
{
return test_bit(EXFAT_FLAGS_SHUTDOWN, &EXFAT_SB(sb)->s_exfat_flags);
}

/*
* If ->i_mode can't hold 0222 (i.e. ATTR_RO), we use ->i_attrs to
* save ATTR_RO instead of ->i_mode.
Expand Down Expand Up @@ -459,6 +470,7 @@ int exfat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync);
long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
long exfat_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
int exfat_force_shutdown(struct super_block *sb, u32 flags);

/* namei.c */
extern const struct dentry_operations exfat_dentry_ops;
Expand Down
21 changes: 21 additions & 0 deletions fs/exfat/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@ int exfat_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
unsigned int ia_valid;
int error;

if (unlikely(exfat_forced_shutdown(inode->i_sb)))
return -EIO;

if ((attr->ia_valid & ATTR_SIZE) &&
attr->ia_size > i_size_read(inode)) {
error = exfat_cont_expand(inode, attr->ia_size);
Expand Down Expand Up @@ -343,11 +346,26 @@ static int exfat_ioctl_fitrim(struct inode *inode, unsigned long arg)
return 0;
}

static int exfat_ioctl_shutdown(struct super_block *sb, unsigned long arg)
{
u32 flags;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;

if (get_user(flags, (__u32 __user *)arg))
return -EFAULT;

return exfat_force_shutdown(sb, flags);
}

long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct inode *inode = file_inode(filp);

switch (cmd) {
case EXFAT_IOC_SHUTDOWN:
return exfat_ioctl_shutdown(inode->i_sb, arg);
case FITRIM:
return exfat_ioctl_fitrim(inode, arg);
default:
Expand All @@ -368,6 +386,9 @@ int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
struct inode *inode = filp->f_mapping->host;
int err;

if (unlikely(exfat_forced_shutdown(inode->i_sb)))
return -EIO;

err = __generic_file_fsync(filp, start, end, datasync);
if (err)
return err;
Expand Down
9 changes: 9 additions & 0 deletions fs/exfat/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ int exfat_write_inode(struct inode *inode, struct writeback_control *wbc)
{
int ret;

if (unlikely(exfat_forced_shutdown(inode->i_sb)))
return -EIO;

mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock);
ret = __exfat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock);
Expand Down Expand Up @@ -346,6 +349,9 @@ static void exfat_readahead(struct readahead_control *rac)
static int exfat_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
if (unlikely(exfat_forced_shutdown(mapping->host->i_sb)))
return -EIO;

return mpage_writepages(mapping, wbc, exfat_get_block);
}

Expand All @@ -366,6 +372,9 @@ static int exfat_write_begin(struct file *file, struct address_space *mapping,
{
int ret;

if (unlikely(exfat_forced_shutdown(mapping->host->i_sb)))
return -EIO;

*pagep = NULL;
ret = cont_write_begin(file, mapping, pos, len, pagep, fsdata,
exfat_get_block,
Expand Down
15 changes: 15 additions & 0 deletions fs/exfat/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,9 @@ static int exfat_create(struct mnt_idmap *idmap, struct inode *dir,
loff_t i_pos;
int err;

if (unlikely(exfat_forced_shutdown(sb)))
return -EIO;

mutex_lock(&EXFAT_SB(sb)->s_lock);
exfat_set_volume_dirty(sb);
err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_FILE,
Expand Down Expand Up @@ -793,6 +796,9 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
struct buffer_head *bh;
int num_entries, entry, err = 0;

if (unlikely(exfat_forced_shutdown(sb)))
return -EIO;

mutex_lock(&EXFAT_SB(sb)->s_lock);
exfat_chain_dup(&cdir, &ei->dir);
entry = ei->entry;
Expand Down Expand Up @@ -854,6 +860,9 @@ static int exfat_mkdir(struct mnt_idmap *idmap, struct inode *dir,
loff_t i_pos;
int err;

if (unlikely(exfat_forced_shutdown(sb)))
return -EIO;

mutex_lock(&EXFAT_SB(sb)->s_lock);
exfat_set_volume_dirty(sb);
err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_DIR,
Expand Down Expand Up @@ -945,6 +954,9 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
struct buffer_head *bh;
int num_entries, entry, err;

if (unlikely(exfat_forced_shutdown(sb)))
return -EIO;

mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock);

exfat_chain_dup(&cdir, &ei->dir);
Expand Down Expand Up @@ -1019,6 +1031,9 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
struct buffer_head *new_bh, *old_bh;
int sync = IS_DIRSYNC(inode);

if (unlikely(exfat_forced_shutdown(sb)))
return -EIO;

epold = exfat_get_dentry(sb, p_dir, oldentry, &old_bh);
if (!epold)
return -EIO;
Expand Down
39 changes: 39 additions & 0 deletions fs/exfat/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ static int exfat_sync_fs(struct super_block *sb, int wait)
struct exfat_sb_info *sbi = EXFAT_SB(sb);
int err = 0;

if (unlikely(exfat_forced_shutdown(sb)))
return 0;

if (!wait)
return 0;

Expand Down Expand Up @@ -168,6 +171,41 @@ static int exfat_show_options(struct seq_file *m, struct dentry *root)
return 0;
}

int exfat_force_shutdown(struct super_block *sb, u32 flags)
{
int ret;
struct exfat_sb_info *sbi = sb->s_fs_info;
struct exfat_mount_options *opts = &sbi->options;

if (exfat_forced_shutdown(sb))
return 0;

switch (flags) {
case EXFAT_GOING_DOWN_DEFAULT:
case EXFAT_GOING_DOWN_FULLSYNC:
ret = freeze_bdev(sb->s_bdev);
if (ret)
return ret;
thaw_bdev(sb->s_bdev);
set_bit(EXFAT_FLAGS_SHUTDOWN, &sbi->s_exfat_flags);
break;
case EXFAT_GOING_DOWN_NOSYNC:
set_bit(EXFAT_FLAGS_SHUTDOWN, &sbi->s_exfat_flags);
break;
default:
return -EINVAL;
}

if (opts->discard)
opts->discard = 0;
return 0;
}

static void exfat_shutdown(struct super_block *sb)
{
exfat_force_shutdown(sb, EXFAT_GOING_DOWN_NOSYNC);
}

static struct inode *exfat_alloc_inode(struct super_block *sb)
{
struct exfat_inode_info *ei;
Expand All @@ -194,6 +232,7 @@ static const struct super_operations exfat_sops = {
.sync_fs = exfat_sync_fs,
.statfs = exfat_statfs,
.show_options = exfat_show_options,
.shutdown = exfat_shutdown,
};

enum {
Expand Down
25 changes: 25 additions & 0 deletions include/uapi/linux/exfat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Copyright (C) 2024 Unisoc Technologies Co., Ltd.
*/

#ifndef _UAPI_LINUX_EXFAT_H
#define _UAPI_LINUX_EXFAT_H
#include <linux/types.h>
#include <linux/ioctl.h>

/*
* exfat-specific ioctl commands
*/

#define EXFAT_IOC_SHUTDOWN _IOR('X', 125, __u32)

/*
* Flags used by EXFAT_IOC_SHUTDOWN
*/

#define EXFAT_GOING_DOWN_DEFAULT 0x0 /* default with full sync */
#define EXFAT_GOING_DOWN_FULLSYNC 0x1 /* going down with full sync*/
#define EXFAT_GOING_DOWN_NOSYNC 0x2 /* going down */

#endif /* _UAPI_LINUX_EXFAT_H */
Loading