From 5a6cb47ef05a48cec778207fff6c189de8f27a0e Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Mon, 25 Mar 2024 12:12:40 +0800 Subject: [PATCH 01/20] fs: quota: use group allocation of per-cpu counters API Use group allocation of per-cpu counters api to accelerate dquot_init() and simplify code. Signed-off-by: Kefeng Wang Signed-off-by: Jan Kara Message-Id: <20240325041240.53537-1-wangkefeng.wang@huawei.com> --- fs/quota/dquot.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index dacbee455c03..808544f74e5e 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -3016,11 +3016,10 @@ static int __init dquot_init(void) if (!dquot_hash) panic("Cannot create dquot hash table"); - for (i = 0; i < _DQST_DQSTAT_LAST; i++) { - ret = percpu_counter_init(&dqstats.counter[i], 0, GFP_KERNEL); - if (ret) - panic("Cannot create dquot stat counters"); - } + ret = percpu_counter_init_many(dqstats.counter, 0, GFP_KERNEL, + _DQST_DQSTAT_LAST); + if (ret) + panic("Cannot create dquot stat counters"); /* Find power-of-two hlist_heads which can fit into allocation */ nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct hlist_head); From 1b17a46c9243e9421ee1ac6d628604bbc4ae2201 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Thu, 7 Mar 2024 12:56:33 -0600 Subject: [PATCH 02/20] isofs: convert isofs to use the new mount API This also renames iso9660_options to isofs_options, for consistency. Signed-off-by: Eric Sandeen cc: Jan Kara Signed-off-by: Jan Kara Message-Id: <409e28da-9c19-427a-acfb-78788f0a23b8@redhat.com> --- fs/isofs/inode.c | 467 ++++++++++++++++++++++++----------------------- 1 file changed, 237 insertions(+), 230 deletions(-) diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 2a616a9f289d..93b1077a380a 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -21,11 +21,12 @@ #include #include #include -#include #include #include #include #include +#include +#include #include "isofs.h" #include "zisofs.h" @@ -110,10 +111,10 @@ static void destroy_inodecache(void) kmem_cache_destroy(isofs_inode_cachep); } -static int isofs_remount(struct super_block *sb, int *flags, char *data) +static int isofs_reconfigure(struct fs_context *fc) { - sync_filesystem(sb); - if (!(*flags & SB_RDONLY)) + sync_filesystem(fc->root->d_sb); + if (!(fc->sb_flags & SB_RDONLY)) return -EROFS; return 0; } @@ -123,7 +124,6 @@ static const struct super_operations isofs_sops = { .free_inode = isofs_free_inode, .put_super = isofs_put_super, .statfs = isofs_statfs, - .remount_fs = isofs_remount, .show_options = isofs_show_options, }; @@ -145,7 +145,7 @@ static const struct dentry_operations isofs_dentry_ops[] = { #endif }; -struct iso9660_options{ +struct isofs_options{ unsigned int rock:1; unsigned int joliet:1; unsigned int cruft:1; @@ -289,197 +289,161 @@ isofs_dentry_cmpi_ms(const struct dentry *dentry, #endif enum { - Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore, - Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet, - Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err, - Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode, Opt_overriderockperm, + Opt_block, Opt_check, Opt_cruft, Opt_gid, Opt_ignore, Opt_iocharset, + Opt_map, Opt_mode, Opt_nojoliet, Opt_norock, Opt_sb, Opt_session, + Opt_uid, Opt_unhide, Opt_utf8, Opt_err, Opt_nocompress, Opt_hide, + Opt_showassoc, Opt_dmode, Opt_overriderockperm, }; -static const match_table_t tokens = { - {Opt_norock, "norock"}, - {Opt_nojoliet, "nojoliet"}, - {Opt_unhide, "unhide"}, - {Opt_hide, "hide"}, - {Opt_showassoc, "showassoc"}, - {Opt_cruft, "cruft"}, - {Opt_utf8, "utf8"}, - {Opt_iocharset, "iocharset=%s"}, - {Opt_map_a, "map=acorn"}, - {Opt_map_a, "map=a"}, - {Opt_map_n, "map=normal"}, - {Opt_map_n, "map=n"}, - {Opt_map_o, "map=off"}, - {Opt_map_o, "map=o"}, - {Opt_session, "session=%u"}, - {Opt_sb, "sbsector=%u"}, - {Opt_check_r, "check=relaxed"}, - {Opt_check_r, "check=r"}, - {Opt_check_s, "check=strict"}, - {Opt_check_s, "check=s"}, - {Opt_uid, "uid=%u"}, - {Opt_gid, "gid=%u"}, - {Opt_mode, "mode=%u"}, - {Opt_dmode, "dmode=%u"}, - {Opt_overriderockperm, "overriderockperm"}, - {Opt_block, "block=%u"}, - {Opt_ignore, "conv=binary"}, - {Opt_ignore, "conv=b"}, - {Opt_ignore, "conv=text"}, - {Opt_ignore, "conv=t"}, - {Opt_ignore, "conv=mtext"}, - {Opt_ignore, "conv=m"}, - {Opt_ignore, "conv=auto"}, - {Opt_ignore, "conv=a"}, - {Opt_nocompress, "nocompress"}, - {Opt_err, NULL} +static const struct constant_table isofs_param_map[] = { + {"acorn", 'a'}, + {"a", 'a'}, + {"normal", 'n'}, + {"n", 'n'}, + {"off", 'o'}, + {"o", 'o'}, + {} }; -static int parse_options(char *options, struct iso9660_options *popt) +static const struct constant_table isofs_param_check[] = { + {"relaxed", 'r'}, + {"r", 'r'}, + {"strict", 's'}, + {"s", 's'}, + {} +}; + +static const struct fs_parameter_spec isofs_param_spec[] = { + fsparam_flag ("norock", Opt_norock), + fsparam_flag ("nojoliet", Opt_nojoliet), + fsparam_flag ("unhide", Opt_unhide), + fsparam_flag ("hide", Opt_hide), + fsparam_flag ("showassoc", Opt_showassoc), + fsparam_flag ("cruft", Opt_cruft), + fsparam_flag ("utf8", Opt_utf8), + fsparam_string ("iocharset", Opt_iocharset), + fsparam_enum ("map", Opt_map, isofs_param_map), + fsparam_u32 ("session", Opt_session), + fsparam_u32 ("sbsector", Opt_sb), + fsparam_enum ("check", Opt_check, isofs_param_check), + fsparam_u32 ("uid", Opt_uid), + fsparam_u32 ("gid", Opt_gid), + /* Note: mode/dmode historically accepted %u not strictly %o */ + fsparam_u32 ("mode", Opt_mode), + fsparam_u32 ("dmode", Opt_dmode), + fsparam_flag ("overriderockperm", Opt_overriderockperm), + fsparam_u32 ("block", Opt_block), + fsparam_string ("conv", Opt_ignore), + fsparam_flag ("nocompress", Opt_nocompress), + {} +}; + +static int isofs_parse_param(struct fs_context *fc, + struct fs_parameter *param) { - char *p; - int option; - unsigned int uv; + struct isofs_options *popt = fc->fs_private; + struct fs_parse_result result; + int opt; + kuid_t uid; + kgid_t gid; + unsigned int n; - popt->map = 'n'; - popt->rock = 1; - popt->joliet = 1; - popt->cruft = 0; - popt->hide = 0; - popt->showassoc = 0; - popt->check = 'u'; /* unset */ - popt->nocompress = 0; - popt->blocksize = 1024; - popt->fmode = popt->dmode = ISOFS_INVALID_MODE; - popt->uid_set = 0; - popt->gid_set = 0; - popt->gid = GLOBAL_ROOT_GID; - popt->uid = GLOBAL_ROOT_UID; - popt->iocharset = NULL; - popt->overriderockperm = 0; - popt->session=-1; - popt->sbsector=-1; - if (!options) - return 1; + /* There are no remountable options */ + if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) + return 0; - while ((p = strsep(&options, ",")) != NULL) { - int token; - substring_t args[MAX_OPT_ARGS]; - unsigned n; + opt = fs_parse(fc, isofs_param_spec, param, &result); + if (opt < 0) + return opt; - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_norock: - popt->rock = 0; - break; - case Opt_nojoliet: - popt->joliet = 0; - break; - case Opt_hide: - popt->hide = 1; - break; - case Opt_unhide: - case Opt_showassoc: - popt->showassoc = 1; - break; - case Opt_cruft: - popt->cruft = 1; - break; + switch (opt) { + case Opt_norock: + popt->rock = 0; + break; + case Opt_nojoliet: + popt->joliet = 0; + break; + case Opt_hide: + popt->hide = 1; + break; + case Opt_unhide: + case Opt_showassoc: + popt->showassoc = 1; + break; + case Opt_cruft: + popt->cruft = 1; + break; #ifdef CONFIG_JOLIET - case Opt_utf8: - kfree(popt->iocharset); - popt->iocharset = kstrdup("utf8", GFP_KERNEL); - if (!popt->iocharset) - return 0; - break; - case Opt_iocharset: - kfree(popt->iocharset); - popt->iocharset = match_strdup(&args[0]); - if (!popt->iocharset) - return 0; - break; + case Opt_utf8: + kfree(popt->iocharset); + popt->iocharset = kstrdup("utf8", GFP_KERNEL); + if (!popt->iocharset) + return -ENOMEM; + break; + case Opt_iocharset: + kfree(popt->iocharset); + popt->iocharset = kstrdup(param->string, GFP_KERNEL); + if (!popt->iocharset) + return -ENOMEM; + break; #endif - case Opt_map_a: - popt->map = 'a'; - break; - case Opt_map_o: - popt->map = 'o'; - break; - case Opt_map_n: - popt->map = 'n'; - break; - case Opt_session: - if (match_int(&args[0], &option)) - return 0; - n = option; - /* - * Track numbers are supposed to be in range 1-99, the - * mount option starts indexing at 0. - */ - if (n >= 99) - return 0; - popt->session = n + 1; - break; - case Opt_sb: - if (match_int(&args[0], &option)) - return 0; - popt->sbsector = option; - break; - case Opt_check_r: - popt->check = 'r'; - break; - case Opt_check_s: - popt->check = 's'; - break; - case Opt_ignore: - break; - case Opt_uid: - if (match_uint(&args[0], &uv)) - return 0; - popt->uid = make_kuid(current_user_ns(), uv); - if (!uid_valid(popt->uid)) - return 0; - popt->uid_set = 1; - break; - case Opt_gid: - if (match_uint(&args[0], &uv)) - return 0; - popt->gid = make_kgid(current_user_ns(), uv); - if (!gid_valid(popt->gid)) - return 0; - popt->gid_set = 1; - break; - case Opt_mode: - if (match_int(&args[0], &option)) - return 0; - popt->fmode = option; - break; - case Opt_dmode: - if (match_int(&args[0], &option)) - return 0; - popt->dmode = option; - break; - case Opt_overriderockperm: - popt->overriderockperm = 1; - break; - case Opt_block: - if (match_int(&args[0], &option)) - return 0; - n = option; - if (n != 512 && n != 1024 && n != 2048) - return 0; - popt->blocksize = n; - break; - case Opt_nocompress: - popt->nocompress = 1; - break; - default: - return 0; - } + case Opt_map: + popt->map = result.uint_32; + break; + case Opt_session: + n = result.uint_32; + /* + * Track numbers are supposed to be in range 1-99, the + * mount option starts indexing at 0. + */ + if (n >= 99) + return -EINVAL; + popt->session = n + 1; + break; + case Opt_sb: + popt->sbsector = result.uint_32; + break; + case Opt_check: + popt->check = result.uint_32; + break; + case Opt_ignore: + break; + case Opt_uid: + uid = make_kuid(current_user_ns(), result.uint_32); + if (!uid_valid(uid)) + return -EINVAL; + popt->uid = uid; + popt->uid_set = 1; + break; + case Opt_gid: + gid = make_kgid(current_user_ns(), result.uint_32); + if (!gid_valid(gid)) + return -EINVAL; + popt->gid = gid; + popt->gid_set = 1; + break; + case Opt_mode: + popt->fmode = result.uint_32; + break; + case Opt_dmode: + popt->dmode = result.uint_32; + break; + case Opt_overriderockperm: + popt->overriderockperm = 1; + break; + case Opt_block: + n = result.uint_32; + if (n != 512 && n != 1024 && n != 2048) + return -EINVAL; + popt->blocksize = n; + break; + case Opt_nocompress: + popt->nocompress = 1; + break; + default: + return -EINVAL; } - return 1; + return 0; } /* @@ -615,7 +579,7 @@ static bool rootdir_empty(struct super_block *sb, unsigned long block) /* * Initialize the superblock and read the root inode. */ -static int isofs_fill_super(struct super_block *s, void *data, int silent) +static int isofs_fill_super(struct super_block *s, struct fs_context *fc) { struct buffer_head *bh = NULL, *pri_bh = NULL; struct hs_primary_descriptor *h_pri = NULL; @@ -623,7 +587,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) struct iso_supplementary_descriptor *sec = NULL; struct iso_directory_record *rootp; struct inode *inode; - struct iso9660_options opt; + struct isofs_options *opt = fc->fs_private; struct isofs_sb_info *sbi; unsigned long first_data_zone; int joliet_level = 0; @@ -631,15 +595,13 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) int orig_zonesize; int table, error = -EINVAL; unsigned int vol_desc_start; + int silent = fc->sb_flags & SB_SILENT; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) return -ENOMEM; s->s_fs_info = sbi; - if (!parse_options((char *)data, &opt)) - goto out_freesbi; - /* * First of all, get the hardware blocksize for this device. * If we don't know what it is, or the hardware blocksize is @@ -655,14 +617,14 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) bdev_logical_block_size(s->s_bdev)); goto out_freesbi; } - opt.blocksize = sb_min_blocksize(s, opt.blocksize); + opt->blocksize = sb_min_blocksize(s, opt->blocksize); sbi->s_high_sierra = 0; /* default is iso9660 */ - sbi->s_session = opt.session; - sbi->s_sbsector = opt.sbsector; + sbi->s_session = opt->session; + sbi->s_sbsector = opt->sbsector; - vol_desc_start = (opt.sbsector != -1) ? - opt.sbsector : isofs_get_last_session(s,opt.session); + vol_desc_start = (opt->sbsector != -1) ? + opt->sbsector : isofs_get_last_session(s, opt->session); for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) { @@ -696,7 +658,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) { sec = (struct iso_supplementary_descriptor *)vdp; if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) { - if (opt.joliet) { + if (opt->joliet) { if (sec->escape[2] == 0x40) joliet_level = 1; else if (sec->escape[2] == 0x43) @@ -721,7 +683,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) goto out_freebh; sbi->s_high_sierra = 1; - opt.rock = 0; + opt->rock = 0; h_pri = (struct hs_primary_descriptor *)vdp; goto root_found; } @@ -749,7 +711,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) goto out_freebh; } - if (joliet_level && (!pri || !opt.rock)) { + if (joliet_level && (!pri || !opt->rock)) { /* This is the case of Joliet with the norock mount flag. * A disc with both Joliet and Rock Ridge is handled later */ @@ -780,7 +742,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) * blocks that were 512 bytes (which should only very rarely * happen.) */ - if (orig_zonesize < opt.blocksize) + if (orig_zonesize < opt->blocksize) goto out_bad_size; /* RDE: convert log zone size to bit shift */ @@ -865,10 +827,10 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) #ifdef CONFIG_JOLIET if (joliet_level) { - char *p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT; + char *p = opt->iocharset ? opt->iocharset : CONFIG_NLS_DEFAULT; if (strcmp(p, "utf8") != 0) { - sbi->s_nls_iocharset = opt.iocharset ? - load_nls(opt.iocharset) : load_nls_default(); + sbi->s_nls_iocharset = opt->iocharset ? + load_nls(opt->iocharset) : load_nls_default(); if (!sbi->s_nls_iocharset) goto out_freesbi; } @@ -876,29 +838,29 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) #endif s->s_op = &isofs_sops; s->s_export_op = &isofs_export_ops; - sbi->s_mapping = opt.map; - sbi->s_rock = (opt.rock ? 2 : 0); + sbi->s_mapping = opt->map; + sbi->s_rock = (opt->rock ? 2 : 0); sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/ - sbi->s_cruft = opt.cruft; - sbi->s_hide = opt.hide; - sbi->s_showassoc = opt.showassoc; - sbi->s_uid = opt.uid; - sbi->s_gid = opt.gid; - sbi->s_uid_set = opt.uid_set; - sbi->s_gid_set = opt.gid_set; - sbi->s_nocompress = opt.nocompress; - sbi->s_overriderockperm = opt.overriderockperm; + sbi->s_cruft = opt->cruft; + sbi->s_hide = opt->hide; + sbi->s_showassoc = opt->showassoc; + sbi->s_uid = opt->uid; + sbi->s_gid = opt->gid; + sbi->s_uid_set = opt->uid_set; + sbi->s_gid_set = opt->gid_set; + sbi->s_nocompress = opt->nocompress; + sbi->s_overriderockperm = opt->overriderockperm; /* * It would be incredibly stupid to allow people to mark every file * on the disk as suid, so we merely allow them to set the default * permissions. */ - if (opt.fmode != ISOFS_INVALID_MODE) - sbi->s_fmode = opt.fmode & 0777; + if (opt->fmode != ISOFS_INVALID_MODE) + sbi->s_fmode = opt->fmode & 0777; else sbi->s_fmode = ISOFS_INVALID_MODE; - if (opt.dmode != ISOFS_INVALID_MODE) - sbi->s_dmode = opt.dmode & 0777; + if (opt->dmode != ISOFS_INVALID_MODE) + sbi->s_dmode = opt->dmode & 0777; else sbi->s_dmode = ISOFS_INVALID_MODE; @@ -960,12 +922,12 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) } } - if (opt.check == 'u') { + if (opt->check == 'u') { /* Only Joliet is case insensitive by default */ if (joliet_level) - opt.check = 'r'; + opt->check = 'r'; else - opt.check = 's'; + opt->check = 's'; } sbi->s_joliet_level = joliet_level; @@ -980,9 +942,9 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) table = 0; if (joliet_level) table += 2; - if (opt.check == 'r') + if (opt->check == 'r') table++; - sbi->s_check = opt.check; + sbi->s_check = opt->check; if (table) s->s_d_op = &isofs_dentry_ops[table - 1]; @@ -994,7 +956,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) goto out_no_inode; } - kfree(opt.iocharset); + kfree(opt->iocharset); return 0; @@ -1023,7 +985,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) goto out_freebh; out_bad_size: printk(KERN_WARNING "ISOFS: Logical zone size(%d) < hardware blocksize(%u)\n", - orig_zonesize, opt.blocksize); + orig_zonesize, opt->blocksize); goto out_freebh; out_unknown_format: if (!silent) @@ -1033,7 +995,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) brelse(bh); brelse(pri_bh); out_freesbi: - kfree(opt.iocharset); + kfree(opt->iocharset); kfree(sbi); s->s_fs_info = NULL; return error; @@ -1567,18 +1529,63 @@ struct inode *__isofs_iget(struct super_block *sb, return inode; } -static struct dentry *isofs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int isofs_get_tree(struct fs_context *fc) { - return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super); + return get_tree_bdev(fc, isofs_fill_super); +} + +static void isofs_free_fc(struct fs_context *fc) +{ + kfree(fc->fs_private); +} + +static const struct fs_context_operations isofs_context_ops = { + .parse_param = isofs_parse_param, + .get_tree = isofs_get_tree, + .reconfigure = isofs_reconfigure, + .free = isofs_free_fc, +}; + +static int isofs_init_fs_context(struct fs_context *fc) +{ + struct isofs_options *opt; + + opt = kzalloc(sizeof(*opt), GFP_KERNEL); + if (!opt) + return -ENOMEM; + + opt->map = 'n'; + opt->rock = 1; + opt->joliet = 1; + opt->cruft = 0; + opt->hide = 0; + opt->showassoc = 0; + opt->check = 'u'; /* unset */ + opt->nocompress = 0; + opt->blocksize = 1024; + opt->fmode = opt->dmode = ISOFS_INVALID_MODE; + opt->uid_set = 0; + opt->gid_set = 0; + opt->gid = GLOBAL_ROOT_GID; + opt->uid = GLOBAL_ROOT_UID; + opt->iocharset = NULL; + opt->overriderockperm = 0; + opt->session = -1; + opt->sbsector = -1; + + fc->fs_private = opt; + fc->ops = &isofs_context_ops; + + return 0; } static struct file_system_type iso9660_fs_type = { .owner = THIS_MODULE, .name = "iso9660", - .mount = isofs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, + .init_fs_context = isofs_init_fs_context, + .parameters = isofs_param_spec, }; MODULE_ALIAS_FS("iso9660"); MODULE_ALIAS("iso9660"); From 8777446a3f2dd6dab0859e4aedef6e0240955fdb Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 15 Mar 2024 09:19:49 +0000 Subject: [PATCH 03/20] udf: Remove second semicolon There is a statement with two semicolons. Remove the second one, it is redundant. Signed-off-by: Colin Ian King Signed-off-by: Jan Kara Message-Id: <20240315091949.2430585-1-colin.i.king@gmail.com> --- fs/udf/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 2217f7ed7a49..ba6b747a3830 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -630,7 +630,7 @@ static int udf_parse_param(struct fs_context *fc, struct fs_parameter *param) if (!uopt->nls_map) { errorf(fc, "iocharset %s not found", param->string); - return -EINVAL;; + return -EINVAL; } } break; From 94755a00a4e79236d4bfa6dc671a339828fb38ce Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Mon, 1 Apr 2024 20:01:51 +0000 Subject: [PATCH 04/20] udf: replace deprecated strncpy/strcpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. Also replace an instance of strcpy() which is also deprecated. s_volume_ident is a NUL-terminated string which is evident from its usage in udf_debug: | udf_debug("volIdent[] = '%s'\n", UDF_SB(sb)->s_volume_ident); s_volume_ident should also be NUL-padded as it is copied out to userspace: | if (copy_to_user((char __user *)arg, | UDF_SB(inode->i_sb)->s_volume_ident, 32)) | return -EFAULT; Considering the above, a suitable replacement is `strscpy_pad` [2] due to the fact that it guarantees both NUL-termination and NUL-padding on the destination buffer. To simplify the code, let's use the new 2-argument version of strscpy_pad() introduced in Commit e6584c3964f2f ("string: Allow 2-argument strscpy()"). Also zero-allocate @outstr so we can safely use a non-@ret length argument. This is just in case udf_dstrCS0toChar() doesn't include the NUL-byte in its return length, we won't truncate @outstr or write garbage bytes either. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Signed-off-by: Jan Kara Message-Id: <20240401-strncpy-fs-udf-super-c-v1-1-80cddab7a281@google.com> --- fs/udf/super.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index ba6b747a3830..9381a66c6ce5 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -895,7 +895,7 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block) int ret; struct timestamp *ts; - outstr = kmalloc(128, GFP_KERNEL); + outstr = kzalloc(128, GFP_KERNEL); if (!outstr) return -ENOMEM; @@ -921,11 +921,11 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block) ret = udf_dstrCS0toChar(sb, outstr, 31, pvoldesc->volIdent, 32); if (ret < 0) { - strcpy(UDF_SB(sb)->s_volume_ident, "InvalidName"); + strscpy_pad(UDF_SB(sb)->s_volume_ident, "InvalidName"); pr_warn("incorrect volume identification, setting to " "'InvalidName'\n"); } else { - strncpy(UDF_SB(sb)->s_volume_ident, outstr, ret); + strscpy_pad(UDF_SB(sb)->s_volume_ident, outstr); } udf_debug("volIdent[] = '%s'\n", UDF_SB(sb)->s_volume_ident); From 3e90417f41f41a7d4a6d5ee0ca216698e9ab4381 Mon Sep 17 00:00:00 2001 From: "Ritesh Harjani (IBM)" Date: Thu, 29 Feb 2024 19:54:13 +0530 Subject: [PATCH 05/20] ext2: set FMODE_CAN_ODIRECT instead of a dummy direct_IO method Since commit a2ad63daa88b ("VFS: add FMODE_CAN_ODIRECT file flag") file systems can just set the FMODE_CAN_ODIRECT flag at open time instead of wiring up a dummy direct_IO method to indicate support for direct I/O. Signed-off-by: Ritesh Harjani (IBM) Signed-off-by: Jan Kara Message-Id: <94f78492f55c3f421359fb6e0d8fab6e79ea17b2.1709215665.git.ritesh.list@gmail.com> --- fs/ext2/file.c | 8 +++++++- fs/ext2/inode.c | 2 -- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 4ddc36f4dbd4..10b061ac5bc0 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -302,6 +302,12 @@ static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) return generic_file_write_iter(iocb, from); } +static int ext2_file_open(struct inode *inode, struct file *filp) +{ + filp->f_mode |= FMODE_CAN_ODIRECT; + return dquot_file_open(inode, filp); +} + const struct file_operations ext2_file_operations = { .llseek = generic_file_llseek, .read_iter = ext2_file_read_iter, @@ -311,7 +317,7 @@ const struct file_operations ext2_file_operations = { .compat_ioctl = ext2_compat_ioctl, #endif .mmap = ext2_file_mmap, - .open = dquot_file_open, + .open = ext2_file_open, .release = ext2_release_file, .fsync = ext2_fsync, .get_unmapped_area = thp_get_unmapped_area, diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index f3d570a9302b..0caa1650cee8 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -965,7 +965,6 @@ const struct address_space_operations ext2_aops = { .write_begin = ext2_write_begin, .write_end = ext2_write_end, .bmap = ext2_bmap, - .direct_IO = noop_direct_IO, .writepages = ext2_writepages, .migrate_folio = buffer_migrate_folio, .is_partially_uptodate = block_is_partially_uptodate, @@ -974,7 +973,6 @@ const struct address_space_operations ext2_aops = { static const struct address_space_operations ext2_dax_aops = { .writepages = ext2_dax_writepages, - .direct_IO = noop_direct_IO, .dirty_folio = noop_dirty_folio, }; From 3b84adf460381169c085e4bc09e7b57e9e16db0a Mon Sep 17 00:00:00 2001 From: Roman Smirnov Date: Wed, 27 Mar 2024 16:27:55 +0300 Subject: [PATCH 06/20] udf: udftime: prevent overflow in udf_disk_stamp_to_time() An overflow can occur in a situation where src.centiseconds takes the value of 255. This situation is unlikely, but there is no validation check anywere in the code. Found by Linux Verification Center (linuxtesting.org) with Svace. Suggested-by: Jan Kara Signed-off-by: Roman Smirnov Reviewed-by: Sergey Shtylyov Signed-off-by: Jan Kara Message-Id: <20240327132755.13945-1-r.smirnov@omp.ru> --- fs/udf/udftime.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c index 758163af39c2..78ecc633606f 100644 --- a/fs/udf/udftime.c +++ b/fs/udf/udftime.c @@ -46,13 +46,18 @@ udf_disk_stamp_to_time(struct timespec64 *dest, struct timestamp src) dest->tv_sec = mktime64(year, src.month, src.day, src.hour, src.minute, src.second); dest->tv_sec -= offset * 60; - dest->tv_nsec = 1000 * (src.centiseconds * 10000 + - src.hundredsOfMicroseconds * 100 + src.microseconds); + /* * Sanitize nanosecond field since reportedly some filesystems are * recorded with bogus sub-second values. */ - dest->tv_nsec %= NSEC_PER_SEC; + if (src.centiseconds < 100 && src.hundredsOfMicroseconds < 100 && + src.microseconds < 100) { + dest->tv_nsec = 1000 * (src.centiseconds * 10000 + + src.hundredsOfMicroseconds * 100 + src.microseconds); + } else { + dest->tv_nsec = 0; + } } void From 4f8cf60ac18bee62e8c58654a300eb44b96caf09 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Tue, 5 Mar 2024 18:52:05 +0000 Subject: [PATCH 07/20] reiserfs: Convert to writepages Use buffer_migrate_folio to handle folio migration instead of writing out dirty pages and reading them back in again. Use writepages to write out folios more efficiently. We now only do that wait_on_write_block check once per call to writepages instead of once per page. It would be possible to do one transaction per writeback run, but that's a bit of a big change to do to this old filesystem, so leave it as one transaction per folio (and leave reiserfs supporting only one page per folio). Signed-off-by: Matthew Wilcox (Oracle) Reviewed-by: Jan Kara Signed-off-by: Jan Kara Message-Id: <20240305185208.1200166-1-willy@infradead.org> --- fs/reiserfs/inode.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 1d825459ee6e..c1daedc50f4c 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -2503,8 +2503,8 @@ static int map_block_for_writepage(struct inode *inode, * start/recovery path as __block_write_full_folio, along with special * code to handle reiserfs tails. */ -static int reiserfs_write_full_folio(struct folio *folio, - struct writeback_control *wbc) +static int reiserfs_write_folio(struct folio *folio, + struct writeback_control *wbc, void *data) { struct inode *inode = folio->mapping->host; unsigned long end_index = inode->i_size >> PAGE_SHIFT; @@ -2721,12 +2721,11 @@ static int reiserfs_read_folio(struct file *f, struct folio *folio) return block_read_full_folio(folio, reiserfs_get_block); } -static int reiserfs_writepage(struct page *page, struct writeback_control *wbc) +static int reiserfs_writepages(struct address_space *mapping, + struct writeback_control *wbc) { - struct folio *folio = page_folio(page); - struct inode *inode = folio->mapping->host; - reiserfs_wait_on_write_block(inode->i_sb); - return reiserfs_write_full_folio(folio, wbc); + reiserfs_wait_on_write_block(mapping->host->i_sb); + return write_cache_pages(mapping, wbc, reiserfs_write_folio, NULL); } static void reiserfs_truncate_failed_write(struct inode *inode) @@ -3405,7 +3404,7 @@ int reiserfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, } const struct address_space_operations reiserfs_address_space_operations = { - .writepage = reiserfs_writepage, + .writepages = reiserfs_writepages, .read_folio = reiserfs_read_folio, .readahead = reiserfs_readahead, .release_folio = reiserfs_release_folio, @@ -3415,4 +3414,5 @@ const struct address_space_operations reiserfs_address_space_operations = { .bmap = reiserfs_aop_bmap, .direct_IO = reiserfs_direct_IO, .dirty_folio = reiserfs_dirty_folio, + .migrate_folio = buffer_migrate_folio, }; From 8e2e0a79a3349b6853f572e4be4885b482f7d837 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Fri, 12 Apr 2024 17:49:42 +0800 Subject: [PATCH 08/20] quota: fix to propagate error of mark_dquot_dirty() to caller in order to let caller be aware of failure of mark_dquot_dirty(). Signed-off-by: Chao Yu Signed-off-by: Jan Kara Message-Id: <20240412094942.2131243-1-chao@kernel.org> --- fs/quota/dquot.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 808544f74e5e..627eb2f72ef3 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -410,7 +410,7 @@ static inline int mark_all_dquot_dirty(struct dquot __rcu * const *dquots) if (dquot) /* Even in case of error we have to continue */ ret = mark_dquot_dirty(dquot); - if (!err) + if (!err && ret < 0) err = ret; } return err; @@ -1737,7 +1737,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) if (reserve) goto out_flush_warn; - mark_all_dquot_dirty(dquots); + ret = mark_all_dquot_dirty(dquots); out_flush_warn: srcu_read_unlock(&dquot_srcu, index); flush_warnings(warn); @@ -1786,7 +1786,7 @@ int dquot_alloc_inode(struct inode *inode) warn_put_all: spin_unlock(&inode->i_lock); if (ret == 0) - mark_all_dquot_dirty(dquots); + ret = mark_all_dquot_dirty(dquots); srcu_read_unlock(&dquot_srcu, index); flush_warnings(warn); return ret; @@ -1990,7 +1990,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to) qsize_t inode_usage = 1; struct dquot __rcu **dquots; struct dquot *transfer_from[MAXQUOTAS] = {}; - int cnt, index, ret = 0; + int cnt, index, ret = 0, err; char is_valid[MAXQUOTAS] = {}; struct dquot_warn warn_to[MAXQUOTAS]; struct dquot_warn warn_from_inodes[MAXQUOTAS]; @@ -2087,8 +2087,12 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to) * mark_all_dquot_dirty(). */ index = srcu_read_lock(&dquot_srcu); - mark_all_dquot_dirty((struct dquot __rcu **)transfer_from); - mark_all_dquot_dirty((struct dquot __rcu **)transfer_to); + err = mark_all_dquot_dirty((struct dquot __rcu **)transfer_from); + if (err < 0) + ret = err; + err = mark_all_dquot_dirty((struct dquot __rcu **)transfer_to); + if (err < 0) + ret = err; srcu_read_unlock(&dquot_srcu, index); flush_warnings(warn_to); @@ -2098,7 +2102,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to) for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (is_valid[cnt]) transfer_to[cnt] = transfer_from[cnt]; - return 0; + return ret; over_quota: /* Back out changes we already did */ for (cnt--; cnt >= 0; cnt--) { @@ -2726,6 +2730,7 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di) struct mem_dqblk *dm = &dquot->dq_dqb; int check_blim = 0, check_ilim = 0; struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type]; + int ret; if (di->d_fieldmask & ~VFS_QC_MASK) return -EINVAL; @@ -2807,8 +2812,9 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di) else set_bit(DQ_FAKE_B, &dquot->dq_flags); spin_unlock(&dquot->dq_dqb_lock); - mark_dquot_dirty(dquot); - + ret = mark_dquot_dirty(dquot); + if (ret < 0) + return ret; return 0; } From 9ec2b350160104175241229ac711ffdde8c10078 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 12 Apr 2024 14:32:12 +0200 Subject: [PATCH 09/20] reiserfs: Trim some README bits Remove some bits of README based on authors request. References: https://lore.kernel.org/lkml/b98b29cf-27d9-49e0-b10b-1848399badfd@kittens.ph/ Signed-off-by: Jan Kara --- fs/reiserfs/README | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/fs/reiserfs/README b/fs/reiserfs/README index e2f7a264e3ff..11e9ecf24b63 100644 --- a/fs/reiserfs/README +++ b/fs/reiserfs/README @@ -102,19 +102,9 @@ that start on a node aligned boundary (there are reasons to want to node align files), and he invented and implemented indirect items and unformatted nodes as the solution. -Konstantin Shvachko, with the help of the Russian version of a VC, -tried to put me in a position where I was forced into giving control -of the project to him. (Fortunately, as the person paying the money -for all salaries from my dayjob I owned all copyrights, and you can't -really force takeovers of sole proprietorships.) This was something -curious, because he never really understood the value of our project, -why we should do what we do, or why innovation was possible in -general, but he was sure that he ought to be controlling it. Every -innovation had to be forced past him while he was with us. He added -two years to the time required to complete reiserfs, and was a net -loss for me. Mikhail Gilula was a brilliant innovator who also left -in a destructive way that erased the value of his contributions, and -that he was shown much generosity just makes it more painful. +Konstantin Shvachko was taking part in the early days. + +Mikhail Gilula was a brilliant innovator that has shown much generosity. Grigory Zaigralin was an extremely effective system administrator for our group. From b591dfb8330e30da0dcc8f5466c6f18173cdab32 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Wed, 17 Apr 2024 16:04:07 +0100 Subject: [PATCH 10/20] udf: Convert udf_symlink_filler() to use a folio Remove the conversion to struct page and use folio APIs throughout. Signed-off-by: Matthew Wilcox (Oracle) Signed-off-by: Jan Kara Message-Id: <20240417150416.752929-2-willy@infradead.org> --- fs/udf/symlink.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index f7eaf7b14594..0105e7e2ba3d 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -99,18 +99,17 @@ static int udf_pc_to_char(struct super_block *sb, unsigned char *from, static int udf_symlink_filler(struct file *file, struct folio *folio) { - struct page *page = &folio->page; - struct inode *inode = page->mapping->host; + struct inode *inode = folio->mapping->host; struct buffer_head *bh = NULL; unsigned char *symlink; int err = 0; - unsigned char *p = page_address(page); + unsigned char *p = folio_address(folio); struct udf_inode_info *iinfo = UDF_I(inode); /* We don't support symlinks longer than one block */ if (inode->i_size > inode->i_sb->s_blocksize) { err = -ENAMETOOLONG; - goto out_unlock; + goto out; } if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { @@ -120,24 +119,15 @@ static int udf_symlink_filler(struct file *file, struct folio *folio) if (!bh) { if (!err) err = -EFSCORRUPTED; - goto out_err; + goto out; } symlink = bh->b_data; } err = udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p, PAGE_SIZE); brelse(bh); - if (err) - goto out_err; - - SetPageUptodate(page); - unlock_page(page); - return 0; - -out_err: - SetPageError(page); -out_unlock: - unlock_page(page); +out: + folio_end_read(folio, err == 0); return err; } From d08f069cc2dafddf81b23db2ead45539b12cd0c2 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Wed, 17 Apr 2024 16:04:08 +0100 Subject: [PATCH 11/20] udf: Convert udf_write_begin() to use a folio Use the folio APIs throughout instead of the deprecated page APIs. Signed-off-by: Matthew Wilcox (Oracle) Signed-off-by: Jan Kara Message-Id: <20240417150416.752929-3-willy@infradead.org> --- fs/udf/inode.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 2f831a3a91af..5146b9d7aba3 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -254,7 +254,7 @@ static int udf_write_begin(struct file *file, struct address_space *mapping, struct page **pagep, void **fsdata) { struct udf_inode_info *iinfo = UDF_I(file_inode(file)); - struct page *page; + struct folio *folio; int ret; if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { @@ -266,12 +266,13 @@ static int udf_write_begin(struct file *file, struct address_space *mapping, } if (WARN_ON_ONCE(pos >= PAGE_SIZE)) return -EIO; - page = grab_cache_page_write_begin(mapping, 0); - if (!page) - return -ENOMEM; - *pagep = page; - if (!PageUptodate(page)) - udf_adinicb_readpage(page); + folio = __filemap_get_folio(mapping, 0, FGP_WRITEBEGIN, + mapping_gfp_mask(mapping)); + if (IS_ERR(folio)) + return PTR_ERR(folio); + *pagep = &folio->page; + if (!folio_test_uptodate(folio)) + udf_adinicb_readpage(&folio->page); return 0; } From db6754090a4f99c67e05ae6b87343ba6e013531f Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Wed, 17 Apr 2024 16:04:09 +0100 Subject: [PATCH 12/20] udf: Convert udf_expand_file_adinicb() to use a folio Use the folio APIs throughout this function. Signed-off-by: Matthew Wilcox (Oracle) Fixes: 1eeceaec794e ("udf: Convert udf_expand_file_adinicb() to avoid kmap_atomic()") Signed-off-by: Jan Kara Message-Id: <20240417150416.752929-4-willy@infradead.org> --- fs/udf/inode.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 5146b9d7aba3..59215494e6f6 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -342,7 +342,7 @@ const struct address_space_operations udf_aops = { */ int udf_expand_file_adinicb(struct inode *inode) { - struct page *page; + struct folio *folio; struct udf_inode_info *iinfo = UDF_I(inode); int err; @@ -358,12 +358,13 @@ int udf_expand_file_adinicb(struct inode *inode) return 0; } - page = find_or_create_page(inode->i_mapping, 0, GFP_KERNEL); - if (!page) - return -ENOMEM; + folio = __filemap_get_folio(inode->i_mapping, 0, + FGP_LOCK | FGP_ACCESSED | FGP_CREAT, GFP_KERNEL); + if (IS_ERR(folio)) + return PTR_ERR(folio); - if (!PageUptodate(page)) - udf_adinicb_readpage(page); + if (!folio_test_uptodate(folio)) + udf_adinicb_readpage(&folio->page); down_write(&iinfo->i_data_sem); memset(iinfo->i_data + iinfo->i_lenEAttr, 0x00, iinfo->i_lenAlloc); @@ -372,22 +373,22 @@ int udf_expand_file_adinicb(struct inode *inode) iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT; else iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; - set_page_dirty(page); - unlock_page(page); + folio_mark_dirty(folio); + folio_unlock(folio); up_write(&iinfo->i_data_sem); err = filemap_fdatawrite(inode->i_mapping); if (err) { /* Restore everything back so that we don't lose data... */ - lock_page(page); + folio_lock(folio); down_write(&iinfo->i_data_sem); - memcpy_to_page(page, 0, iinfo->i_data + iinfo->i_lenEAttr, - inode->i_size); - unlock_page(page); + memcpy_from_folio(iinfo->i_data + iinfo->i_lenEAttr, + folio, 0, inode->i_size); + folio_unlock(folio); iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB; iinfo->i_lenAlloc = inode->i_size; up_write(&iinfo->i_data_sem); } - put_page(page); + folio_put(folio); mark_inode_dirty(inode); return err; From d257d924a3fc6fe26594fba221c8be62f043b8d0 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Wed, 17 Apr 2024 16:04:10 +0100 Subject: [PATCH 13/20] udf: Convert udf_adinicb_readpage() to udf_adinicb_read_folio() Now that all three callers have a folio, convert this function to take a folio, and use the folio APIs. Signed-off-by: Matthew Wilcox (Oracle) Signed-off-by: Jan Kara Message-Id: <20240417150416.752929-5-willy@infradead.org> --- fs/udf/inode.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 59215494e6f6..d34562156522 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -208,19 +208,14 @@ static int udf_writepages(struct address_space *mapping, return write_cache_pages(mapping, wbc, udf_adinicb_writepage, NULL); } -static void udf_adinicb_readpage(struct page *page) +static void udf_adinicb_read_folio(struct folio *folio) { - struct inode *inode = page->mapping->host; - char *kaddr; + struct inode *inode = folio->mapping->host; struct udf_inode_info *iinfo = UDF_I(inode); loff_t isize = i_size_read(inode); - kaddr = kmap_local_page(page); - memcpy(kaddr, iinfo->i_data + iinfo->i_lenEAttr, isize); - memset(kaddr + isize, 0, PAGE_SIZE - isize); - flush_dcache_page(page); - SetPageUptodate(page); - kunmap_local(kaddr); + folio_fill_tail(folio, 0, iinfo->i_data + iinfo->i_lenEAttr, isize); + folio_mark_uptodate(folio); } static int udf_read_folio(struct file *file, struct folio *folio) @@ -228,7 +223,7 @@ static int udf_read_folio(struct file *file, struct folio *folio) struct udf_inode_info *iinfo = UDF_I(file_inode(file)); if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { - udf_adinicb_readpage(&folio->page); + udf_adinicb_read_folio(folio); folio_unlock(folio); return 0; } @@ -272,7 +267,7 @@ static int udf_write_begin(struct file *file, struct address_space *mapping, return PTR_ERR(folio); *pagep = &folio->page; if (!folio_test_uptodate(folio)) - udf_adinicb_readpage(&folio->page); + udf_adinicb_read_folio(folio); return 0; } @@ -364,7 +359,7 @@ int udf_expand_file_adinicb(struct inode *inode) return PTR_ERR(folio); if (!folio_test_uptodate(folio)) - udf_adinicb_readpage(&folio->page); + udf_adinicb_read_folio(folio); down_write(&iinfo->i_data_sem); memset(iinfo->i_data + iinfo->i_lenEAttr, 0x00, iinfo->i_lenAlloc); From 2f1c1bd7b18768377ff4a84974d77e6e8b371a67 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Wed, 17 Apr 2024 16:04:11 +0100 Subject: [PATCH 14/20] udf: Convert udf_symlink_getattr() to use a folio We're getting this from the page cache, so it's definitely a folio. Saves a call to compound_head() hidden in put_page(). Signed-off-by: Matthew Wilcox (Oracle) Signed-off-by: Jan Kara Message-Id: <20240417150416.752929-6-willy@infradead.org> --- fs/udf/symlink.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index 0105e7e2ba3d..fe03745d09b1 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -137,12 +137,12 @@ static int udf_symlink_getattr(struct mnt_idmap *idmap, { struct dentry *dentry = path->dentry; struct inode *inode = d_backing_inode(dentry); - struct page *page; + struct folio *folio; generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); - page = read_mapping_page(inode->i_mapping, 0, NULL); - if (IS_ERR(page)) - return PTR_ERR(page); + folio = read_mapping_folio(inode->i_mapping, 0, NULL); + if (IS_ERR(folio)) + return PTR_ERR(folio); /* * UDF uses non-trivial encoding of symlinks so i_size does not match * number of characters reported by readlink(2) which apparently some @@ -152,8 +152,8 @@ static int udf_symlink_getattr(struct mnt_idmap *idmap, * let's report the length of string returned by readlink(2) for * st_size. */ - stat->size = strlen(page_address(page)); - put_page(page); + stat->size = strlen(folio_address(folio)); + folio_put(folio); return 0; } From f5985ef281f9efff3e8291123fdb8a748b506951 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Wed, 17 Apr 2024 16:04:12 +0100 Subject: [PATCH 15/20] udf: Convert udf_page_mkwrite() to use a folio Convert the vm_fault page to a folio, then use it throughout. Replaces five calls to compound_head() with one. Signed-off-by: Matthew Wilcox (Oracle) Signed-off-by: Jan Kara Message-Id: <20240417150416.752929-7-willy@infradead.org> --- fs/udf/file.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/udf/file.c b/fs/udf/file.c index 0ceac4b5937c..97c59585208c 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -39,7 +39,7 @@ static vm_fault_t udf_page_mkwrite(struct vm_fault *vmf) struct vm_area_struct *vma = vmf->vma; struct inode *inode = file_inode(vma->vm_file); struct address_space *mapping = inode->i_mapping; - struct page *page = vmf->page; + struct folio *folio = page_folio(vmf->page); loff_t size; unsigned int end; vm_fault_t ret = VM_FAULT_LOCKED; @@ -48,31 +48,31 @@ static vm_fault_t udf_page_mkwrite(struct vm_fault *vmf) sb_start_pagefault(inode->i_sb); file_update_time(vma->vm_file); filemap_invalidate_lock_shared(mapping); - lock_page(page); + folio_lock(folio); size = i_size_read(inode); - if (page->mapping != inode->i_mapping || page_offset(page) >= size) { - unlock_page(page); + if (folio->mapping != inode->i_mapping || folio_pos(folio) >= size) { + folio_unlock(folio); ret = VM_FAULT_NOPAGE; goto out_unlock; } /* Space is already allocated for in-ICB file */ if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) goto out_dirty; - if (page->index == size >> PAGE_SHIFT) + if (folio->index == size >> PAGE_SHIFT) end = size & ~PAGE_MASK; else end = PAGE_SIZE; - err = __block_write_begin(page, 0, end, udf_get_block); + err = __block_write_begin(&folio->page, 0, end, udf_get_block); if (err) { - unlock_page(page); + folio_unlock(folio); ret = vmf_fs_error(err); goto out_unlock; } - block_commit_write(page, 0, end); + block_commit_write(&folio->page, 0, end); out_dirty: - set_page_dirty(page); - wait_for_stable_page(page); + folio_mark_dirty(folio); + folio_wait_stable(folio); out_unlock: filemap_invalidate_unlock_shared(mapping); sb_end_pagefault(inode->i_sb); From e29741676fac5d4430b3d2b799a5ff671ea9f023 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Wed, 17 Apr 2024 16:04:13 +0100 Subject: [PATCH 16/20] udf: Use a folio in udf_write_end() Convert the page to a folio and use the folio APIs. Replaces three calls to compound_head() with one. Signed-off-by: Matthew Wilcox (Oracle) Signed-off-by: Jan Kara Message-Id: <20240417150416.752929-8-willy@infradead.org> --- fs/udf/inode.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index d34562156522..2fb21c5ffccf 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -276,17 +276,19 @@ static int udf_write_end(struct file *file, struct address_space *mapping, struct page *page, void *fsdata) { struct inode *inode = file_inode(file); + struct folio *folio; loff_t last_pos; if (UDF_I(inode)->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) return generic_write_end(file, mapping, pos, len, copied, page, fsdata); + folio = page_folio(page); last_pos = pos + copied; if (last_pos > inode->i_size) i_size_write(inode, last_pos); - set_page_dirty(page); - unlock_page(page); - put_page(page); + folio_mark_dirty(folio); + folio_unlock(folio); + folio_put(folio); return copied; } From 72a5425adc7ade7f7808e85d949dde26c05ec127 Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Sat, 20 Apr 2024 03:50:04 +0100 Subject: [PATCH 17/20] ext2: Remove call to folio_set_error() Nobody checks this flag on ext2 folios, stop setting it. Cc: Jan Kara Cc: linux-ext4@vger.kernel.org Signed-off-by: Matthew Wilcox (Oracle) Signed-off-by: Jan Kara Message-Id: <20240420025029.2166544-10-willy@infradead.org> --- fs/ext2/dir.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 4fb155b5a958..087457061c6e 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -175,7 +175,6 @@ static bool ext2_check_folio(struct folio *folio, int quiet, char *kaddr) (unsigned long) le32_to_cpu(p->inode)); } fail: - folio_set_error(folio); return false; } From 91ba8cb1b09393b1c2222082e087f066fe13fd9b Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Sat, 20 Apr 2024 03:50:08 +0100 Subject: [PATCH 18/20] isofs: Remove calls to set/clear the error flag Nobody checks the error flag on isofs folios, so stop setting and clearing it. Cc: Jan Kara Signed-off-by: Matthew Wilcox (Oracle) Acked-by: Jan Kara Signed-off-by: Jan Kara Message-Id: <20240420025029.2166544-14-willy@infradead.org> --- fs/isofs/compress.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c index c4da3f634b92..34d5baa5d88a 100644 --- a/fs/isofs/compress.c +++ b/fs/isofs/compress.c @@ -346,8 +346,6 @@ static int zisofs_read_folio(struct file *file, struct folio *folio) for (i = 0; i < pcount; i++, index++) { if (i != full_page) pages[i] = grab_cache_page_nowait(mapping, index); - if (pages[i]) - ClearPageError(pages[i]); } err = zisofs_fill_pages(inode, full_page, pcount, pages); @@ -356,8 +354,6 @@ static int zisofs_read_folio(struct file *file, struct folio *folio) for (i = 0; i < pcount; i++) { if (pages[i]) { flush_dcache_page(pages[i]); - if (i == full_page && err) - SetPageError(pages[i]); unlock_page(pages[i]); if (i != full_page) put_page(pages[i]); From 290fa9471ee040734bbe873c3d7b2a20240b375a Mon Sep 17 00:00:00 2001 From: "Ritesh Harjani (IBM)" Date: Fri, 3 May 2024 14:58:52 +0530 Subject: [PATCH 19/20] ext2: Remove LEGACY_DIRECT_IO dependency commit fb5de4358e1a ("ext2: Move direct-io to use iomap"), converted ext2 direct-io to iomap which killed the call to blockdev_direct_IO(). So let's remove LEGACY_DIRECT_IO config dependency from ext2 Kconfig. Signed-off-by: Ritesh Harjani (IBM) Signed-off-by: Jan Kara Message-Id: --- fs/ext2/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/ext2/Kconfig b/fs/ext2/Kconfig index d6cfb1849580..d5bce83ad905 100644 --- a/fs/ext2/Kconfig +++ b/fs/ext2/Kconfig @@ -3,7 +3,6 @@ config EXT2_FS tristate "Second extended fs support (DEPRECATED)" select BUFFER_HEAD select FS_IOMAP - select LEGACY_DIRECT_IO help Ext2 is a standard Linux file system for hard disks. From 1dd719a959794467c2a75b3813df86cc6f55f5e3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 May 2024 18:21:11 +0300 Subject: [PATCH 20/20] isofs: Use *-y instead of *-objs in Makefile *-objs suffix is reserved rather for (user-space) host programs while usually *-y suffix is used for kernel drivers (although *-objs works for that purpose for now). Let's correct the old usages of *-objs in Makefiles. Signed-off-by: Andy Shevchenko Signed-off-by: Jan Kara Message-Id: <20240508152129.1445372-1-andriy.shevchenko@linux.intel.com> --- fs/isofs/Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/isofs/Makefile b/fs/isofs/Makefile index 6498fd2b0f60..b25bc542a22b 100644 --- a/fs/isofs/Makefile +++ b/fs/isofs/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_ISO9660_FS) += isofs.o -isofs-objs-y := namei.o inode.o dir.o util.o rock.o export.o -isofs-objs-$(CONFIG_JOLIET) += joliet.o -isofs-objs-$(CONFIG_ZISOFS) += compress.o -isofs-objs := $(isofs-objs-y) +isofs-y := namei.o inode.o dir.o util.o rock.o export.o +isofs-$(CONFIG_JOLIET) += joliet.o +isofs-$(CONFIG_ZISOFS) += compress.o