From b8a30b4171b9a3c22ef0605ed74a21544d00c680 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 18:35:49 +0300 Subject: fs/ntfs3: Remove unnecesarry mount option noatime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnecesarry mount option noatime because this will be handled by VFS. Our option parser will never get opt like this. Acked-by: Christian Brauner Reviewed-by: Christoph Hellwig Reviewed-by: Pali Rohár Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- Documentation/filesystems/ntfs3.rst | 4 ---- fs/ntfs3/super.c | 7 ------- 2 files changed, 11 deletions(-) diff --git a/Documentation/filesystems/ntfs3.rst b/Documentation/filesystems/ntfs3.rst index ffe9ea0c1499..af7158de6fde 100644 --- a/Documentation/filesystems/ntfs3.rst +++ b/Documentation/filesystems/ntfs3.rst @@ -85,10 +85,6 @@ acl Support POSIX ACLs (Access Control Lists). Effective if supported by Kernel. Not to be confused with NTFS ACLs. The option specified as acl enables support for POSIX ACLs. -noatime All files and directories will not update their last access - time attribute if a partition is mounted with this parameter. - This option can speed up file system operation. - =============================================================================== ToDo list diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 55bbc9200a10..a18b99a3e3b5 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -223,7 +223,6 @@ enum Opt { Opt_nohidden, Opt_showmeta, Opt_acl, - Opt_noatime, Opt_nls, Opt_prealloc, Opt_no_acs_rules, @@ -242,7 +241,6 @@ static const match_table_t ntfs_tokens = { { Opt_sparse, "sparse" }, { Opt_nohidden, "nohidden" }, { Opt_acl, "acl" }, - { Opt_noatime, "noatime" }, { Opt_showmeta, "showmeta" }, { Opt_nls, "nls=%s" }, { Opt_prealloc, "prealloc" }, @@ -333,9 +331,6 @@ static noinline int ntfs_parse_options(struct super_block *sb, char *options, ntfs_err(sb, "support for ACL not compiled in!"); return -EINVAL; #endif - case Opt_noatime: - sb->s_flags |= SB_NOATIME; - break; case Opt_showmeta: opts->showmeta = 1; break; @@ -587,8 +582,6 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root) seq_puts(m, ",prealloc"); if (sb->s_flags & SB_POSIXACL) seq_puts(m, ",acl"); - if (sb->s_flags & SB_NOATIME) - seq_puts(m, ",noatime"); return 0; } -- cgit v1.2.3 From c2c389fd6c6b0393549578997744b03822dd2b24 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 18:35:50 +0300 Subject: fs/ntfs3: Remove unnecesarry remount flag handling Remove unnecesarry remount flag handling. This does not do anything for this driver. We have already set SB_NODIRATIME when we fill super. Also noatime should be set from mount option. Now for some reson we try to set it when remounting. Lazytime part looks like it is copied from f2fs and there is own mount parameter for it. That is why they use it. We do not set lazytime anywhere in our code. So basically this just blocks lazytime when remounting. Acked-by: Christian Brauner Reviewed-by: Christoph Hellwig Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index a18b99a3e3b5..6cb689605089 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -417,8 +417,6 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *data) clear_mount_options(&old_opts); - *flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME) | - SB_NODIRATIME | SB_NOATIME; ntfs_info(sb, "re-mounted. Opts: %s", orig_data); err = 0; goto out; -- cgit v1.2.3 From 564c97bdfa39c7d1f331841fb24da6e714693037 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 18:35:51 +0300 Subject: fs/ntfs3: Convert mount options to pointer in sbi Use pointer to mount options. We want to do this because we will use new mount api which will benefit that we have spi and mount options in different allocations. When we remount we do not have to make whole new spi it is enough that we will allocate just mount options. Please note that we can do example remount lot cleaner but things will change in next patch so this should be just functional. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/attrib.c | 2 +- fs/ntfs3/dir.c | 8 ++++---- fs/ntfs3/file.c | 4 ++-- fs/ntfs3/inode.c | 12 ++++++------ fs/ntfs3/ntfs_fs.h | 2 +- fs/ntfs3/super.c | 31 +++++++++++++++++++------------ fs/ntfs3/xattr.c | 2 +- 7 files changed, 34 insertions(+), 27 deletions(-) diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index 34c4cbf7e29b..b1055b284c60 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -529,7 +529,7 @@ add_alloc_in_same_attr_seg: } else if (pre_alloc == -1) { pre_alloc = 0; if (type == ATTR_DATA && !name_len && - sbi->options.prealloc) { + sbi->options->prealloc) { CLST new_alen2 = bytes_to_cluster( sbi, get_pre_allocated(new_size)); pre_alloc = new_alen2 - new_alen; diff --git a/fs/ntfs3/dir.c b/fs/ntfs3/dir.c index 93f6d485564e..40440df021ef 100644 --- a/fs/ntfs3/dir.c +++ b/fs/ntfs3/dir.c @@ -24,7 +24,7 @@ int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni, int ret, uni_len, warn; const __le16 *ip; u8 *op; - struct nls_table *nls = sbi->options.nls; + struct nls_table *nls = sbi->options->nls; static_assert(sizeof(wchar_t) == sizeof(__le16)); @@ -186,7 +186,7 @@ int ntfs_nls_to_utf16(struct ntfs_sb_info *sbi, const u8 *name, u32 name_len, { int ret, slen; const u8 *end; - struct nls_table *nls = sbi->options.nls; + struct nls_table *nls = sbi->options->nls; u16 *uname = uni->name; static_assert(sizeof(wchar_t) == sizeof(u16)); @@ -301,10 +301,10 @@ static inline int ntfs_filldir(struct ntfs_sb_info *sbi, struct ntfs_inode *ni, return 0; /* Skip meta files. Unless option to show metafiles is set. */ - if (!sbi->options.showmeta && ntfs_is_meta_file(sbi, ino)) + if (!sbi->options->showmeta && ntfs_is_meta_file(sbi, ino)) return 0; - if (sbi->options.nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN)) + if (sbi->options->nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN)) return 0; name_len = ntfs_utf16_to_nls(sbi, (struct le_str *)&fname->name_len, diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index 424450e77ad5..fef57141b161 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -737,7 +737,7 @@ int ntfs3_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, umode_t mode = inode->i_mode; int err; - if (sbi->options.no_acs_rules) { + if (sbi->options->no_acs_rules) { /* "No access rules" - Force any changes of time etc. */ attr->ia_valid |= ATTR_FORCE; /* and disable for editing some attributes. */ @@ -1185,7 +1185,7 @@ static int ntfs_file_release(struct inode *inode, struct file *file) int err = 0; /* If we are last writer on the inode, drop the block reservation. */ - if (sbi->options.prealloc && ((file->f_mode & FMODE_WRITE) && + if (sbi->options->prealloc && ((file->f_mode & FMODE_WRITE) && atomic_read(&inode->i_writecount) == 1)) { ni_lock(ni); down_write(&ni->file.run_lock); diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index db2a5a4c38e4..9f740fd301b2 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -49,8 +49,8 @@ static struct inode *ntfs_read_mft(struct inode *inode, inode->i_op = NULL; /* Setup 'uid' and 'gid' */ - inode->i_uid = sbi->options.fs_uid; - inode->i_gid = sbi->options.fs_gid; + inode->i_uid = sbi->options->fs_uid; + inode->i_gid = sbi->options->fs_gid; err = mi_init(&ni->mi, sbi, ino); if (err) @@ -229,7 +229,7 @@ next_attr: t32 = le16_to_cpu(attr->nres.run_off); } - mode = S_IFREG | (0777 & sbi->options.fs_fmask_inv); + mode = S_IFREG | (0777 & sbi->options->fs_fmask_inv); if (!attr->non_res) { ni->ni_flags |= NI_FLAG_RESIDENT; @@ -272,7 +272,7 @@ next_attr: goto out; mode = sb->s_root - ? (S_IFDIR | (0777 & sbi->options.fs_dmask_inv)) + ? (S_IFDIR | (0777 & sbi->options->fs_dmask_inv)) : (S_IFDIR | 0777); goto next_attr; @@ -443,7 +443,7 @@ end_enum: goto out; } - if ((sbi->options.sys_immutable && + if ((sbi->options->sys_immutable && (std5->fa & FILE_ATTRIBUTE_SYSTEM)) && !S_ISFIFO(mode) && !S_ISSOCK(mode) && !S_ISLNK(mode)) { inode->i_flags |= S_IMMUTABLE; @@ -1244,7 +1244,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns, * } */ } else if (S_ISREG(mode)) { - if (sbi->options.sparse) { + if (sbi->options->sparse) { /* Sparsed regular file, cause option 'sparse'. */ fa = FILE_ATTRIBUTE_SPARSE_FILE | FILE_ATTRIBUTE_ARCHIVE; diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 97e682ebcfb9..98c90c399ee2 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -279,7 +279,7 @@ struct ntfs_sb_info { #endif } compress; - struct ntfs_mount_options options; + struct ntfs_mount_options *options; struct ratelimit_state msg_ratelimit; }; diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 6cb689605089..0f3820342051 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -389,11 +389,11 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *data) return -ENOMEM; /* Store original options. */ - memcpy(&old_opts, &sbi->options, sizeof(old_opts)); - clear_mount_options(&sbi->options); - memset(&sbi->options, 0, sizeof(sbi->options)); + memcpy(&old_opts, sbi->options, sizeof(old_opts)); + clear_mount_options(sbi->options); + memset(sbi->options, 0, sizeof(old_opts)); - err = ntfs_parse_options(sb, data, 0, &sbi->options); + err = ntfs_parse_options(sb, data, 0, sbi->options); if (err) goto restore_opts; @@ -409,7 +409,7 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *data) sync_filesystem(sb); if (ro_rw && (sbi->volume.flags & VOLUME_FLAG_DIRTY) && - !sbi->options.force) { + !sbi->options->force) { ntfs_warn(sb, "volume is dirty and \"force\" flag is not set!"); err = -EINVAL; goto restore_opts; @@ -422,8 +422,8 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *data) goto out; restore_opts: - clear_mount_options(&sbi->options); - memcpy(&sbi->options, &old_opts, sizeof(old_opts)); + clear_mount_options(sbi->options); + memcpy(sbi->options, &old_opts, sizeof(old_opts)); out: kfree(orig_data); @@ -506,7 +506,8 @@ static noinline void put_ntfs(struct ntfs_sb_info *sbi) xpress_free_decompressor(sbi->compress.xpress); lzx_free_decompressor(sbi->compress.lzx); #endif - clear_mount_options(&sbi->options); + clear_mount_options(sbi->options); + kfree(sbi->options); kfree(sbi); } @@ -545,7 +546,7 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root) { struct super_block *sb = root->d_sb; struct ntfs_sb_info *sbi = sb->s_fs_info; - struct ntfs_mount_options *opts = &sbi->options; + struct ntfs_mount_options *opts = sbi->options; struct user_namespace *user_ns = seq_user_ns(m); if (opts->uid) @@ -930,6 +931,12 @@ static int ntfs_fill_super(struct super_block *sb, void *data, int silent) if (!sbi) return -ENOMEM; + sbi->options = kzalloc(sizeof(struct ntfs_mount_options), GFP_NOFS); + if (!sbi->options) { + kfree(sbi); + return -ENOMEM; + } + sb->s_fs_info = sbi; sbi->sb = sb; sb->s_flags |= SB_NODIRATIME; @@ -942,7 +949,7 @@ static int ntfs_fill_super(struct super_block *sb, void *data, int silent) ratelimit_state_init(&sbi->msg_ratelimit, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); - err = ntfs_parse_options(sb, data, silent, &sbi->options); + err = ntfs_parse_options(sb, data, silent, sbi->options); if (err) goto out; @@ -1074,7 +1081,7 @@ static int ntfs_fill_super(struct super_block *sb, void *data, int silent) goto out; } } else if (sbi->volume.flags & VOLUME_FLAG_DIRTY) { - if (!is_ro && !sbi->options.force) { + if (!is_ro && !sbi->options->force) { ntfs_warn( sb, "volume is dirty and \"force\" flag is not set!"); @@ -1394,7 +1401,7 @@ int ntfs_discard(struct ntfs_sb_info *sbi, CLST lcn, CLST len) if (sbi->flags & NTFS_FLAGS_NODISCARD) return -EOPNOTSUPP; - if (!sbi->options.discard) + if (!sbi->options->discard) return -EOPNOTSUPP; lbo = (u64)lcn << sbi->cluster_bits; diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index b15d532e4a17..ac4b37bf8832 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -769,7 +769,7 @@ int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode) int ntfs_permission(struct user_namespace *mnt_userns, struct inode *inode, int mask) { - if (ntfs_sb(inode->i_sb)->options.no_acs_rules) { + if (ntfs_sb(inode->i_sb)->options->no_acs_rules) { /* "No access rules" mode - Allow all changes. */ return 0; } -- cgit v1.2.3 From 610f8f5a7baf998e70a61c63e53869b676d9b04c Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 18:35:52 +0300 Subject: fs/ntfs3: Use new api for mounting We have now new mount api as described in Documentation/filesystems. We should use it as it gives us some benefits which are desribed here lore.kernel.org/linux-fsdevel/159646178122.1784947.11705396571718464082.stgit@warthog.procyon.org.uk/ Nls loading is changed a to load with string. This did make code also little cleaner. Also try to use fsparam_flag_no as much as possible. This is just nice little touch and is not mandatory but it should not make any harm. It is just convenient that we can use example acl/noacl mount options. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/ntfs_fs.h | 1 + fs/ntfs3/super.c | 433 ++++++++++++++++++++++++++++------------------------- 2 files changed, 229 insertions(+), 205 deletions(-) diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 98c90c399ee2..aa18f12b7096 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -52,6 +52,7 @@ // clang-format on struct ntfs_mount_options { + char *nls_name; struct nls_table *nls; kuid_t fs_uid; diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 0f3820342051..befa78d3cb26 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -28,11 +28,12 @@ #include #include #include +#include +#include #include #include #include #include -#include #include #include @@ -205,9 +206,11 @@ void *ntfs_put_shared(void *ptr) return ret; } -static inline void clear_mount_options(struct ntfs_mount_options *options) +static inline void put_mount_options(struct ntfs_mount_options *options) { + kfree(options->nls_name); unload_nls(options->nls); + kfree(options); } enum Opt { @@ -229,205 +232,171 @@ enum Opt { Opt_err, }; -static const match_table_t ntfs_tokens = { - { Opt_uid, "uid=%u" }, - { Opt_gid, "gid=%u" }, - { Opt_umask, "umask=%o" }, - { Opt_dmask, "dmask=%o" }, - { Opt_fmask, "fmask=%o" }, - { Opt_immutable, "sys_immutable" }, - { Opt_discard, "discard" }, - { Opt_force, "force" }, - { Opt_sparse, "sparse" }, - { Opt_nohidden, "nohidden" }, - { Opt_acl, "acl" }, - { Opt_showmeta, "showmeta" }, - { Opt_nls, "nls=%s" }, - { Opt_prealloc, "prealloc" }, - { Opt_no_acs_rules, "no_acs_rules" }, - { Opt_err, NULL }, +static const struct fs_parameter_spec ntfs_fs_parameters[] = { + fsparam_u32("uid", Opt_uid), + fsparam_u32("gid", Opt_gid), + fsparam_u32oct("umask", Opt_umask), + fsparam_u32oct("dmask", Opt_dmask), + fsparam_u32oct("fmask", Opt_fmask), + fsparam_flag_no("sys_immutable", Opt_immutable), + fsparam_flag_no("discard", Opt_discard), + fsparam_flag_no("force", Opt_force), + fsparam_flag_no("sparse", Opt_sparse), + fsparam_flag("nohidden", Opt_nohidden), + fsparam_flag_no("acl", Opt_acl), + fsparam_flag_no("showmeta", Opt_showmeta), + fsparam_string("nls", Opt_nls), + fsparam_flag_no("prealloc", Opt_prealloc), + fsparam_flag("no_acs_rules", Opt_no_acs_rules), + {} }; -static noinline int ntfs_parse_options(struct super_block *sb, char *options, - int silent, - struct ntfs_mount_options *opts) +/* + * Load nls table or if @nls is utf8 then return NULL. + */ +static struct nls_table *ntfs_load_nls(char *nls) { - char *p; - substring_t args[MAX_OPT_ARGS]; - int option; - char nls_name[30]; - struct nls_table *nls; + struct nls_table *ret; - opts->fs_uid = current_uid(); - opts->fs_gid = current_gid(); - opts->fs_fmask_inv = opts->fs_dmask_inv = ~current_umask(); - nls_name[0] = 0; + if (!nls) + nls = CONFIG_NLS_DEFAULT; - if (!options) - goto out; + if (strcmp(nls, "utf8") == 0) + return NULL; - while ((p = strsep(&options, ","))) { - int token; + if (strcmp(nls, CONFIG_NLS_DEFAULT) == 0) + return load_nls_default(); - if (!*p) - continue; + ret = load_nls(nls); + if (ret) + return ret; - token = match_token(p, ntfs_tokens, args); - switch (token) { - case Opt_immutable: - opts->sys_immutable = 1; - break; - case Opt_uid: - if (match_int(&args[0], &option)) - return -EINVAL; - opts->fs_uid = make_kuid(current_user_ns(), option); - if (!uid_valid(opts->fs_uid)) - return -EINVAL; - opts->uid = 1; - break; - case Opt_gid: - if (match_int(&args[0], &option)) - return -EINVAL; - opts->fs_gid = make_kgid(current_user_ns(), option); - if (!gid_valid(opts->fs_gid)) - return -EINVAL; - opts->gid = 1; - break; - case Opt_umask: - if (match_octal(&args[0], &option)) - return -EINVAL; - opts->fs_fmask_inv = opts->fs_dmask_inv = ~option; - opts->fmask = opts->dmask = 1; - break; - case Opt_dmask: - if (match_octal(&args[0], &option)) - return -EINVAL; - opts->fs_dmask_inv = ~option; - opts->dmask = 1; - break; - case Opt_fmask: - if (match_octal(&args[0], &option)) - return -EINVAL; - opts->fs_fmask_inv = ~option; - opts->fmask = 1; - break; - case Opt_discard: - opts->discard = 1; - break; - case Opt_force: - opts->force = 1; - break; - case Opt_sparse: - opts->sparse = 1; - break; - case Opt_nohidden: - opts->nohidden = 1; - break; - case Opt_acl: + return ERR_PTR(-EINVAL); +} + +static int ntfs_fs_parse_param(struct fs_context *fc, + struct fs_parameter *param) +{ + struct ntfs_mount_options *opts = fc->fs_private; + struct fs_parse_result result; + int opt; + + opt = fs_parse(fc, ntfs_fs_parameters, param, &result); + if (opt < 0) + return opt; + + switch (opt) { + case Opt_uid: + opts->fs_uid = make_kuid(current_user_ns(), result.uint_32); + if (!uid_valid(opts->fs_uid)) + return invalf(fc, "ntfs3: Invalid value for uid."); + opts->uid = 1; + break; + case Opt_gid: + opts->fs_gid = make_kgid(current_user_ns(), result.uint_32); + if (!gid_valid(opts->fs_gid)) + return invalf(fc, "ntfs3: Invalid value for gid."); + opts->gid = 1; + break; + case Opt_umask: + if (result.uint_32 & ~07777) + return invalf(fc, "ntfs3: Invalid value for umask."); + opts->fs_fmask_inv = ~result.uint_32; + opts->fs_dmask_inv = ~result.uint_32; + opts->fmask = 1; + opts->dmask = 1; + break; + case Opt_dmask: + if (result.uint_32 & ~07777) + return invalf(fc, "ntfs3: Invalid value for dmask."); + opts->fs_dmask_inv = ~result.uint_32; + opts->dmask = 1; + break; + case Opt_fmask: + if (result.uint_32 & ~07777) + return invalf(fc, "ntfs3: Invalid value for fmask."); + opts->fs_fmask_inv = ~result.uint_32; + opts->fmask = 1; + break; + case Opt_immutable: + opts->sys_immutable = result.negated ? 0 : 1; + break; + case Opt_discard: + opts->discard = result.negated ? 0 : 1; + break; + case Opt_force: + opts->force = result.negated ? 0 : 1; + break; + case Opt_sparse: + opts->sparse = result.negated ? 0 : 1; + break; + case Opt_nohidden: + opts->nohidden = 1; + break; + case Opt_acl: + if (!result.negated) #ifdef CONFIG_NTFS3_FS_POSIX_ACL - sb->s_flags |= SB_POSIXACL; - break; + fc->sb_flags |= SB_POSIXACL; #else - ntfs_err(sb, "support for ACL not compiled in!"); - return -EINVAL; + return invalf(fc, "ntfs3: Support for ACL not compiled in!"); #endif - case Opt_showmeta: - opts->showmeta = 1; - break; - case Opt_nls: - match_strlcpy(nls_name, &args[0], sizeof(nls_name)); - break; - case Opt_prealloc: - opts->prealloc = 1; - break; - case Opt_no_acs_rules: - opts->no_acs_rules = 1; - break; - default: - if (!silent) - ntfs_err( - sb, - "Unrecognized mount option \"%s\" or missing value", - p); - //return -EINVAL; - } - } - -out: - if (!strcmp(nls_name[0] ? nls_name : CONFIG_NLS_DEFAULT, "utf8")) { - /* - * For UTF-8 use utf16s_to_utf8s()/utf8s_to_utf16s() - * instead of NLS. - */ - nls = NULL; - } else if (nls_name[0]) { - nls = load_nls(nls_name); - if (!nls) { - ntfs_err(sb, "failed to load \"%s\"", nls_name); - return -EINVAL; - } - } else { - nls = load_nls_default(); - if (!nls) { - ntfs_err(sb, "failed to load default nls"); - return -EINVAL; - } + else + fc->sb_flags &= ~SB_POSIXACL; + break; + case Opt_showmeta: + opts->showmeta = result.negated ? 0 : 1; + break; + case Opt_nls: + kfree(opts->nls_name); + opts->nls_name = param->string; + param->string = NULL; + break; + case Opt_prealloc: + opts->prealloc = result.negated ? 0 : 1; + break; + case Opt_no_acs_rules: + opts->no_acs_rules = 1; + break; + default: + /* Should not be here unless we forget add case. */ + return -EINVAL; } - opts->nls = nls; - return 0; } -static int ntfs_remount(struct super_block *sb, int *flags, char *data) +static int ntfs_fs_reconfigure(struct fs_context *fc) { - int err, ro_rw; + struct super_block *sb = fc->root->d_sb; struct ntfs_sb_info *sbi = sb->s_fs_info; - struct ntfs_mount_options old_opts; - char *orig_data = kstrdup(data, GFP_KERNEL); - - if (data && !orig_data) - return -ENOMEM; - - /* Store original options. */ - memcpy(&old_opts, sbi->options, sizeof(old_opts)); - clear_mount_options(sbi->options); - memset(sbi->options, 0, sizeof(old_opts)); - - err = ntfs_parse_options(sb, data, 0, sbi->options); - if (err) - goto restore_opts; + struct ntfs_mount_options *new_opts = fc->fs_private; + int ro_rw; - ro_rw = sb_rdonly(sb) && !(*flags & SB_RDONLY); + ro_rw = sb_rdonly(sb) && !(fc->sb_flags & SB_RDONLY); if (ro_rw && (sbi->flags & NTFS_FLAGS_NEED_REPLAY)) { - ntfs_warn( - sb, - "Couldn't remount rw because journal is not replayed. Please umount/remount instead\n"); - err = -EINVAL; - goto restore_opts; + errorf(fc, "ntfs3: Couldn't remount rw because journal is not replayed. Please umount/remount instead\n"); + return -EINVAL; + } + + new_opts->nls = ntfs_load_nls(new_opts->nls_name); + if (IS_ERR(new_opts->nls)) { + new_opts->nls = NULL; + errorf(fc, "ntfs3: Cannot load nls %s", new_opts->nls_name); + return -EINVAL; } + if (new_opts->nls != sbi->options->nls) + return invalf(fc, "ntfs3: Cannot use different nls when remounting!"); sync_filesystem(sb); if (ro_rw && (sbi->volume.flags & VOLUME_FLAG_DIRTY) && - !sbi->options->force) { - ntfs_warn(sb, "volume is dirty and \"force\" flag is not set!"); - err = -EINVAL; - goto restore_opts; + !new_opts->force) { + errorf(fc, "ntfs3: Volume is dirty and \"force\" flag is not set!"); + return -EINVAL; } - clear_mount_options(&old_opts); - - ntfs_info(sb, "re-mounted. Opts: %s", orig_data); - err = 0; - goto out; - -restore_opts: - clear_mount_options(sbi->options); - memcpy(sbi->options, &old_opts, sizeof(old_opts)); + memcpy(sbi->options, new_opts, sizeof(*new_opts)); -out: - kfree(orig_data); - return err; + return 0; } static struct kmem_cache *ntfs_inode_cachep; @@ -506,9 +475,6 @@ static noinline void put_ntfs(struct ntfs_sb_info *sbi) xpress_free_decompressor(sbi->compress.xpress); lzx_free_decompressor(sbi->compress.lzx); #endif - clear_mount_options(sbi->options); - kfree(sbi->options); - kfree(sbi); } @@ -519,7 +485,9 @@ static void ntfs_put_super(struct super_block *sb) /* Mark rw ntfs as clear, if possible. */ ntfs_set_state(sbi, NTFS_DIRTY_CLEAR); + put_mount_options(sbi->options); put_ntfs(sbi); + sb->s_fs_info = NULL; sync_blockdev(sb->s_bdev); } @@ -635,7 +603,6 @@ static const struct super_operations ntfs_sops = { .statfs = ntfs_statfs, .show_options = ntfs_show_options, .sync_fs = ntfs_sync_fs, - .remount_fs = ntfs_remount, .write_inode = ntfs3_write_inode, }; @@ -905,10 +872,10 @@ out: /* * ntfs_fill_super - Try to mount. */ -static int ntfs_fill_super(struct super_block *sb, void *data, int silent) +static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) { int err; - struct ntfs_sb_info *sbi; + struct ntfs_sb_info *sbi = sb->s_fs_info; struct block_device *bdev = sb->s_bdev; struct inode *bd_inode = bdev->bd_inode; struct request_queue *rq = bdev_get_queue(bdev); @@ -927,17 +894,6 @@ static int ntfs_fill_super(struct super_block *sb, void *data, int silent) ref.high = 0; - sbi = kzalloc(sizeof(struct ntfs_sb_info), GFP_NOFS); - if (!sbi) - return -ENOMEM; - - sbi->options = kzalloc(sizeof(struct ntfs_mount_options), GFP_NOFS); - if (!sbi->options) { - kfree(sbi); - return -ENOMEM; - } - - sb->s_fs_info = sbi; sbi->sb = sb; sb->s_flags |= SB_NODIRATIME; sb->s_magic = 0x7366746e; // "ntfs" @@ -949,9 +905,12 @@ static int ntfs_fill_super(struct super_block *sb, void *data, int silent) ratelimit_state_init(&sbi->msg_ratelimit, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); - err = ntfs_parse_options(sb, data, silent, sbi->options); - if (err) - goto out; + sbi->options->nls = ntfs_load_nls(sbi->options->nls_name); + if (IS_ERR(sbi->options->nls)) { + sbi->options->nls = NULL; + errorf(fc, "Cannot load nls %s", sbi->options->nls_name); + return -EINVAL; + } if (!rq || !blk_queue_discard(rq) || !rq->limits.discard_granularity) { ; @@ -1344,6 +1303,9 @@ load_root: goto out; } + fc->fs_private = NULL; + fc->s_fs_info = NULL; + return 0; out: @@ -1354,9 +1316,6 @@ out: sb->s_root = NULL; } - put_ntfs(sbi); - - sb->s_fs_info = NULL; return err; } @@ -1426,19 +1385,83 @@ int ntfs_discard(struct ntfs_sb_info *sbi, CLST lcn, CLST len) return err; } -static struct dentry *ntfs_mount(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) +static int ntfs_fs_get_tree(struct fs_context *fc) +{ + return get_tree_bdev(fc, ntfs_fill_super); +} + +/* + * ntfs_fs_free - Free fs_context. + * + * Note that this will be called after fill_super and reconfigure + * even when they pass. So they have to take pointers if they pass. + */ +static void ntfs_fs_free(struct fs_context *fc) +{ + struct ntfs_mount_options *opts = fc->fs_private; + struct ntfs_sb_info *sbi = fc->s_fs_info; + + if (sbi) + put_ntfs(sbi); + + if (opts) + put_mount_options(opts); +} + +static const struct fs_context_operations ntfs_context_ops = { + .parse_param = ntfs_fs_parse_param, + .get_tree = ntfs_fs_get_tree, + .reconfigure = ntfs_fs_reconfigure, + .free = ntfs_fs_free, +}; + +/* + * ntfs_init_fs_context - Initialize spi and opts + * + * This will called when mount/remount. We will first initiliaze + * options so that if remount we can use just that. + */ +static int ntfs_init_fs_context(struct fs_context *fc) { - return mount_bdev(fs_type, flags, dev_name, data, ntfs_fill_super); + struct ntfs_mount_options *opts; + struct ntfs_sb_info *sbi; + + opts = kzalloc(sizeof(struct ntfs_mount_options), GFP_NOFS); + if (!opts) + return -ENOMEM; + + /* Default options. */ + opts->fs_uid = current_uid(); + opts->fs_gid = current_gid(); + opts->fs_fmask_inv = ~current_umask(); + opts->fs_dmask_inv = ~current_umask(); + + if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) + goto ok; + + sbi = kzalloc(sizeof(struct ntfs_sb_info), GFP_NOFS); + if (!sbi) { + kfree(opts); + return -ENOMEM; + } + + sbi->options = opts; + fc->s_fs_info = sbi; +ok: + fc->fs_private = opts; + fc->ops = &ntfs_context_ops; + + return 0; } // clang-format off static struct file_system_type ntfs_fs_type = { - .owner = THIS_MODULE, - .name = "ntfs3", - .mount = ntfs_mount, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP, + .owner = THIS_MODULE, + .name = "ntfs3", + .init_fs_context = ntfs_init_fs_context, + .parameters = ntfs_fs_parameters, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP, }; // clang-format on -- cgit v1.2.3 From 27fac77707a1d99deef33fd5f3f5f2ed96bfbf6a Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 18:35:53 +0300 Subject: fs/ntfs3: Init spi more in init_fs_context than fill_super init_fs_context() is meant to initialize s_fs_info (spi). Move spi initializing code there which we can initialize before fill_super(). Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index befa78d3cb26..420cd1409170 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -887,7 +887,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) const struct VOLUME_INFO *info; u32 idx, done, bytes; struct ATTR_DEF_ENTRY *t; - u16 *upcase = NULL; + u16 *upcase; u16 *shared; bool is_ro; struct MFT_REF ref; @@ -902,9 +902,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) sb->s_time_gran = NTFS_TIME_GRAN; // 100 nsec sb->s_xattr = ntfs_xattr_handlers; - ratelimit_state_init(&sbi->msg_ratelimit, DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); - sbi->options->nls = ntfs_load_nls(sbi->options->nls_name); if (IS_ERR(sbi->options->nls)) { sbi->options->nls = NULL; @@ -934,12 +931,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) sb->s_maxbytes = 0xFFFFFFFFull << sbi->cluster_bits; #endif - mutex_init(&sbi->compress.mtx_lznt); -#ifdef CONFIG_NTFS3_LZX_XPRESS - mutex_init(&sbi->compress.mtx_xpress); - mutex_init(&sbi->compress.mtx_lzx); -#endif - /* * Load $Volume. This should be done before $LogFile * 'cause 'sbi->volume.ni' is used 'ntfs_set_state'. @@ -1224,11 +1215,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) goto out; } - sbi->upcase = upcase = kvmalloc(0x10000 * sizeof(short), GFP_KERNEL); - if (!upcase) { - err = -ENOMEM; - goto out; - } + upcase = sbi->upcase; for (idx = 0; idx < (0x10000 * sizeof(short) >> PAGE_SHIFT); idx++) { const __le16 *src; @@ -1440,10 +1427,21 @@ static int ntfs_init_fs_context(struct fs_context *fc) goto ok; sbi = kzalloc(sizeof(struct ntfs_sb_info), GFP_NOFS); - if (!sbi) { - kfree(opts); - return -ENOMEM; - } + if (!sbi) + goto free_opts; + + sbi->upcase = kvmalloc(0x10000 * sizeof(short), GFP_KERNEL); + if (!sbi->upcase) + goto free_sbi; + + ratelimit_state_init(&sbi->msg_ratelimit, DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + + mutex_init(&sbi->compress.mtx_lznt); +#ifdef CONFIG_NTFS3_LZX_XPRESS + mutex_init(&sbi->compress.mtx_xpress); + mutex_init(&sbi->compress.mtx_lzx); +#endif sbi->options = opts; fc->s_fs_info = sbi; @@ -1452,6 +1450,11 @@ ok: fc->ops = &ntfs_context_ops; return 0; +free_opts: + kfree(opts); +free_sbi: + kfree(sbi); + return -ENOMEM; } // clang-format off -- cgit v1.2.3 From 9d1939f4575f3fda70dd94542dbd4d775e104132 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 18:35:54 +0300 Subject: fs/ntfs3: Make mount option nohidden more universal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we call Opt_nohidden with just keyword hidden, then we can use hidden/nohidden when mounting. We already use this method for almoust all other parameters so it is just logical that this will use same method. Acked-by: Christian Brauner Reviewed-by: Christoph Hellwig Reviewed-by: Pali Rohár Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 420cd1409170..729ead6f2fac 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -242,7 +242,7 @@ static const struct fs_parameter_spec ntfs_fs_parameters[] = { fsparam_flag_no("discard", Opt_discard), fsparam_flag_no("force", Opt_force), fsparam_flag_no("sparse", Opt_sparse), - fsparam_flag("nohidden", Opt_nohidden), + fsparam_flag_no("hidden", Opt_nohidden), fsparam_flag_no("acl", Opt_acl), fsparam_flag_no("showmeta", Opt_showmeta), fsparam_string("nls", Opt_nls), @@ -331,7 +331,7 @@ static int ntfs_fs_parse_param(struct fs_context *fc, opts->sparse = result.negated ? 0 : 1; break; case Opt_nohidden: - opts->nohidden = 1; + opts->nohidden = result.negated ? 1 : 0; break; case Opt_acl: if (!result.negated) -- cgit v1.2.3 From e274cde8c7550cac46eb7aba3a77aff44ae0b301 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 18:35:55 +0300 Subject: fs/ntfs3: Add iocharset= mount option as alias for nls= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Other fs drivers are using iocharset= mount option for specifying charset. So add it also for ntfs3 and mark old nls= mount option as deprecated. Reviewed-by: Pali Rohár Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- Documentation/filesystems/ntfs3.rst | 4 ++-- fs/ntfs3/super.c | 18 +++++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Documentation/filesystems/ntfs3.rst b/Documentation/filesystems/ntfs3.rst index af7158de6fde..ded706474825 100644 --- a/Documentation/filesystems/ntfs3.rst +++ b/Documentation/filesystems/ntfs3.rst @@ -32,12 +32,12 @@ generic ones. =============================================================================== -nls=name This option informs the driver how to interpret path +iocharset=name This option informs the driver how to interpret path strings and translate them to Unicode and back. If this option is not set, the default codepage will be used (CONFIG_NLS_DEFAULT). Examples: - 'nls=utf8' + 'iocharset=utf8' uid= gid= diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 729ead6f2fac..503e2e23f711 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -226,7 +226,7 @@ enum Opt { Opt_nohidden, Opt_showmeta, Opt_acl, - Opt_nls, + Opt_iocharset, Opt_prealloc, Opt_no_acs_rules, Opt_err, @@ -245,9 +245,13 @@ static const struct fs_parameter_spec ntfs_fs_parameters[] = { fsparam_flag_no("hidden", Opt_nohidden), fsparam_flag_no("acl", Opt_acl), fsparam_flag_no("showmeta", Opt_showmeta), - fsparam_string("nls", Opt_nls), fsparam_flag_no("prealloc", Opt_prealloc), fsparam_flag("no_acs_rules", Opt_no_acs_rules), + fsparam_string("iocharset", Opt_iocharset), + + __fsparam(fs_param_is_string, + "nls", Opt_iocharset, + fs_param_deprecated, NULL), {} }; @@ -346,7 +350,7 @@ static int ntfs_fs_parse_param(struct fs_context *fc, case Opt_showmeta: opts->showmeta = result.negated ? 0 : 1; break; - case Opt_nls: + case Opt_iocharset: kfree(opts->nls_name); opts->nls_name = param->string; param->string = NULL; @@ -380,11 +384,11 @@ static int ntfs_fs_reconfigure(struct fs_context *fc) new_opts->nls = ntfs_load_nls(new_opts->nls_name); if (IS_ERR(new_opts->nls)) { new_opts->nls = NULL; - errorf(fc, "ntfs3: Cannot load nls %s", new_opts->nls_name); + errorf(fc, "ntfs3: Cannot load iocharset %s", new_opts->nls_name); return -EINVAL; } if (new_opts->nls != sbi->options->nls) - return invalf(fc, "ntfs3: Cannot use different nls when remounting!"); + return invalf(fc, "ntfs3: Cannot use different iocharset when remounting!"); sync_filesystem(sb); @@ -528,9 +532,9 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root) if (opts->dmask) seq_printf(m, ",dmask=%04o", ~opts->fs_dmask_inv); if (opts->nls) - seq_printf(m, ",nls=%s", opts->nls->charset); + seq_printf(m, ",iocharset=%s", opts->nls->charset); else - seq_puts(m, ",nls=utf8"); + seq_puts(m, ",iocharset=utf8"); if (opts->sys_immutable) seq_puts(m, ",sys_immutable"); if (opts->discard) -- cgit v1.2.3 From 28a941ffc1404b66d67228cbe8392bbadb94af0d Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 18:35:56 +0300 Subject: fs/ntfs3: Rename mount option no_acs_rules > (no)acsrules Rename mount option no_acs_rules to (no)acsrules. This allow us to use possibility to mount with options noaclrules or aclrules. Acked-by: Christian Brauner Reviewed-by: Christoph Hellwig Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- Documentation/filesystems/ntfs3.rst | 2 +- fs/ntfs3/file.c | 2 +- fs/ntfs3/ntfs_fs.h | 2 +- fs/ntfs3/super.c | 12 ++++++------ fs/ntfs3/xattr.c | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/filesystems/ntfs3.rst b/Documentation/filesystems/ntfs3.rst index ded706474825..7b6afe452197 100644 --- a/Documentation/filesystems/ntfs3.rst +++ b/Documentation/filesystems/ntfs3.rst @@ -73,7 +73,7 @@ prealloc Preallocate space for files excessively when file size is increasing on writes. Decreases fragmentation in case of parallel write operations to different files. -no_acs_rules "No access rules" mount option sets access rights for +noacsrules "No access rules" mount option sets access rights for files/folders to 777 and owner/group to root. This mount option absorbs all other permissions: - permissions change for files/folders will be reported diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index fef57141b161..0743d806c567 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -737,7 +737,7 @@ int ntfs3_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, umode_t mode = inode->i_mode; int err; - if (sbi->options->no_acs_rules) { + if (sbi->options->noacsrules) { /* "No access rules" - Force any changes of time etc. */ attr->ia_valid |= ATTR_FORCE; /* and disable for editing some attributes. */ diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index aa18f12b7096..15bab48bc1ad 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -70,7 +70,7 @@ struct ntfs_mount_options { showmeta : 1, /* Show meta files. */ nohidden : 1, /* Do not show hidden files. */ force : 1, /* Rw mount dirty volume. */ - no_acs_rules : 1, /*Exclude acs rules. */ + noacsrules : 1, /*Exclude acs rules. */ prealloc : 1 /* Preallocate space when file is growing. */ ; }; diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 503e2e23f711..0690e7e4f00d 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -228,7 +228,7 @@ enum Opt { Opt_acl, Opt_iocharset, Opt_prealloc, - Opt_no_acs_rules, + Opt_noacsrules, Opt_err, }; @@ -246,7 +246,7 @@ static const struct fs_parameter_spec ntfs_fs_parameters[] = { fsparam_flag_no("acl", Opt_acl), fsparam_flag_no("showmeta", Opt_showmeta), fsparam_flag_no("prealloc", Opt_prealloc), - fsparam_flag("no_acs_rules", Opt_no_acs_rules), + fsparam_flag_no("acsrules", Opt_noacsrules), fsparam_string("iocharset", Opt_iocharset), __fsparam(fs_param_is_string, @@ -358,8 +358,8 @@ static int ntfs_fs_parse_param(struct fs_context *fc, case Opt_prealloc: opts->prealloc = result.negated ? 0 : 1; break; - case Opt_no_acs_rules: - opts->no_acs_rules = 1; + case Opt_noacsrules: + opts->noacsrules = result.negated ? 1 : 0; break; default: /* Should not be here unless we forget add case. */ @@ -547,8 +547,8 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root) seq_puts(m, ",nohidden"); if (opts->force) seq_puts(m, ",force"); - if (opts->no_acs_rules) - seq_puts(m, ",no_acs_rules"); + if (opts->noacsrules) + seq_puts(m, ",noacsrules"); if (opts->prealloc) seq_puts(m, ",prealloc"); if (sb->s_flags & SB_POSIXACL) diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index ac4b37bf8832..6f88cb77a17f 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -769,7 +769,7 @@ int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode) int ntfs_permission(struct user_namespace *mnt_userns, struct inode *inode, int mask) { - if (ntfs_sb(inode->i_sb)->options->no_acs_rules) { + if (ntfs_sb(inode->i_sb)->options->noacsrules) { /* "No access rules" mode - Allow all changes. */ return 0; } -- cgit v1.2.3 From 15b2ae776044ac52cddda8a3e6c9fecd15226b8c Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 18:35:57 +0300 Subject: fs/ntfs3: Show uid/gid always in show_options() Show options should show option according documentation when some value is not default or when ever coder wants. Uid/gid are problematic because it is hard to know which are defaults. In file system there is many different implementation for this problem. Some file systems show uid/gid when they are different than root, some when user has set them and some show them always. There is also problem that what if root uid/gid change. This code just choose to show them always. This way we do not need to think this any more. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/ntfs_fs.h | 23 ++++++++++------------- fs/ntfs3/super.c | 12 ++++-------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 15bab48bc1ad..372cda697dd4 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -60,19 +60,16 @@ struct ntfs_mount_options { u16 fs_fmask_inv; u16 fs_dmask_inv; - unsigned uid : 1, /* uid was set. */ - gid : 1, /* gid was set. */ - fmask : 1, /* fmask was set. */ - dmask : 1, /* dmask was set. */ - sys_immutable : 1, /* Immutable system files. */ - discard : 1, /* Issue discard requests on deletions. */ - sparse : 1, /* Create sparse files. */ - showmeta : 1, /* Show meta files. */ - nohidden : 1, /* Do not show hidden files. */ - force : 1, /* Rw mount dirty volume. */ - noacsrules : 1, /*Exclude acs rules. */ - prealloc : 1 /* Preallocate space when file is growing. */ - ; + unsigned fmask : 1; /* fmask was set. */ + unsigned dmask : 1; /*dmask was set. */ + unsigned sys_immutable : 1; /* Immutable system files. */ + unsigned discard : 1; /* Issue discard requests on deletions. */ + unsigned sparse : 1; /* Create sparse files. */ + unsigned showmeta : 1; /* Show meta files. */ + unsigned nohidden : 1; /* Do not show hidden files. */ + unsigned force : 1; /* RW mount dirty volume. */ + unsigned noacsrules : 1; /* Exclude acs rules. */ + unsigned prealloc : 1; /* Preallocate space when file is growing. */ }; /* Special value to unpack and deallocate. */ diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 0690e7e4f00d..3cba0b5e7ac7 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -294,13 +294,11 @@ static int ntfs_fs_parse_param(struct fs_context *fc, opts->fs_uid = make_kuid(current_user_ns(), result.uint_32); if (!uid_valid(opts->fs_uid)) return invalf(fc, "ntfs3: Invalid value for uid."); - opts->uid = 1; break; case Opt_gid: opts->fs_gid = make_kgid(current_user_ns(), result.uint_32); if (!gid_valid(opts->fs_gid)) return invalf(fc, "ntfs3: Invalid value for gid."); - opts->gid = 1; break; case Opt_umask: if (result.uint_32 & ~07777) @@ -521,12 +519,10 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root) struct ntfs_mount_options *opts = sbi->options; struct user_namespace *user_ns = seq_user_ns(m); - if (opts->uid) - seq_printf(m, ",uid=%u", - from_kuid_munged(user_ns, opts->fs_uid)); - if (opts->gid) - seq_printf(m, ",gid=%u", - from_kgid_munged(user_ns, opts->fs_gid)); + seq_printf(m, ",uid=%u", + from_kuid_munged(user_ns, opts->fs_uid)); + seq_printf(m, ",gid=%u", + from_kgid_munged(user_ns, opts->fs_gid)); if (opts->fmask) seq_printf(m, ",fmask=%04o", ~opts->fs_fmask_inv); if (opts->dmask) -- cgit v1.2.3 From 0327c6d01a97a3242cf10717819994aa6e095a1d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 3 Sep 2021 14:24:58 +0100 Subject: fs/ntfs3: Remove redundant initialization of variable err The variable err is being initialized with a value that is never read, it is being updated later on. The assignment is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/index.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index 0daca9adc54c..b1175542d854 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -1401,7 +1401,7 @@ ok: static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, CLST *vbn) { - int err = -ENOMEM; + int err; struct ntfs_sb_info *sbi = ni->mi.sbi; struct ATTRIB *bitmap; struct ATTRIB *alloc; -- cgit v1.2.3 From cde81f13ef63d47c3f0742fbe6f17a5123cf6ca4 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 2 Sep 2021 19:15:21 +0300 Subject: fs/ntfs3. Add forward declarations for structs to debug.h Add forward declarations for structs so that we can include this file without warnings even without linux/fs.h Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/debug.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/ntfs3/debug.h b/fs/ntfs3/debug.h index 31120569a87b..53ef7489c75f 100644 --- a/fs/ntfs3/debug.h +++ b/fs/ntfs3/debug.h @@ -11,6 +11,9 @@ #ifndef _LINUX_NTFS3_DEBUG_H #define _LINUX_NTFS3_DEBUG_H +struct super_block; +struct inode; + #ifndef Add2Ptr #define Add2Ptr(P, I) ((void *)((u8 *)(P) + (I))) #define PtrOffset(B, O) ((size_t)((size_t)(O) - (size_t)(B))) -- cgit v1.2.3 From 4dfe83320e1e9665b986840b426742ea764e08d7 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 2 Sep 2021 19:15:22 +0300 Subject: fs/ntfs3: Add missing header files to ntfs.h We do not have header files at all in this file. Add following headers and there is also explanation which for it was added. Note that explanation might not be complete, but it just proofs it is needed. // SECTOR_SHIFT // static_assert() // cpu_to_le64, cpu_to_le32, ALIGN // offsetof() // memcmp() //__le32, __le16 "debug.h" // PtrOffset(), Add2Ptr() Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/ntfs.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/ntfs3/ntfs.h b/fs/ntfs3/ntfs.h index 6bb3e595263b..695b684bce20 100644 --- a/fs/ntfs3/ntfs.h +++ b/fs/ntfs3/ntfs.h @@ -10,6 +10,15 @@ #ifndef _LINUX_NTFS3_NTFS_H #define _LINUX_NTFS3_NTFS_H +#include +#include +#include +#include +#include +#include + +#include "debug.h" + /* TODO: Check 4K MFT record and 512 bytes cluster. */ /* Activate this define to use binary search in indexes. */ -- cgit v1.2.3 From f239b3a95dd4f7daba26ea17f339a5b19a7d40a1 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 2 Sep 2021 19:15:23 +0300 Subject: fs/ntfs3: Add missing headers and forward declarations to ntfs_fs.h We do not have headers at all in this file. We should have them so that not every .c file needs to include all of the stuff which this file need for building. This way we can remove some headers from other files and get better picture what is needed. This can save some compilation time. And this can help if we sometimes want to separate this one big header. Also use forward declarations for structs and enums when it not included straight with include and it is used in function declarations input. This will prevent possible compiler warning: xxx declared inside parameter list will not be visible outside of this definition or declaration Here is list which I made when parsing this. There is not necessarily all example from this header file, but this just proofs we need it. SECTOR_SHIFT sb_bread(), put_bh put_page() struct inode (Just struct ntfs_inode need it) kunmap(), kmap() cpu_to_leXX() ALIGN kvfree() struct mutex, mutex_(un/try)lock() PageError() read_mapping_page() struct rb_root struct rw_semaphore krfree(), kzalloc() memset() struct timespec64 uXX, __leXX kuid_t, kgid_t do_div() PAGE_SIZE "debug.h" ntfs_err() (Just one entry. Maybe we can drop this) "ntfs.h" Do you even ask? Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/ntfs_fs.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 372cda697dd4..dae6dd4ac619 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -9,6 +9,37 @@ #ifndef _LINUX_NTFS3_NTFS_FS_H #define _LINUX_NTFS3_NTFS_FS_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "ntfs.h" + +struct dentry; +struct fiemap_extent_info; +struct user_namespace; +struct page; +struct writeback_control; +enum utf16_endian; + + #define MINUS_ONE_T ((size_t)(-1)) /* Biggest MFT / smallest cluster */ #define MAXIMUM_BYTES_PER_MFT 4096 -- cgit v1.2.3 From b6ba81034b1b74cf426abcece4becda2611504a4 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 2 Sep 2021 19:15:24 +0300 Subject: fs/ntfs3: Add missing header and guards to lib/ headers size_t needs header. Add missing header guards so that compiler will only include these ones. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/lib/decompress_common.h | 5 +++++ fs/ntfs3/lib/lib.h | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/fs/ntfs3/lib/decompress_common.h b/fs/ntfs3/lib/decompress_common.h index 2d70ae42f1b5..dd7ced000d0e 100644 --- a/fs/ntfs3/lib/decompress_common.h +++ b/fs/ntfs3/lib/decompress_common.h @@ -5,6 +5,9 @@ * Copyright (C) 2015 Eric Biggers */ +#ifndef _LINUX_NTFS3_LIB_DECOMPRESS_COMMON_H +#define _LINUX_NTFS3_LIB_DECOMPRESS_COMMON_H + #include #include #include @@ -336,3 +339,5 @@ static forceinline u8 *lz_copy(u8 *dst, u32 length, u32 offset, const u8 *bufend return dst; } + +#endif /* _LINUX_NTFS3_LIB_DECOMPRESS_COMMON_H */ diff --git a/fs/ntfs3/lib/lib.h b/fs/ntfs3/lib/lib.h index f508fbad2e71..90309a5ae59c 100644 --- a/fs/ntfs3/lib/lib.h +++ b/fs/ntfs3/lib/lib.h @@ -7,6 +7,10 @@ * - linux kernel code style */ +#ifndef _LINUX_NTFS3_LIB_LIB_H +#define _LINUX_NTFS3_LIB_LIB_H + +#include /* globals from xpress_decompress.c */ struct xpress_decompressor *xpress_allocate_decompressor(void); @@ -24,3 +28,5 @@ int lzx_decompress(struct lzx_decompressor *__restrict d, const void *__restrict compressed_data, size_t compressed_size, void *__restrict uncompressed_data, size_t uncompressed_size); + +#endif /* _LINUX_NTFS3_LIB_LIB_H */ -- cgit v1.2.3 From c632f639d1d9bb3e379741a30c6882342d859daf Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 2 Sep 2021 19:15:25 +0300 Subject: fs/ntfs3: Change right headers to bitfunc.c We only need linux/types.h for types like u8 etc. So we can remove rest and help compiler a little bit. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/bitfunc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/ntfs3/bitfunc.c b/fs/ntfs3/bitfunc.c index ce304d40b5e1..bf10e2da5c6e 100644 --- a/fs/ntfs3/bitfunc.c +++ b/fs/ntfs3/bitfunc.c @@ -5,13 +5,8 @@ * */ -#include -#include -#include -#include +#include -#include "debug.h" -#include "ntfs.h" #include "ntfs_fs.h" #define BITS_IN_SIZE_T (sizeof(size_t) * 8) -- cgit v1.2.3 From f97676611937f4550a60970acadeccbd5e6f124c Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 2 Sep 2021 19:15:26 +0300 Subject: fs/ntfs3: Change right headers to upcase.c There is no headers. They will be included through ntfs_fs.c, but that is not right thing to do. Let's include headers what this file need straight away. types.h is needed for __le16, u8 etc. kernel.h is needed for le16_to_cpu() Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/upcase.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fs/ntfs3/upcase.c b/fs/ntfs3/upcase.c index bbeba778237e..b5e8256fd710 100644 --- a/fs/ntfs3/upcase.c +++ b/fs/ntfs3/upcase.c @@ -5,13 +5,9 @@ * */ -#include -#include -#include -#include +#include +#include -#include "debug.h" -#include "ntfs.h" #include "ntfs_fs.h" static inline u16 upcase_unicode_char(const u16 *upcase, u16 chr) -- cgit v1.2.3 From 977d0558e310113767feed91fdcc618691dd2835 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 2 Sep 2021 19:15:27 +0300 Subject: fs/ntfs3: Change right headers to lznt.c There is lot of headers which we do not need in this file. Delete them and add what we really need. Here is list which identify why we need this header. // min() // kzalloc() // offsetof() // memcpy(), memset() // u8, size_t, etc. "debug.h" // PtrOffset() Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/lznt.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/ntfs3/lznt.c b/fs/ntfs3/lznt.c index f1f691a67cc4..12ba42518efe 100644 --- a/fs/ntfs3/lznt.c +++ b/fs/ntfs3/lznt.c @@ -5,13 +5,13 @@ * */ -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "debug.h" -#include "ntfs.h" #include "ntfs_fs.h" // clang-format off -- cgit v1.2.3 From 9c2aadd0fdf88a7ebeebd1e97a9c66b07ad3e14a Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 2 Sep 2021 19:15:28 +0300 Subject: fs/ntfs3: Remove unneeded header files from c files We have lot of unnecessary headers in these files. Remove them so that we help compiler a little bit. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/attrib.c | 5 ----- fs/ntfs3/attrlist.c | 3 --- fs/ntfs3/bitmap.c | 3 --- fs/ntfs3/dir.c | 3 --- fs/ntfs3/file.c | 1 - fs/ntfs3/frecord.c | 3 --- fs/ntfs3/fslog.c | 4 ---- fs/ntfs3/fsntfs.c | 1 - fs/ntfs3/index.c | 1 - fs/ntfs3/inode.c | 2 -- fs/ntfs3/namei.c | 4 ---- fs/ntfs3/record.c | 3 --- fs/ntfs3/run.c | 2 -- fs/ntfs3/super.c | 2 -- fs/ntfs3/xattr.c | 3 --- 15 files changed, 40 deletions(-) diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index b1055b284c60..12cff28f3e71 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -6,12 +6,7 @@ * TODO: Merge attr_set_size/attr_data_get_block/attr_allocate_frame? */ -#include -#include #include -#include -#include -#include #include #include "debug.h" diff --git a/fs/ntfs3/attrlist.c b/fs/ntfs3/attrlist.c index fa32399eb517..b9da527b96aa 100644 --- a/fs/ntfs3/attrlist.c +++ b/fs/ntfs3/attrlist.c @@ -5,10 +5,7 @@ * */ -#include -#include #include -#include #include "debug.h" #include "ntfs.h" diff --git a/fs/ntfs3/bitmap.c b/fs/ntfs3/bitmap.c index 831501555009..a03584674fea 100644 --- a/fs/ntfs3/bitmap.c +++ b/fs/ntfs3/bitmap.c @@ -10,12 +10,9 @@ * */ -#include #include #include -#include -#include "debug.h" #include "ntfs.h" #include "ntfs_fs.h" diff --git a/fs/ntfs3/dir.c b/fs/ntfs3/dir.c index 40440df021ef..785e72d4392e 100644 --- a/fs/ntfs3/dir.c +++ b/fs/ntfs3/dir.c @@ -7,10 +7,7 @@ * */ -#include -#include #include -#include #include #include "debug.h" diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index 0743d806c567..5fb3508e5422 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -12,7 +12,6 @@ #include #include #include -#include #include "debug.h" #include "ntfs.h" diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 938b12d56ca6..080264ced909 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -5,11 +5,8 @@ * */ -#include -#include #include #include -#include #include #include "debug.h" diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c index b5853aed0e25..6e7f9b72792b 100644 --- a/fs/ntfs3/fslog.c +++ b/fs/ntfs3/fslog.c @@ -6,12 +6,8 @@ */ #include -#include #include -#include -#include #include -#include #include #include "debug.h" diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index 91e3743e1442..9232a7f410c6 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -8,7 +8,6 @@ #include #include #include -#include #include "debug.h" #include "ntfs.h" diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index b1175542d854..35b77c92e96d 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -8,7 +8,6 @@ #include #include #include -#include #include "debug.h" #include "ntfs.h" diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 9f740fd301b2..33f278a0947c 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -5,10 +5,8 @@ * */ -#include #include #include -#include #include #include #include diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index e58415d07132..1c475da4e19d 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -5,11 +5,7 @@ * */ -#include -#include #include -#include -#include #include #include "debug.h" diff --git a/fs/ntfs3/record.c b/fs/ntfs3/record.c index 103705c86772..861e35791506 100644 --- a/fs/ntfs3/record.c +++ b/fs/ntfs3/record.c @@ -5,10 +5,7 @@ * */ -#include -#include #include -#include #include "debug.h" #include "ntfs.h" diff --git a/fs/ntfs3/run.c b/fs/ntfs3/run.c index 26ed2b64345e..a8fec651f973 100644 --- a/fs/ntfs3/run.c +++ b/fs/ntfs3/run.c @@ -7,10 +7,8 @@ */ #include -#include #include #include -#include #include "debug.h" #include "ntfs.h" diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 3cba0b5e7ac7..acfa00acf4dd 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -23,14 +23,12 @@ * */ -#include #include #include #include #include #include #include -#include #include #include #include diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 6f88cb77a17f..a8c5a899f0dd 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -5,10 +5,7 @@ * */ -#include -#include #include -#include #include #include #include -- cgit v1.2.3 From 162333efa8dc4984d2ca0a2eb85528e13366f271 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 2 Sep 2021 18:40:48 +0300 Subject: fs/ntfs3: Limit binary search table size Current binary search allocates memory for table and fill whole table before we start actual binary search. This is quite inefficient because table fill will always be O(n). Also if table is huge we need to reallocate memory which is costly. This implementation use just stack memory and always when table is full we will check if last element is <= and if not start table fill again. The idea was that it would be same cost as table reallocation. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/index.c | 110 +++++++++++++++++++++---------------------------------- 1 file changed, 41 insertions(+), 69 deletions(-) diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index 35b77c92e96d..a16256ab3e9f 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -677,98 +677,70 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx, u32 off = le32_to_cpu(hdr->de_off); #ifdef NTFS3_INDEX_BINARY_SEARCH - int max_idx = 0, fnd, min_idx; - int nslots = 64; - u16 *offs; + struct NTFS_DE *found = NULL; + int min_idx = 0, mid_idx, max_idx = 0; + int diff2; + u16 offs[64]; if (end > 0x10000) goto next; - offs = kmalloc(sizeof(u16) * nslots, GFP_NOFS); - if (!offs) - goto next; +fill_table: + if (off + sizeof(struct NTFS_DE) > end) + return NULL; - /* Use binary search algorithm. */ -next1: - if (off + sizeof(struct NTFS_DE) > end) { - e = NULL; - goto out1; - } e = Add2Ptr(hdr, off); e_size = le16_to_cpu(e->size); - if (e_size < sizeof(struct NTFS_DE) || off + e_size > end) { - e = NULL; - goto out1; - } - - if (max_idx >= nslots) { - u16 *ptr; - int new_slots = ALIGN(2 * nslots, 8); - - ptr = kmalloc(sizeof(u16) * new_slots, GFP_NOFS); - if (ptr) - memcpy(ptr, offs, sizeof(u16) * max_idx); - kfree(offs); - offs = ptr; - nslots = new_slots; - if (!ptr) - goto next; - } - - /* Store entry table. */ - offs[max_idx] = off; + if (e_size < sizeof(struct NTFS_DE) || off + e_size > end) + return NULL; if (!de_is_last(e)) { + offs[max_idx] = off; off += e_size; - max_idx += 1; - goto next1; - } - /* - * Table of pointers is created. - * Use binary search to find entry that is <= to the search value. - */ - fnd = -1; - min_idx = 0; + max_idx++; + if (max_idx < ARRAY_SIZE(offs)) + goto fill_table; - while (min_idx <= max_idx) { - int mid_idx = min_idx + ((max_idx - min_idx) >> 1); - int diff2; - - e = Add2Ptr(hdr, offs[mid_idx]); + max_idx--; + } - e_key_len = le16_to_cpu(e->key_size); +binary_search: + e_key_len = le16_to_cpu(e->key_size); - diff2 = (*cmp)(key, key_len, e + 1, e_key_len, ctx); + diff2 = (*cmp)(key, key_len, e + 1, e_key_len, ctx); + if (diff2 > 0) { + if (found) { + min_idx = mid_idx + 1; + } else { + if (de_is_last(e)) + return NULL; - if (!diff2) { - *diff = 0; - goto out1; + max_idx = 0; + goto fill_table; } - - if (diff2 < 0) { + } else if (diff2 < 0) { + if (found) max_idx = mid_idx - 1; - fnd = mid_idx; - if (!fnd) - break; - } else { - min_idx = mid_idx + 1; - } - } + else + max_idx--; - if (fnd == -1) { - e = NULL; - goto out1; + found = e; + } else { + *diff = 0; + return e; } - *diff = -1; - e = Add2Ptr(hdr, offs[fnd]); + if (min_idx > max_idx) { + *diff = -1; + return found; + } -out1: - kfree(offs); + mid_idx = (min_idx + max_idx) >> 1; + e = Add2Ptr(hdr, offs[mid_idx]); - return e; + goto binary_search; #endif next: -- cgit v1.2.3 From ef9297007e9904588682699e618c56401f61d1c2 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 2 Sep 2021 18:40:49 +0300 Subject: fs/ntfs3: Make binary search to search smaller chunks in beginning We could try to optimize algorithm to first fill just small table and after that use bigger table all the way up to ARRAY_SIZE(offs). This way we can use bigger search array, but not lose benefits with entry count smaller < ARRAY_SIZE(offs). Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/index.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index a16256ab3e9f..3ad1ee608e53 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "debug.h" #include "ntfs.h" @@ -679,8 +680,9 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx, #ifdef NTFS3_INDEX_BINARY_SEARCH struct NTFS_DE *found = NULL; int min_idx = 0, mid_idx, max_idx = 0; + int table_size = 8; int diff2; - u16 offs[64]; + u16 offs[128]; if (end > 0x10000) goto next; @@ -700,7 +702,7 @@ fill_table: off += e_size; max_idx++; - if (max_idx < ARRAY_SIZE(offs)) + if (max_idx < table_size) goto fill_table; max_idx--; @@ -718,6 +720,7 @@ binary_search: return NULL; max_idx = 0; + table_size = min(table_size * 2, 128); goto fill_table; } } else if (diff2 < 0) { -- cgit v1.2.3 From 8e69212253d320d4768071086b1111e6ab91d9bd Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 2 Sep 2021 18:40:50 +0300 Subject: fs/ntfs3: Always use binary search with entry search We do not have any reason to keep old linear search in. Before this was used for error path or if table was so big that it cannot be allocated. Current binary search implementation won't need error path. Remove old references to linear entry search. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/index.c | 50 ++++++-------------------------------------------- fs/ntfs3/ntfs.h | 3 --- 2 files changed, 6 insertions(+), 47 deletions(-) diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index 3ad1ee608e53..4f71a91f07d9 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -671,22 +671,16 @@ static struct NTFS_DE *hdr_find_e(const struct ntfs_index *indx, const struct INDEX_HDR *hdr, const void *key, size_t key_len, const void *ctx, int *diff) { - struct NTFS_DE *e; + struct NTFS_DE *e, *found = NULL; NTFS_CMP_FUNC cmp = indx->cmp; + int min_idx = 0, mid_idx, max_idx = 0; + int diff2; + int table_size = 8; u32 e_size, e_key_len; u32 end = le32_to_cpu(hdr->used); u32 off = le32_to_cpu(hdr->de_off); - -#ifdef NTFS3_INDEX_BINARY_SEARCH - struct NTFS_DE *found = NULL; - int min_idx = 0, mid_idx, max_idx = 0; - int table_size = 8; - int diff2; u16 offs[128]; - if (end > 0x10000) - goto next; - fill_table: if (off + sizeof(struct NTFS_DE) > end) return NULL; @@ -720,7 +714,8 @@ binary_search: return NULL; max_idx = 0; - table_size = min(table_size * 2, 128); + table_size = min(table_size * 2, + (int)ARRAY_SIZE(offs)); goto fill_table; } } else if (diff2 < 0) { @@ -744,39 +739,6 @@ binary_search: e = Add2Ptr(hdr, offs[mid_idx]); goto binary_search; -#endif - -next: - /* - * Entries index are sorted. - * Enumerate all entries until we find entry - * that is <= to the search value. - */ - if (off + sizeof(struct NTFS_DE) > end) - return NULL; - - e = Add2Ptr(hdr, off); - e_size = le16_to_cpu(e->size); - - if (e_size < sizeof(struct NTFS_DE) || off + e_size > end) - return NULL; - - off += e_size; - - e_key_len = le16_to_cpu(e->key_size); - - *diff = (*cmp)(key, key_len, e + 1, e_key_len, ctx); - if (!*diff) - return e; - - if (*diff <= 0) - return e; - - if (de_is_last(e)) { - *diff = 1; - return e; - } - goto next; } /* diff --git a/fs/ntfs3/ntfs.h b/fs/ntfs3/ntfs.h index 695b684bce20..303a162c3158 100644 --- a/fs/ntfs3/ntfs.h +++ b/fs/ntfs3/ntfs.h @@ -21,9 +21,6 @@ /* TODO: Check 4K MFT record and 512 bytes cluster. */ -/* Activate this define to use binary search in indexes. */ -#define NTFS3_INDEX_BINARY_SEARCH - /* Check each run for marked clusters. */ #define NTFS3_CHECK_FREE_CLST -- cgit v1.2.3 From 7d95995ab4de07ee642c925aa6dbf6d07069a751 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 11:34:38 +0300 Subject: fs/ntfs3: Remove '+' before constant in ni_insert_resident() No need for plus sign here. So remove it. Checkpatch will also be happy. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/frecord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 080264ced909..df41eae8f7e1 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -1448,7 +1448,7 @@ int ni_insert_resident(struct ntfs_inode *ni, u32 data_size, attr->res.flags = RESIDENT_FLAG_INDEXED; /* is_attr_indexed(attr)) == true */ - le16_add_cpu(&ni->mi.mrec->hard_links, +1); + le16_add_cpu(&ni->mi.mrec->hard_links, 1); ni->mi.dirty = true; } attr->res.res = 0; -- cgit v1.2.3 From 4ca7fe57f21a25afc4a651db5145bfe090c6248f Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 11:34:39 +0300 Subject: fs/ntfs3: Place Comparisons constant right side of the test For better code readability place constant always right side of the test. This will also address checkpatch warning. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/frecord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index df41eae8f7e1..2f8af53da219 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -1603,7 +1603,7 @@ struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type, *le = NULL; - if (FILE_NAME_POSIX == name_type) + if (name_type == FILE_NAME_POSIX) return NULL; /* Enumerate all names. */ -- cgit v1.2.3 From 2829e39e0e8add377508b3c6ef4cf48e6db324fb Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 11:34:40 +0300 Subject: fs/ntfs3: Remove braces from single statment block Remove braces from single statment block as they are not needed. Also Linux kernel coding style guide recommend this and checkpatch warn about this. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/frecord.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 2f8af53da219..1e1a09034f65 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -2903,9 +2903,8 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de + 1, de_key_size); mi_get_ref(&ni->mi, &de->ref); - if (indx_insert_entry(&dir_ni->dir, dir_ni, de, sbi, NULL, 1)) { + if (indx_insert_entry(&dir_ni->dir, dir_ni, de, sbi, NULL, 1)) return false; - } } return true; -- cgit v1.2.3 From cffb5152eea82de890dd418a90612aede96068d6 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 11:34:41 +0300 Subject: fs/ntfs3: Remove tabs before spaces from comment Remove tabs before spaces from comment as recommended by kernel coding style. Checkpatch also warn about these. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/lznt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs3/lznt.c b/fs/ntfs3/lznt.c index 12ba42518efe..28f654561f27 100644 --- a/fs/ntfs3/lznt.c +++ b/fs/ntfs3/lznt.c @@ -292,7 +292,7 @@ next: /* * get_lznt_ctx * @level: 0 - Standard compression. - * !0 - Best compression, requires a lot of cpu. + * !0 - Best compression, requires a lot of cpu. */ struct lznt *get_lznt_ctx(int level) { -- cgit v1.2.3 From edb853ff3dc01c22577ea5d0383d067b68a6d663 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 17:28:39 +0300 Subject: fs/ntfs3: Fix ntfs_look_for_free_space() does only report -ENOSPC If ntfs_refresh_zone() returns error it will be changed to -ENOSPC. It is not right. Also caller of this functions also check other errors. Fixes: 78ab59fee07f ("fs/ntfs3: Rework file operations") Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/fsntfs.c | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index 9232a7f410c6..e77fad89eaed 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -357,7 +357,7 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len, enum ALLOCATE_OPT opt) { int err; - CLST alen = 0; + CLST alen; struct super_block *sb = sbi->sb; size_t alcn, zlen, zeroes, zlcn, zlen2, ztrim, new_zlen; struct wnd_bitmap *wnd = &sbi->used.bitmap; @@ -369,13 +369,15 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len, if (!zlen) { err = ntfs_refresh_zone(sbi); if (err) - goto out; + goto up_write; + zlen = wnd_zone_len(wnd); } if (!zlen) { ntfs_err(sbi->sb, "no free space to extend mft"); - goto out; + err = -ENOSPC; + goto up_write; } lcn = wnd_zone_bit(wnd); @@ -384,12 +386,11 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len, wnd_zone_set(wnd, lcn + alen, zlen - alen); err = wnd_set_used(wnd, lcn, alen); - if (err) { - up_write(&wnd->rw_lock); - return err; - } + if (err) + goto up_write; + alcn = lcn; - goto out; + goto space_found; } /* * 'Cause cluster 0 is always used this value means that we should use @@ -403,15 +404,17 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len, alen = wnd_find(wnd, len, lcn, BITMAP_FIND_MARK_AS_USED, &alcn); if (alen) - goto out; + goto space_found; /* Try to use clusters from MftZone. */ zlen = wnd_zone_len(wnd); zeroes = wnd_zeroes(wnd); /* Check too big request */ - if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE) - goto out; + if (len > zeroes + zlen || zlen <= NTFS_MIN_MFT_ZONE) { + err = -ENOSPC; + goto up_write; + } /* How many clusters to cat from zone. */ zlcn = wnd_zone_bit(wnd); @@ -430,22 +433,22 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len, /* Allocate continues clusters. */ alen = wnd_find(wnd, len, 0, BITMAP_FIND_MARK_AS_USED | BITMAP_FIND_FULL, &alcn); - -out: - if (alen) { - err = 0; - *new_len = alen; - *new_lcn = alcn; - - ntfs_unmap_meta(sb, alcn, alen); - - /* Set hint for next requests. */ - if (!(opt & ALLOCATE_MFT)) - sbi->used.next_free_lcn = alcn + alen; - } else { + if (!alen) { err = -ENOSPC; + goto up_write; } +space_found: + err = 0; + *new_len = alen; + *new_lcn = alcn; + + ntfs_unmap_meta(sb, alcn, alen); + + /* Set hint for next requests. */ + if (!(opt & ALLOCATE_MFT)) + sbi->used.next_free_lcn = alcn + alen; +up_write: up_write(&wnd->rw_lock); return err; } -- cgit v1.2.3 From f162f7b8dbc29742896f8a7e678bb31192716ae0 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 17:28:40 +0300 Subject: fs/ntfs3: Remove always false condition check We do not need this check as this is same thing as NTFS_MIN_MFT_ZONE > zlen. We already check NTFS_MIN_MFT_ZONE <= zlen and exit because is too big request. Remove it so code is cleaner. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/fsntfs.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index e77fad89eaed..4cd24e4e58ff 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -422,11 +422,8 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len, ztrim = len > zlen ? zlen : (len > zlen2 ? len : zlen2); new_zlen = zlen - ztrim; - if (new_zlen < NTFS_MIN_MFT_ZONE) { + if (new_zlen < NTFS_MIN_MFT_ZONE) new_zlen = NTFS_MIN_MFT_ZONE; - if (new_zlen > zlen) - new_zlen = zlen; - } wnd_zone_set(wnd, zlcn, new_zlen); -- cgit v1.2.3 From b5322eb1ae94572f5a52e804857e641b846059f4 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 17:28:41 +0300 Subject: fs/ntfs3: Use clamp/max macros instead of comparisons We can make code little more readable by using kernel macros clamp/max. This were found with kernel included Coccinelle minmax script. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/fsntfs.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index 4cd24e4e58ff..c964d3996aab 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "debug.h" #include "ntfs.h" @@ -419,11 +420,8 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len, /* How many clusters to cat from zone. */ zlcn = wnd_zone_bit(wnd); zlen2 = zlen >> 1; - ztrim = len > zlen ? zlen : (len > zlen2 ? len : zlen2); - new_zlen = zlen - ztrim; - - if (new_zlen < NTFS_MIN_MFT_ZONE) - new_zlen = NTFS_MIN_MFT_ZONE; + ztrim = clamp_val(len, zlen2, zlen); + new_zlen = max_t(size_t, zlen - ztrim, NTFS_MIN_MFT_ZONE); wnd_zone_set(wnd, zlcn, new_zlen); -- cgit v1.2.3 From 6e3331ee34461be37f50912295a2e924a673dbc6 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 7 Sep 2021 17:28:42 +0300 Subject: fs/ntfs3: Use min/max macros instated of ternary operators We can make code little bit more readable by using min/max macros. These were found with Coccinelle. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/attrib.c | 3 ++- fs/ntfs3/bitmap.c | 11 ++++++----- fs/ntfs3/fsntfs.c | 6 +++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index 12cff28f3e71..c15cc17e3cd9 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -8,6 +8,7 @@ #include #include +#include #include "debug.h" #include "ntfs.h" @@ -1961,7 +1962,7 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size) return 0; from = vbo; - to = (vbo + bytes) < data_size ? (vbo + bytes) : data_size; + to = min_t(u64, vbo + bytes, data_size); memset(Add2Ptr(resident_data(attr_b), from), 0, to - from); return 0; } diff --git a/fs/ntfs3/bitmap.c b/fs/ntfs3/bitmap.c index a03584674fea..aa184407520f 100644 --- a/fs/ntfs3/bitmap.c +++ b/fs/ntfs3/bitmap.c @@ -12,6 +12,7 @@ #include #include +#include #include "ntfs.h" #include "ntfs_fs.h" @@ -432,7 +433,7 @@ static void wnd_remove_free_ext(struct wnd_bitmap *wnd, size_t bit, size_t len) ; } else { n3 = rb_next(&e->count.node); - max_new_len = len > new_len ? len : new_len; + max_new_len = max(len, new_len); if (!n3) { wnd->extent_max = max_new_len; } else { @@ -728,7 +729,7 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits) wbits = wnd->bits_last; tail = wbits - wbit; - op = tail < bits ? tail : bits; + op = min_t(u32, tail, bits); bh = wnd_map(wnd, iw); if (IS_ERR(bh)) { @@ -781,7 +782,7 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits) wbits = wnd->bits_last; tail = wbits - wbit; - op = tail < bits ? tail : bits; + op = min_t(u32, tail, bits); bh = wnd_map(wnd, iw); if (IS_ERR(bh)) { @@ -831,7 +832,7 @@ static bool wnd_is_free_hlp(struct wnd_bitmap *wnd, size_t bit, size_t bits) wbits = wnd->bits_last; tail = wbits - wbit; - op = tail < bits ? tail : bits; + op = min_t(u32, tail, bits); if (wbits != wnd->free_bits[iw]) { bool ret; @@ -923,7 +924,7 @@ use_wnd: wbits = wnd->bits_last; tail = wbits - wbit; - op = tail < bits ? tail : bits; + op = min_t(u32, tail, bits); if (wnd->free_bits[iw]) { bool ret; diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index c964d3996aab..77d2e56d5b4f 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -382,7 +382,7 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len, } lcn = wnd_zone_bit(wnd); - alen = zlen > len ? len : zlen; + alen = min_t(CLST, len, zlen); wnd_zone_set(wnd, lcn + alen, zlen - alen); @@ -1096,7 +1096,7 @@ int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run, len = ((u64)clen << cluster_bits) - off; for (;;) { - u32 op = len < bytes ? len : bytes; + u32 op = min_t(u64, len, bytes); int err = ntfs_sb_write(sb, lbo, op, buf, 0); if (err) @@ -1297,7 +1297,7 @@ int ntfs_get_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo, nb->off = off = lbo & (blocksize - 1); for (;;) { - u32 len32 = len < bytes ? len : bytes; + u32 len32 = min_t(u64, len, bytes); sector_t block = lbo >> sb->s_blocksize_bits; do { -- cgit v1.2.3 From 0412016e48076f5f9dbdcc6613436e3c6db89523 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 9 Sep 2021 21:09:32 +0300 Subject: fs/ntfs3: Fix wrong error message $Logfile -> $UpCase Fix wrong error message $Logfile -> $UpCase. Probably copy paste. Fixes: 203c2b3a406a ("fs/ntfs3: Add initialization of super block") Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index acfa00acf4dd..1e01184f4ee2 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -1201,7 +1201,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) inode = ntfs_iget5(sb, &ref, &NAME_UPCASE); if (IS_ERR(inode)) { err = PTR_ERR(inode); - ntfs_err(sb, "Failed to load \x24LogFile."); + ntfs_err(sb, "Failed to load $UpCase."); inode = NULL; goto out; } -- cgit v1.2.3 From 7ea04817866a5ac369f1a33d1b86d06a695aaedb Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 9 Sep 2021 21:09:33 +0300 Subject: fs/ntfs3: Change EINVAL to ENOMEM when d_make_root fails Change EINVAL to ENOMEM when d_make_root fails because that is right errno. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 1e01184f4ee2..642bd63932d0 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -1284,7 +1284,7 @@ load_root: sb->s_root = d_make_root(inode); if (!sb->s_root) { - err = -EINVAL; + err = -ENOMEM; goto out; } -- cgit v1.2.3 From 5d7d6b16bc1dbe0f84997e639c49b5ed98a562f7 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 9 Sep 2021 21:09:34 +0300 Subject: fs/ntfs3: Remove impossible fault condition in fill_super Remove root drop when we fault out. This can never happened because when we allocate root we eather fault when no root or success. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 642bd63932d0..ad185c723c0e 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -1295,12 +1295,6 @@ load_root: out: iput(inode); - - if (sb->s_root) { - d_drop(sb->s_root); - sb->s_root = NULL; - } - return err; } -- cgit v1.2.3 From bce1828f6d82ad0ffa3b7259d6f1769ffbcec30c Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 9 Sep 2021 21:09:35 +0300 Subject: fs/ntfs3: Return straight without goto in fill_super In many places it is not needed to use goto out. We can just return right away. This will make code little bit more cleaner as we won't need to check error path. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 56 ++++++++++++++++---------------------------------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index ad185c723c0e..31a9a0d16261 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -921,7 +921,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) err = ntfs_init_from_boot(sb, rq ? queue_logical_block_size(rq) : 512, bd_inode->i_size); if (err) - goto out; + return err; #ifdef CONFIG_NTFS3_64BIT_CLUSTER sb->s_maxbytes = MAX_LFS_FILESIZE; @@ -937,10 +937,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_VOL); inode = ntfs_iget5(sb, &ref, &NAME_VOLUME); if (IS_ERR(inode)) { - err = PTR_ERR(inode); ntfs_err(sb, "Failed to load $Volume."); - inode = NULL; - goto out; + return PTR_ERR(inode); } ni = ntfs_i(inode); @@ -988,10 +986,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_MIRR); inode = ntfs_iget5(sb, &ref, &NAME_MIRROR); if (IS_ERR(inode)) { - err = PTR_ERR(inode); ntfs_err(sb, "Failed to load $MFTMirr."); - inode = NULL; - goto out; + return PTR_ERR(inode); } sbi->mft.recs_mirr = @@ -1004,10 +1000,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_LOG); inode = ntfs_iget5(sb, &ref, &NAME_LOGFILE); if (IS_ERR(inode)) { - err = PTR_ERR(inode); ntfs_err(sb, "Failed to load \x24LogFile."); - inode = NULL; - goto out; + return PTR_ERR(inode); } ni = ntfs_i(inode); @@ -1025,16 +1019,14 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) if (!is_ro) { ntfs_warn(sb, "failed to replay log file. Can't mount rw!"); - err = -EINVAL; - goto out; + return -EINVAL; } } else if (sbi->volume.flags & VOLUME_FLAG_DIRTY) { if (!is_ro && !sbi->options->force) { ntfs_warn( sb, "volume is dirty and \"force\" flag is not set!"); - err = -EINVAL; - goto out; + return -EINVAL; } } @@ -1044,10 +1036,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) inode = ntfs_iget5(sb, &ref, &NAME_MFT); if (IS_ERR(inode)) { - err = PTR_ERR(inode); ntfs_err(sb, "Failed to load $MFT."); - inode = NULL; - goto out; + return PTR_ERR(inode); } ni = ntfs_i(inode); @@ -1071,10 +1061,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_BADCLUST); inode = ntfs_iget5(sb, &ref, &NAME_BADCLUS); if (IS_ERR(inode)) { - err = PTR_ERR(inode); ntfs_err(sb, "Failed to load $BadClus."); - inode = NULL; - goto out; + return PTR_ERR(inode); } ni = ntfs_i(inode); @@ -1096,10 +1084,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_BITMAP); inode = ntfs_iget5(sb, &ref, &NAME_BITMAP); if (IS_ERR(inode)) { - err = PTR_ERR(inode); ntfs_err(sb, "Failed to load $Bitmap."); - inode = NULL; - goto out; + return PTR_ERR(inode); } ni = ntfs_i(inode); @@ -1129,17 +1115,15 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) /* Compute the MFT zone. */ err = ntfs_refresh_zone(sbi); if (err) - goto out; + return err; /* Load $AttrDef. */ ref.low = cpu_to_le32(MFT_REC_ATTR); ref.seq = cpu_to_le16(MFT_REC_ATTR); inode = ntfs_iget5(sbi->sb, &ref, &NAME_ATTRDEF); if (IS_ERR(inode)) { - err = PTR_ERR(inode); ntfs_err(sb, "Failed to load $AttrDef -> %d", err); - inode = NULL; - goto out; + return PTR_ERR(inode); } if (inode->i_size < sizeof(struct ATTR_DEF_ENTRY)) { @@ -1200,10 +1184,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.seq = cpu_to_le16(MFT_REC_UPCASE); inode = ntfs_iget5(sb, &ref, &NAME_UPCASE); if (IS_ERR(inode)) { - err = PTR_ERR(inode); ntfs_err(sb, "Failed to load $UpCase."); - inode = NULL; - goto out; + return PTR_ERR(inode); } ni = ntfs_i(inode); @@ -1249,7 +1231,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) /* Load $Secure. */ err = ntfs_security_init(sbi); if (err) - goto out; + return err; /* Load $Extend. */ err = ntfs_extend_init(sbi); @@ -1273,26 +1255,20 @@ load_root: ref.seq = cpu_to_le16(MFT_REC_ROOT); inode = ntfs_iget5(sb, &ref, &NAME_ROOT); if (IS_ERR(inode)) { - err = PTR_ERR(inode); ntfs_err(sb, "Failed to load root."); - inode = NULL; - goto out; + return PTR_ERR(inode); } ni = ntfs_i(inode); sb->s_root = d_make_root(inode); - - if (!sb->s_root) { - err = -ENOMEM; - goto out; - } + if (!sb->s_root) + return -ENOMEM; fc->fs_private = NULL; fc->s_fs_info = NULL; return 0; - out: iput(inode); return err; -- cgit v1.2.3 From 10b4f12c7028399007aaebc25810b18d8f7731a7 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 9 Sep 2021 21:09:36 +0300 Subject: fs/ntfs3: Remove unnecessary variable loading in fill_super Remove some unnecessary variable loading. These look like copy paste work and they are not used to anything. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 31a9a0d16261..4ff61534682c 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -877,7 +877,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) struct block_device *bdev = sb->s_bdev; struct inode *bd_inode = bdev->bd_inode; struct request_queue *rq = bdev_get_queue(bdev); - struct inode *inode = NULL; + struct inode *inode; struct ntfs_inode *ni; size_t i, tt; CLST vcn, lcn, len; @@ -977,9 +977,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) sbi->volume.major_ver = info->major_ver; sbi->volume.minor_ver = info->minor_ver; sbi->volume.flags = info->flags; - sbi->volume.ni = ni; - inode = NULL; /* Load $MFTMirr to estimate recs_mirr. */ ref.low = cpu_to_le32(MFT_REC_MIRR); @@ -1011,7 +1009,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) goto out; iput(inode); - inode = NULL; is_ro = sb_rdonly(sbi->sb); @@ -1088,8 +1085,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) return PTR_ERR(inode); } - ni = ntfs_i(inode); - #ifndef CONFIG_NTFS3_64BIT_CLUSTER if (inode->i_size >> 32) { err = -EINVAL; @@ -1188,8 +1183,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) return PTR_ERR(inode); } - ni = ntfs_i(inode); - if (inode->i_size != 0x10000 * sizeof(short)) { err = -EINVAL; goto out; @@ -1225,7 +1218,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) } iput(inode); - inode = NULL; if (is_ntfs3(sbi)) { /* Load $Secure. */ @@ -1259,8 +1251,6 @@ load_root: return PTR_ERR(inode); } - ni = ntfs_i(inode); - sb->s_root = d_make_root(inode); if (!sb->s_root) return -ENOMEM; -- cgit v1.2.3 From b4f110d65e21bf937fc5d3d894ec1cd540c85a71 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 9 Sep 2021 21:09:37 +0300 Subject: fs/ntfs3: Use sb instead of sbi->sb in fill_super Use sb instead of sbi->sb in fill_super. We have sb so why not use it. Also makes code more readable. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 4ff61534682c..c18705bf857f 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -1010,7 +1010,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) iput(inode); - is_ro = sb_rdonly(sbi->sb); + is_ro = sb_rdonly(sb); if (sbi->flags & NTFS_FLAGS_NEED_REPLAY) { if (!is_ro) { @@ -1101,7 +1101,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) /* Not necessary. */ sbi->used.bitmap.set_tail = true; - err = wnd_init(&sbi->used.bitmap, sbi->sb, tt); + err = wnd_init(&sbi->used.bitmap, sb, tt); if (err) goto out; @@ -1115,7 +1115,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) /* Load $AttrDef. */ ref.low = cpu_to_le32(MFT_REC_ATTR); ref.seq = cpu_to_le16(MFT_REC_ATTR); - inode = ntfs_iget5(sbi->sb, &ref, &NAME_ATTRDEF); + inode = ntfs_iget5(sb, &ref, &NAME_ATTRDEF); if (IS_ERR(inode)) { ntfs_err(sb, "Failed to load $AttrDef -> %d", err); return PTR_ERR(inode); -- cgit v1.2.3 From 0cde7e81cd448a5df01a3960f6608b15dc3f12a3 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 9 Sep 2021 21:09:38 +0300 Subject: fs/ntfs3: Remove tmp var is_ro in ntfs_fill_super We only use this in two places so we do not really need it. Also wrapper sb_rdonly() is pretty self explanatory. This will make little bit easier to read this super long variable list in the beginning of ntfs_fill_super(). Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index c18705bf857f..93b8a1f4d748 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -887,7 +887,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) struct ATTR_DEF_ENTRY *t; u16 *upcase; u16 *shared; - bool is_ro; struct MFT_REF ref; ref.high = 0; @@ -1010,16 +1009,14 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) iput(inode); - is_ro = sb_rdonly(sb); - if (sbi->flags & NTFS_FLAGS_NEED_REPLAY) { - if (!is_ro) { + if (!sb_rdonly(sb)) { ntfs_warn(sb, "failed to replay log file. Can't mount rw!"); return -EINVAL; } } else if (sbi->volume.flags & VOLUME_FLAG_DIRTY) { - if (!is_ro && !sbi->options->force) { + if (!sb_rdonly(sb) && !sbi->options->force) { ntfs_warn( sb, "volume is dirty and \"force\" flag is not set!"); -- cgit v1.2.3 From 4ea41b3eb5fd51b47742c6fa2ac1851a51ab0c69 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 9 Sep 2021 21:09:39 +0300 Subject: fs/ntfs3: Remove tmp pointer bd_inode in fill_super Drop tmp pointer bd_inode because this is only used ones in fill_super. Also we have so many initializing happening at the beginning that it is already way too much to follow. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 93b8a1f4d748..e5ec808bd052 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -875,7 +875,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) int err; struct ntfs_sb_info *sbi = sb->s_fs_info; struct block_device *bdev = sb->s_bdev; - struct inode *bd_inode = bdev->bd_inode; struct request_queue *rq = bdev_get_queue(bdev); struct inode *inode; struct ntfs_inode *ni; @@ -918,7 +917,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) /* Parse boot. */ err = ntfs_init_from_boot(sb, rq ? queue_logical_block_size(rq) : 512, - bd_inode->i_size); + bdev->bd_inode->i_size); if (err) return err; -- cgit v1.2.3 From 0056b273757b3057a5aff73f96a7fa134641caf4 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 9 Sep 2021 21:09:40 +0300 Subject: fs/ntfs3: Remove tmp pointer upcase in fill_super We can survive without this tmp point upcase. So remove it we don't have so many tmp pointer in this function. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index e5ec808bd052..8ce0d4f439a1 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -884,7 +884,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) const struct VOLUME_INFO *info; u32 idx, done, bytes; struct ATTR_DEF_ENTRY *t; - u16 *upcase; u16 *shared; struct MFT_REF ref; @@ -1184,11 +1183,9 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) goto out; } - upcase = sbi->upcase; - for (idx = 0; idx < (0x10000 * sizeof(short) >> PAGE_SHIFT); idx++) { const __le16 *src; - u16 *dst = Add2Ptr(upcase, idx << PAGE_SHIFT); + u16 *dst = Add2Ptr(sbi->upcase, idx << PAGE_SHIFT); struct page *page = ntfs_map_page(inode->i_mapping, idx); if (IS_ERR(page)) { @@ -1207,10 +1204,10 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ntfs_unmap_page(page); } - shared = ntfs_set_shared(upcase, 0x10000 * sizeof(short)); - if (shared && upcase != shared) { + shared = ntfs_set_shared(sbi->upcase, 0x10000 * sizeof(short)); + if (shared && sbi->upcase != shared) { + kvfree(sbi->upcase); sbi->upcase = shared; - kvfree(upcase); } iput(inode); -- cgit v1.2.3 From 0e59a87ee619915c2eb189eb232a972c276681fb Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 9 Sep 2021 21:09:41 +0300 Subject: fs/ntfs3: Initialize pointer before use place in fill_super Initializing should be as close as possible when we use it so that we do not need to scroll up to see what is happening. Also bdev_get_queue() can never return NULL so we do not need to check for !rq. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 8ce0d4f439a1..3d034eac2bd1 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -875,7 +875,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) int err; struct ntfs_sb_info *sbi = sb->s_fs_info; struct block_device *bdev = sb->s_bdev; - struct request_queue *rq = bdev_get_queue(bdev); + struct request_queue *rq; struct inode *inode; struct ntfs_inode *ni; size_t i, tt; @@ -904,9 +904,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) return -EINVAL; } - if (!rq || !blk_queue_discard(rq) || !rq->limits.discard_granularity) { - ; - } else { + rq = bdev_get_queue(bdev); + if (blk_queue_discard(rq) && rq->limits.discard_granularity) { sbi->discard_granularity = rq->limits.discard_granularity; sbi->discard_granularity_mask_inv = ~(u64)(sbi->discard_granularity - 1); -- cgit v1.2.3 From 28861e3bbd9e7ac4cd9c811aad71b4d116e27930 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Thu, 9 Sep 2021 21:09:42 +0300 Subject: fs/ntfs3: Initiliaze sb blocksize only in one place + refactor Right now sb blocksize first get initiliazed in fill_super but in can be changed in helper function. It makes more sense to that this happened only in one place. Because we move this to helper function it makes more sense that s_maxbytes will also be there. I rather have every sb releted thing in fill_super, but because there is already sb releted stuff in this helper. This will have to do for now. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 3d034eac2bd1..cefb9ddaf4db 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -840,8 +840,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, rec->total = cpu_to_le32(sbi->record_size); ((struct ATTRIB *)Add2Ptr(rec, ao))->type = ATTR_END; - if (sbi->cluster_size < PAGE_SIZE) - sb_set_blocksize(sb, sbi->cluster_size); + sb_set_blocksize(sb, min_t(u32, sbi->cluster_size, PAGE_SIZE)); sbi->block_mask = sb->s_blocksize - 1; sbi->blocks_per_cluster = sbi->cluster_size >> sb->s_blocksize_bits; @@ -854,9 +853,11 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, if (clusters >= (1ull << (64 - sbi->cluster_bits))) sbi->maxbytes = -1; sbi->maxbytes_sparse = -1; + sb->s_maxbytes = MAX_LFS_FILESIZE; #else /* Maximum size for sparse file. */ sbi->maxbytes_sparse = (1ull << (sbi->cluster_bits + 32)) - 1; + sb->s_maxbytes = 0xFFFFFFFFull << sbi->cluster_bits; #endif err = 0; @@ -911,20 +912,12 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ~(u64)(sbi->discard_granularity - 1); } - sb_set_blocksize(sb, PAGE_SIZE); - /* Parse boot. */ err = ntfs_init_from_boot(sb, rq ? queue_logical_block_size(rq) : 512, bdev->bd_inode->i_size); if (err) return err; -#ifdef CONFIG_NTFS3_64BIT_CLUSTER - sb->s_maxbytes = MAX_LFS_FILESIZE; -#else - sb->s_maxbytes = 0xFFFFFFFFull << sbi->cluster_bits; -#endif - /* * Load $Volume. This should be done before $LogFile * 'cause 'sbi->volume.ni' is used 'ntfs_set_state'. -- cgit v1.2.3 From a0fc05a37cae9e61aa29f7e283662ce70f7df342 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Fri, 10 Sep 2021 00:57:53 +0300 Subject: Doc/fs/ntfs3: Fix rst format and make it cleaner Current ntfs3 rst documentation is broken. I turn table to list table as this is current Linux documentation quide line. Simple table also did not quite work in our situation as we need to span rows together. It still look quite good as text so we did not loss anything. This will also make diffing quite bit more pleasure. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- Documentation/filesystems/ntfs3.rst | 139 ++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 63 deletions(-) diff --git a/Documentation/filesystems/ntfs3.rst b/Documentation/filesystems/ntfs3.rst index 7b6afe452197..d67ccd22c63b 100644 --- a/Documentation/filesystems/ntfs3.rst +++ b/Documentation/filesystems/ntfs3.rst @@ -4,99 +4,112 @@ NTFS3 ===== - Summary and Features ==================== -NTFS3 is fully functional NTFS Read-Write driver. The driver works with -NTFS versions up to 3.1, normal/compressed/sparse files -and journal replaying. File system type to use on mount is 'ntfs3'. +NTFS3 is fully functional NTFS Read-Write driver. The driver works with NTFS +versions up to 3.1. File system type to use on mount is *ntfs3*. - This driver implements NTFS read/write support for normal, sparse and compressed files. -- Supports native journal replaying; -- Supports extended attributes - Predefined extended attributes: - - 'system.ntfs_security' gets/sets security - descriptor (SECURITY_DESCRIPTOR_RELATIVE) - - 'system.ntfs_attrib' gets/sets ntfs file/dir attributes. - Note: applied to empty files, this allows to switch type between - sparse(0x200), compressed(0x800) and normal; +- Supports native journal replaying. - Supports NFS export of mounted NTFS volumes. +- Supports extended attributes. Predefined extended attributes: + + - *system.ntfs_security* gets/sets security + + Descriptor: SECURITY_DESCRIPTOR_RELATIVE + + - *system.ntfs_attrib* gets/sets ntfs file/dir attributes. + + Note: Applied to empty files, this allows to switch type between + sparse(0x200), compressed(0x800) and normal. Mount Options ============= The list below describes mount options supported by NTFS3 driver in addition to -generic ones. +generic ones. You can use every mount option with **no** option. If it is in +this table marked with no it means default is without **no**. -=============================================================================== +.. flat-table:: + :widths: 1 5 + :fill-cells: -iocharset=name This option informs the driver how to interpret path - strings and translate them to Unicode and back. If - this option is not set, the default codepage will be - used (CONFIG_NLS_DEFAULT). - Examples: - 'iocharset=utf8' + * - iocharset=name + - This option informs the driver how to interpret path strings and + translate them to Unicode and back. If this option is not set, the + default codepage will be used (CONFIG_NLS_DEFAULT). -uid= -gid= -umask= Controls the default permissions for files/directories created - after the NTFS volume is mounted. + Example: iocharset=utf8 -fmask= -dmask= Instead of specifying umask which applies both to - files and directories, fmask applies only to files and - dmask only to directories. + * - uid= + - :rspan:`1` + * - gid= -nohidden Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN) - attribute will not be shown under Linux. + * - umask= + - Controls the default permissions for files/directories created after + the NTFS volume is mounted. -sys_immutable Files with the Windows-specific SYSTEM - (FILE_ATTRIBUTE_SYSTEM) attribute will be marked as system - immutable files. + * - dmask= + - :rspan:`1` Instead of specifying umask which applies both to files and + directories, fmask applies only to files and dmask only to directories. + * - fmask= -discard Enable support of the TRIM command for improved performance - on delete operations, which is recommended for use with the - solid-state drives (SSD). + * - noacsrules + - "No access rules" mount option sets access rights for files/folders to + 777 and owner/group to root. This mount option absorbs all other + permissions. -force Forces the driver to mount partitions even if 'dirty' flag - (volume dirty) is set. Not recommended for use. + - Permissions change for files/folders will be reported as successful, + but they will remain 777. -sparse Create new files as "sparse". + - Owner/group change will be reported as successful, butthey will stay + as root. -showmeta Use this parameter to show all meta-files (System Files) on - a mounted NTFS partition. - By default, all meta-files are hidden. + * - nohidden + - Files with the Windows-specific HIDDEN (FILE_ATTRIBUTE_HIDDEN) attribute + will not be shown under Linux. -prealloc Preallocate space for files excessively when file size is - increasing on writes. Decreases fragmentation in case of - parallel write operations to different files. + * - sys_immutable + - Files with the Windows-specific SYSTEM (FILE_ATTRIBUTE_SYSTEM) attribute + will be marked as system immutable files. -noacsrules "No access rules" mount option sets access rights for - files/folders to 777 and owner/group to root. This mount - option absorbs all other permissions: - - permissions change for files/folders will be reported - as successful, but they will remain 777; - - owner/group change will be reported as successful, but - they will stay as root + * - discard + - Enable support of the TRIM command for improved performance on delete + operations, which is recommended for use with the solid-state drives + (SSD). -acl Support POSIX ACLs (Access Control Lists). Effective if - supported by Kernel. Not to be confused with NTFS ACLs. - The option specified as acl enables support for POSIX ACLs. + * - force + - Forces the driver to mount partitions even if volume is marked dirty. + Not recommended for use. -=============================================================================== + * - sparse + - Create new files as sparse. -ToDo list -========= + * - showmeta + - Use this parameter to show all meta-files (System Files) on a mounted + NTFS partition. By default, all meta-files are hidden. -- Full journaling support (currently journal replaying is supported) over JBD. + * - prealloc + - Preallocate space for files excessively when file size is increasing on + writes. Decreases fragmentation in case of parallel write operations to + different files. + * - acl + - Support POSIX ACLs (Access Control Lists). Effective if supported by + Kernel. Not to be confused with NTFS ACLs. The option specified as acl + enables support for POSIX ACLs. + +Todo list +========= +- Full journaling support over JBD. Currently journal replaying is supported + which is not necessarily as effectice as JBD would be. References ========== -https://www.paragon-software.com/home/ntfs-linux-professional/ - - Commercial version of the NTFS driver for Linux. +- Commercial version of the NTFS driver for Linux. + https://www.paragon-software.com/home/ntfs-linux-professional/ -almaz.alexandrovich@paragon-software.com - - Direct e-mail address for feedback and requests on the NTFS3 implementation. +- Direct e-mail address for feedback and requests on the NTFS3 implementation. + almaz.alexandrovich@paragon-software.com -- cgit v1.2.3 From 880301bb313295a65523e79bc5666f5cf49eb3ed Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 10 Sep 2021 11:02:02 +0100 Subject: fs/ntfs3: Fix a memory leak on object opts Currently a failed allocation on sbi->upcase will cause an exit via the label free_sbi causing a memory leak on object opts. Fix this by re-ordering the exit paths free_opts and free_sbi so that kfree's occur in the reverse allocation order. Addresses-Coverity: ("Resource leak") Fixes: 27fac77707a1 ("fs/ntfs3: Init spi more in init_fs_context than fill_super") Signed-off-by: Colin Ian King Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index cefb9ddaf4db..6a535b144ff9 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -1393,10 +1393,10 @@ ok: fc->ops = &ntfs_context_ops; return 0; -free_opts: - kfree(opts); free_sbi: kfree(sbi); +free_opts: + kfree(opts); return -ENOMEM; } -- cgit v1.2.3 From ee9d4810aab95208541d2807f9d114f1d5edcee0 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Wed, 8 Sep 2021 18:39:53 +0300 Subject: fs/ntfs3: Fix insertion of attr in ni_ins_attr_ext Do not try to insert attribute if there is no room in record. Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/frecord.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 1e1a09034f65..0d00b2301a2f 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -953,6 +953,13 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le, continue; } + /* + * Do not try to insert this attribute + * if there is no room in record. + */ + if (le32_to_cpu(mi->mrec->used) + asize > sbi->record_size) + continue; + /* Try to insert attribute into this subrecord. */ attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize, name_off, svcn, ins_le); -- cgit v1.2.3 From 56eaeb10e2619081cc383febf6740a4c3e806777 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Thu, 9 Sep 2021 13:12:41 +0300 Subject: fs/ntfs3: Change max hardlinks limit to 4000 xfstest generic/041 works with 3003 hardlinks. Because of this we raise hardlinks limit to 4000. There are no drawbacks or regressions. Theoretically we can raise all the way up to ffff, but there is no practical use for this. Signed-off-by: Konstantin Komarov --- fs/ntfs3/ntfs.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/ntfs3/ntfs.h b/fs/ntfs3/ntfs.h index 303a162c3158..9cc396b117bf 100644 --- a/fs/ntfs3/ntfs.h +++ b/fs/ntfs3/ntfs.h @@ -26,9 +26,11 @@ #define NTFS_NAME_LEN 255 -/* ntfs.sys used 500 maximum links on-disk struct allows up to 0xffff. */ -#define NTFS_LINK_MAX 0x400 -//#define NTFS_LINK_MAX 0xffff +/* + * ntfs.sys used 500 maximum links on-disk struct allows up to 0xffff. + * xfstest generic/041 creates 3003 hardlinks. + */ +#define NTFS_LINK_MAX 4000 /* * Activate to use 64 bit clusters instead of 32 bits in ntfs.sys. -- cgit v1.2.3 From 6354467245ff8dd04b54e39790f2ee4d21d5419e Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Thu, 9 Sep 2021 13:15:20 +0300 Subject: fs/ntfs3: Add sync flag to ntfs_sb_write_run and al_update This allows to wait only when it's requested. It speeds up creation of hardlinks. Signed-off-by: Konstantin Komarov --- fs/ntfs3/attrib.c | 2 +- fs/ntfs3/attrlist.c | 6 +++--- fs/ntfs3/frecord.c | 2 +- fs/ntfs3/fslog.c | 8 ++++---- fs/ntfs3/fsntfs.c | 8 ++++---- fs/ntfs3/inode.c | 2 +- fs/ntfs3/ntfs_fs.h | 4 ++-- fs/ntfs3/xattr.c | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index c15cc17e3cd9..8a00fa978f5f 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -287,7 +287,7 @@ int attr_make_nonresident(struct ntfs_inode *ni, struct ATTRIB *attr, if (!rsize) { /* Empty resident -> Non empty nonresident. */ } else if (!is_data) { - err = ntfs_sb_write_run(sbi, run, 0, data, rsize); + err = ntfs_sb_write_run(sbi, run, 0, data, rsize, 0); if (err) goto out2; } else if (!page) { diff --git a/fs/ntfs3/attrlist.c b/fs/ntfs3/attrlist.c index b9da527b96aa..bad6d8a849a2 100644 --- a/fs/ntfs3/attrlist.c +++ b/fs/ntfs3/attrlist.c @@ -333,7 +333,7 @@ int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name, if (attr && attr->non_res) { err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le, - al->size); + al->size, 0); if (err) return err; al->dirty = false; @@ -420,7 +420,7 @@ next: return true; } -int al_update(struct ntfs_inode *ni) +int al_update(struct ntfs_inode *ni, int sync) { int err; struct ATTRIB *attr; @@ -442,7 +442,7 @@ int al_update(struct ntfs_inode *ni) memcpy(resident_data(attr), al->le, al->size); } else { err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le, - al->size); + al->size, sync); if (err) goto out; diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 0d00b2301a2f..9a53f809576d 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -3208,7 +3208,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint) goto out; } - err = al_update(ni); + err = al_update(ni, sync); if (err) goto out; } diff --git a/fs/ntfs3/fslog.c b/fs/ntfs3/fslog.c index 6e7f9b72792b..06492f088d60 100644 --- a/fs/ntfs3/fslog.c +++ b/fs/ntfs3/fslog.c @@ -2215,7 +2215,7 @@ file_is_valid: err = ntfs_sb_write_run(log->ni->mi.sbi, &log->ni->file.run, off, page, - log->page_size); + log->page_size, 0); if (err) goto out; @@ -3706,7 +3706,7 @@ move_data: if (a_dirty) { attr = oa->attr; - err = ntfs_sb_write_run(sbi, oa->run1, vbo, buffer_le, bytes); + err = ntfs_sb_write_run(sbi, oa->run1, vbo, buffer_le, bytes, 0); if (err) goto out; } @@ -5148,10 +5148,10 @@ end_reply: ntfs_fix_pre_write(&rh->rhdr, log->page_size); - err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rh, log->page_size); + err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rh, log->page_size, 0); if (!err) err = ntfs_sb_write_run(sbi, &log->ni->file.run, log->page_size, - rh, log->page_size); + rh, log->page_size, 0); kfree(rh); if (err) diff --git a/fs/ntfs3/fsntfs.c b/fs/ntfs3/fsntfs.c index 77d2e56d5b4f..4de9acb16968 100644 --- a/fs/ntfs3/fsntfs.c +++ b/fs/ntfs3/fsntfs.c @@ -1077,7 +1077,7 @@ int ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes, } int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run, - u64 vbo, const void *buf, size_t bytes) + u64 vbo, const void *buf, size_t bytes, int sync) { struct super_block *sb = sbi->sb; u8 cluster_bits = sbi->cluster_bits; @@ -1097,7 +1097,7 @@ int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run, for (;;) { u32 op = min_t(u64, len, bytes); - int err = ntfs_sb_write(sb, lbo, op, buf, 0); + int err = ntfs_sb_write(sb, lbo, op, buf, sync); if (err) return err; @@ -2172,7 +2172,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi, /* Write main SDS bucket. */ err = ntfs_sb_write_run(sbi, &ni->file.run, sbi->security.next_off, - d_security, aligned_sec_size); + d_security, aligned_sec_size, 0); if (err) goto out; @@ -2190,7 +2190,7 @@ int ntfs_insert_security(struct ntfs_sb_info *sbi, /* Write copy SDS bucket. */ err = ntfs_sb_write_run(sbi, &ni->file.run, mirr_off, d_security, - aligned_sec_size); + aligned_sec_size, 0); if (err) goto out; diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 33f278a0947c..d583b71bec50 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -1584,7 +1584,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns, /* Write non resident data. */ if (nsize) { - err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp, nsize); + err = ntfs_sb_write_run(sbi, &ni->file.run, 0, rp, nsize, 0); if (err) goto out7; } diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index dae6dd4ac619..6731b5d9e2d8 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -465,7 +465,7 @@ bool al_remove_le(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le); bool al_delete_le(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST vcn, const __le16 *name, size_t name_len, const struct MFT_REF *ref); -int al_update(struct ntfs_inode *ni); +int al_update(struct ntfs_inode *ni, int sync); static inline size_t al_aligned(size_t size) { return (size + 1023) & ~(size_t)1023; @@ -606,7 +606,7 @@ int ntfs_sb_read(struct super_block *sb, u64 lbo, size_t bytes, void *buffer); int ntfs_sb_write(struct super_block *sb, u64 lbo, size_t bytes, const void *buffer, int wait); int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run, - u64 vbo, const void *buf, size_t bytes); + u64 vbo, const void *buf, size_t bytes, int sync); struct buffer_head *ntfs_bread_run(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo); int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run, diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index a8c5a899f0dd..5c7c5c7a5ec1 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -441,7 +441,7 @@ update_ea: /* Delete xattr, ATTR_EA */ ni_remove_attr_le(ni, attr, mi, le); } else if (attr->non_res) { - err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size); + err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size, 0); if (err) goto out; } else { -- cgit v1.2.3 From d2846bf33c1423ff872c7a7c2afde292ad502c04 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 18 Sep 2021 21:56:19 +0200 Subject: fs/ntfs3: Remove a useless test in 'indx_find()' 'fnd' has been dereferenced several time before, so testing it here is pointless. Moreover, all callers of 'indx_find()' already have some error handling code that makes sure that no NULL 'fnd' is passed. So, remove the useless test. Signed-off-by: Christophe JAILLET Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/index.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/ntfs3/index.c b/fs/ntfs3/index.c index 4f71a91f07d9..6f81e3a49abf 100644 --- a/fs/ntfs3/index.c +++ b/fs/ntfs3/index.c @@ -1072,9 +1072,7 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni, if (!e) return -EINVAL; - if (fnd) - fnd->root_de = e; - + fnd->root_de = e; err = 0; for (;;) { -- cgit v1.2.3 From 808bc0a82bcd2cbe32a139613325b1a3e03f35f1 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 18 Sep 2021 21:56:28 +0200 Subject: fs/ntfs3: Remove a useless shadowing variable There is already a 'u8 mask' defined at the top of the function. There is no need to define a new one here. Remove the useless and shadowing new 'mask' variable. Signed-off-by: Christophe JAILLET Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/bitfunc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/ntfs3/bitfunc.c b/fs/ntfs3/bitfunc.c index bf10e2da5c6e..50d838093790 100644 --- a/fs/ntfs3/bitfunc.c +++ b/fs/ntfs3/bitfunc.c @@ -119,8 +119,7 @@ bool are_bits_set(const ulong *lmap, size_t bit, size_t nbits) pos = nbits & 7; if (pos) { - u8 mask = fill_mask[pos]; - + mask = fill_mask[pos]; if ((*map & mask) != mask) return false; } -- cgit v1.2.3 From 82cb875313188ccbd3ac174b471c86dcb97b8626 Mon Sep 17 00:00:00 2001 From: Kari Argillander Date: Tue, 21 Sep 2021 20:19:01 +0300 Subject: fs/ntfs3: Remove deprecated mount options nls Some discussion has been spoken that this deprecated mount options should be removed before 5.15 lands. This driver is not never seen day light so it was decided that nls mount option has to be removed. We have always possibility to add this if needed. One possible need is example if current ntfs driver will be taken out of kernel and ntfs3 needs to support mount options what it has. Signed-off-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 6a535b144ff9..800897777eb0 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -246,10 +246,6 @@ static const struct fs_parameter_spec ntfs_fs_parameters[] = { fsparam_flag_no("prealloc", Opt_prealloc), fsparam_flag_no("acsrules", Opt_noacsrules), fsparam_string("iocharset", Opt_iocharset), - - __fsparam(fs_param_is_string, - "nls", Opt_iocharset, - fs_param_deprecated, NULL), {} }; -- cgit v1.2.3 From 6c1ee4d304983d2f68bf7639d5912f781398d5ac Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Thu, 23 Sep 2021 18:05:36 +0300 Subject: fs/ntfs3: Fix logical error in ntfs_create_inode We need to always call indx_delete_entry after indx_insert_entry if error occurred. Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index d583b71bec50..d51bf4018835 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -1575,7 +1575,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns, if (!S_ISLNK(mode) && (sb->s_flags & SB_POSIXACL)) { err = ntfs_init_acl(mnt_userns, inode, dir); if (err) - goto out6; + goto out7; } else #endif { -- cgit v1.2.3 From d562e901f25d275b55b0496fe01935beeff0ed37 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Thu, 23 Sep 2021 18:04:26 +0300 Subject: fs/ntfs3: Move ni_lock_dir and ni_unlock into ntfs_create_inode Now ntfs3 locks mutex for smaller time. Theoretically in successful cases those locks aren't needed at all. But proving the same for error cases is difficult. So instead of removing them we just move them. Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/inode.c | 17 ++++++++++++++--- fs/ntfs3/namei.c | 20 -------------------- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index d51bf4018835..7dd162f6a7e2 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -1198,9 +1198,13 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns, struct REPARSE_DATA_BUFFER *rp = NULL; bool rp_inserted = false; + ni_lock_dir(dir_ni); + dir_root = indx_get_root(&dir_ni->dir, dir_ni, NULL, NULL); - if (!dir_root) - return ERR_PTR(-EINVAL); + if (!dir_root) { + err = -EINVAL; + goto out1; + } if (S_ISDIR(mode)) { /* Use parent's directory attributes. */ @@ -1549,6 +1553,9 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns, if (err) goto out6; + /* Unlock parent directory before ntfs_init_acl. */ + ni_unlock(dir_ni); + inode->i_generation = le16_to_cpu(rec->seq); dir->i_mtime = dir->i_ctime = inode->i_atime; @@ -1605,8 +1612,10 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns, out7: /* Undo 'indx_insert_entry'. */ + ni_lock_dir(dir_ni); indx_delete_entry(&dir_ni->dir, dir_ni, new_de + 1, le16_to_cpu(new_de->key_size), sbi); + /* ni_unlock(dir_ni); will be called later. */ out6: if (rp_inserted) ntfs_remove_reparse(sbi, IO_REPARSE_TAG_SYMLINK, &new_de->ref); @@ -1630,8 +1639,10 @@ out2: kfree(rp); out1: - if (err) + if (err) { + ni_unlock(dir_ni); return ERR_PTR(err); + } unlock_new_inode(inode); diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index 1c475da4e19d..bc741213ad84 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -95,16 +95,11 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry, static int ntfs_create(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { - struct ntfs_inode *ni = ntfs_i(dir); struct inode *inode; - ni_lock_dir(ni); - inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFREG | mode, 0, NULL, 0, NULL); - ni_unlock(ni); - return IS_ERR(inode) ? PTR_ERR(inode) : 0; } @@ -116,16 +111,11 @@ static int ntfs_create(struct user_namespace *mnt_userns, struct inode *dir, static int ntfs_mknod(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { - struct ntfs_inode *ni = ntfs_i(dir); struct inode *inode; - ni_lock_dir(ni); - inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, mode, rdev, NULL, 0, NULL); - ni_unlock(ni); - return IS_ERR(inode) ? PTR_ERR(inode) : 0; } @@ -196,15 +186,10 @@ static int ntfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, { u32 size = strlen(symname); struct inode *inode; - struct ntfs_inode *ni = ntfs_i(dir); - - ni_lock_dir(ni); inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFLNK | 0777, 0, symname, size, NULL); - ni_unlock(ni); - return IS_ERR(inode) ? PTR_ERR(inode) : 0; } @@ -215,15 +200,10 @@ static int ntfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; - struct ntfs_inode *ni = ntfs_i(dir); - - ni_lock_dir(ni); inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFDIR | mode, 0, NULL, 0, NULL); - ni_unlock(ni); - return IS_ERR(inode) ? PTR_ERR(inode) : 0; } -- cgit v1.2.3 From 0bd5fdb811b0449fcef948a100099cc3197f1b73 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Wed, 22 Sep 2021 18:28:36 +0300 Subject: fs/ntfs3: Refactor ntfs_get_acl_ex for better readability We can safely move set_cached_acl because it works with NULL acl too. Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/xattr.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 5c7c5c7a5ec1..3795943efc8e 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -518,12 +518,15 @@ static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns, /* Translate extended attribute to acl. */ if (err >= 0) { acl = posix_acl_from_xattr(mnt_userns, buf, err); - if (!IS_ERR(acl)) - set_cached_acl(inode, type, acl); + } else if (err == -ENODATA) { + acl = NULL; } else { - acl = err == -ENODATA ? NULL : ERR_PTR(err); + acl = ERR_PTR(err); } + if (!IS_ERR(acl)) + set_cached_acl(inode, type, acl); + __putname(buf); return acl; -- cgit v1.2.3 From 398c35f4d78410725e154c2fc0a51ecac05a3f1f Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Wed, 22 Sep 2021 18:33:38 +0300 Subject: fs/ntfs3: Pass flags to ntfs_set_ea in ntfs_set_acl_ex In case of removing of xattr there must be XATTR_REPLACE flag and zero length. We already check XATTR_REPLACE in ntfs_set_ea, so now we pass XATTR_REPLACE to ntfs_set_ea. Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/xattr.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 3795943efc8e..70f2f9eb6b1e 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -549,6 +549,7 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns, size_t size, name_len; void *value = NULL; int err = 0; + int flags; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; @@ -591,20 +592,24 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns, } if (!acl) { + /* Remove xattr if it can be presented via mode. */ size = 0; value = NULL; + flags = XATTR_REPLACE; } else { size = posix_acl_xattr_size(acl->a_count); value = kmalloc(size, GFP_NOFS); if (!value) return -ENOMEM; - err = posix_acl_to_xattr(mnt_userns, acl, value, size); if (err < 0) goto out; + flags = 0; } - err = ntfs_set_ea(inode, name, name_len, value, size, 0, locked); + err = ntfs_set_ea(inode, name, name_len, value, size, flags, locked); + if (err == -ENODATA && !size) + err = 0; /* Removing non existed xattr. */ if (!err) set_cached_acl(inode, type, acl); -- cgit v1.2.3 From ba77237ef880320105e681b93d596b2fb13860f9 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Wed, 22 Sep 2021 18:46:14 +0300 Subject: fs/ntfs3: Change posix_acl_equiv_mode to posix_acl_update_mode Right now ntfs3 uses posix_acl_equiv_mode instead of posix_acl_update_mode like all other fs. Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/xattr.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 70f2f9eb6b1e..59ec5e61a239 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -559,22 +559,15 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns, if (acl) { umode_t mode = inode->i_mode; - err = posix_acl_equiv_mode(acl, &mode); - if (err < 0) - return err; + err = posix_acl_update_mode(mnt_userns, inode, &mode, + &acl); + if (err) + goto out; if (inode->i_mode != mode) { inode->i_mode = mode; mark_inode_dirty(inode); } - - if (!err) { - /* - * ACL can be exactly represented in the - * traditional file mode permission bits. - */ - acl = NULL; - } } name = XATTR_NAME_POSIX_ACL_ACCESS; name_len = sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1; -- cgit v1.2.3 From 66019837a5563e1f80a4228b7d110d8c52bfdd8b Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Wed, 22 Sep 2021 18:50:58 +0300 Subject: fs/ntfs3: Refactoring lock in ntfs_init_acl This is possible because of moving lock into ntfs_create_inode. Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/xattr.c | 55 ++++++++++++++----------------------------------------- 1 file changed, 14 insertions(+), 41 deletions(-) diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 59ec5e61a239..83bbee277e12 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -693,54 +693,27 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode, struct posix_acl *default_acl, *acl; int err; - /* - * TODO: Refactoring lock. - * ni_lock(dir) ... -> posix_acl_create(dir,...) -> ntfs_get_acl -> ni_lock(dir) - */ - inode->i_default_acl = NULL; - - default_acl = ntfs_get_acl_ex(mnt_userns, dir, ACL_TYPE_DEFAULT, 1); - - if (!default_acl || default_acl == ERR_PTR(-EOPNOTSUPP)) { - inode->i_mode &= ~current_umask(); - err = 0; - goto out; - } - - if (IS_ERR(default_acl)) { - err = PTR_ERR(default_acl); - goto out; - } - - acl = default_acl; - err = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); - if (err < 0) - goto out1; - if (!err) { - posix_acl_release(acl); - acl = NULL; - } - - if (!S_ISDIR(inode->i_mode)) { - posix_acl_release(default_acl); - default_acl = NULL; - } + err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); + if (err) + return err; - if (default_acl) + if (default_acl) { err = ntfs_set_acl_ex(mnt_userns, inode, default_acl, ACL_TYPE_DEFAULT, 1); + posix_acl_release(default_acl); + } else { + inode->i_default_acl = NULL; + } if (!acl) inode->i_acl = NULL; - else if (!err) - err = ntfs_set_acl_ex(mnt_userns, inode, acl, ACL_TYPE_ACCESS, - 1); - - posix_acl_release(acl); -out1: - posix_acl_release(default_acl); + else { + if (!err) + err = ntfs_set_acl_ex(mnt_userns, inode, acl, + ACL_TYPE_ACCESS, 1); + posix_acl_release(acl); + } -out: return err; } #endif -- cgit v1.2.3 From 09f7c338da7818fd33af401d855b895550e7c170 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 28 Sep 2021 19:19:17 +0300 Subject: fs/ntfs3: Reject mount if boot's cluster size < media sector size If we continue to work in this case, then we can corrupt fs. Fixes: 82cae269cfa9 ("fs/ntfs3: Add initialization of super block"). Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 800897777eb0..e9b6a3734576 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -763,9 +763,20 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, sbi->mft.lbo = mlcn << sbi->cluster_bits; sbi->mft.lbo2 = mlcn2 << sbi->cluster_bits; - if (sbi->cluster_size < sbi->sector_size) + /* Compare boot's cluster and sector. */ + if (sbi->cluster_size < boot_sector_size) goto out; + /* Compare boot's cluster and media sector. */ + if (sbi->cluster_size < sector_size) { + /* No way to use ntfs_get_block in this case. */ + ntfs_err( + sb, + "Failed to mount 'cause NTFS's cluster size (%u) is less than media sector size (%u)", + sbi->cluster_size, sector_size); + goto out; + } + sbi->cluster_mask = sbi->cluster_size - 1; sbi->cluster_mask_inv = ~(u64)sbi->cluster_mask; sbi->record_size = record_size = boot->record_size < 0 -- cgit v1.2.3 From dbf59e2a33d2cb5ae0534523fd3d6d8bda808be8 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 28 Sep 2021 19:19:49 +0300 Subject: fs/ntfs3: Refactoring of ntfs_init_from_boot Remove ntfs_sb_info members sector_size and sector_bits. Print details why mount failed. Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/ntfs_fs.h | 2 -- fs/ntfs3/super.c | 19 +++++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 6731b5d9e2d8..38b7c1a9dc52 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -211,10 +211,8 @@ struct ntfs_sb_info { u32 blocks_per_cluster; // cluster_size / sb->s_blocksize u32 record_size; - u32 sector_size; u32 index_size; - u8 sector_bits; u8 cluster_bits; u8 record_bits; diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index e9b6a3734576..705d8b4f4894 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -682,7 +682,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, struct ntfs_sb_info *sbi = sb->s_fs_info; int err; u32 mb, gb, boot_sector_size, sct_per_clst, record_size; - u64 sectors, clusters, fs_size, mlcn, mlcn2; + u64 sectors, clusters, mlcn, mlcn2; struct NTFS_BOOT *boot; struct buffer_head *bh; struct MFT_REC *rec; @@ -740,20 +740,20 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, goto out; } - sbi->sector_size = boot_sector_size; - sbi->sector_bits = blksize_bits(boot_sector_size); - fs_size = (sectors + 1) << sbi->sector_bits; + sbi->volume.size = sectors * boot_sector_size; - gb = format_size_gb(fs_size, &mb); + gb = format_size_gb(sbi->volume.size + boot_sector_size, &mb); /* * - Volume formatted and mounted with the same sector size. * - Volume formatted 4K and mounted as 512. * - Volume formatted 512 and mounted as 4K. */ - if (sbi->sector_size != sector_size) { - ntfs_warn(sb, - "Different NTFS' sector size and media sector size"); + if (boot_sector_size != sector_size) { + ntfs_warn( + sb, + "Different NTFS' sector size (%u) and media sector size (%u)", + boot_sector_size, sector_size); dev_size += sector_size - 1; } @@ -800,10 +800,9 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, : (u32)boot->index_size << sbi->cluster_bits; sbi->volume.ser_num = le64_to_cpu(boot->serial_num); - sbi->volume.size = sectors << sbi->sector_bits; /* Warning if RAW volume. */ - if (dev_size < fs_size) { + if (dev_size < sbi->volume.size + boot_sector_size) { u32 mb0, gb0; gb0 = format_size_gb(dev_size, &mb0); -- cgit v1.2.3 From 35afb70dcfe4eb445060dd955e5b67d962869ce5 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Wed, 29 Sep 2021 19:29:52 +0300 Subject: fs/ntfs3: Check for NULL if ATTR_EA_INFO is incorrect This can be reason for reported panic https://lore.kernel.org/ntfs3/f9de5807-2311-7374-afb0-bc5dffb522c0@gmail.com/ Fixes: 4342306f0f0d ("fs/ntfs3: Add file operations and implementation") Reported-by: Mohammad Rasim Signed-off-by: Konstantin Komarov --- fs/ntfs3/frecord.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 9a53f809576d..007602badd90 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -3080,7 +3080,9 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup, const struct EA_INFO *info; info = resident_data_ex(attr, sizeof(struct EA_INFO)); - dup->ea_size = info->size_pack; + /* If ATTR_EA_INFO exists 'info' can't be NULL. */ + if (info) + dup->ea_size = info->size_pack; } } -- cgit v1.2.3 From b1e0c55a409955aba2d5a151f3f3a8bda8e45193 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Fri, 24 Sep 2021 17:47:04 +0300 Subject: fs/ntfs3: Use available posix_acl_release instead of ntfs_posix_acl_release We don't need to maintain ntfs_posix_acl_release. Reviewed-by: Kari Argillander Signed-off-by: Konstantin Komarov --- fs/ntfs3/xattr.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 83bbee277e12..253a07d9aa7b 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -475,12 +475,6 @@ out: } #ifdef CONFIG_NTFS3_FS_POSIX_ACL -static inline void ntfs_posix_acl_release(struct posix_acl *acl) -{ - if (acl && refcount_dec_and_test(&acl->a_refcount)) - kfree(acl); -} - static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns, struct inode *inode, int type, int locked) @@ -641,7 +635,7 @@ static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns, return -ENODATA; err = posix_acl_to_xattr(mnt_userns, acl, buffer, size); - ntfs_posix_acl_release(acl); + posix_acl_release(acl); return err; } @@ -678,7 +672,7 @@ static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns, err = ntfs_set_acl(mnt_userns, inode, acl, type); release_and_out: - ntfs_posix_acl_release(acl); + posix_acl_release(acl); return err; } -- cgit v1.2.3 From d81e06be921f90d5f1bada59d4549ca6f1bedc61 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Fri, 24 Sep 2021 17:50:22 +0300 Subject: fs/ntfs3: Remove locked argument in ntfs_set_ea We always need to lock now, because locks became smaller (see d562e901f25d "fs/ntfs3: Move ni_lock_dir and ni_unlock into ntfs_create_inode"). Signed-off-by: Konstantin Komarov --- fs/ntfs3/xattr.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 253a07d9aa7b..29f571b53083 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -257,7 +257,7 @@ out: static noinline int ntfs_set_ea(struct inode *inode, const char *name, size_t name_len, const void *value, - size_t val_size, int flags, int locked) + size_t val_size, int flags) { struct ntfs_inode *ni = ntfs_i(inode); struct ntfs_sb_info *sbi = ni->mi.sbi; @@ -276,8 +276,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name, u64 new_sz; void *p; - if (!locked) - ni_lock(ni); + ni_lock(ni); run_init(&ea_run); @@ -465,8 +464,7 @@ update_ea: mark_inode_dirty(&ni->vfs_inode); out: - if (!locked) - ni_unlock(ni); + ni_unlock(ni); run_close(&ea_run); kfree(ea_all); @@ -537,7 +535,7 @@ struct posix_acl *ntfs_get_acl(struct inode *inode, int type) static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns, struct inode *inode, struct posix_acl *acl, - int type, int locked) + int type) { const char *name; size_t size, name_len; @@ -594,7 +592,7 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns, flags = 0; } - err = ntfs_set_ea(inode, name, name_len, value, size, flags, locked); + err = ntfs_set_ea(inode, name, name_len, value, size, flags); if (err == -ENODATA && !size) err = 0; /* Removing non existed xattr. */ if (!err) @@ -612,7 +610,7 @@ out: int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode, struct posix_acl *acl, int type) { - return ntfs_set_acl_ex(mnt_userns, inode, acl, type, 0); + return ntfs_set_acl_ex(mnt_userns, inode, acl, type); } static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns, @@ -693,7 +691,7 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode, if (default_acl) { err = ntfs_set_acl_ex(mnt_userns, inode, default_acl, - ACL_TYPE_DEFAULT, 1); + ACL_TYPE_DEFAULT); posix_acl_release(default_acl); } else { inode->i_default_acl = NULL; @@ -704,7 +702,7 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode, else { if (!err) err = ntfs_set_acl_ex(mnt_userns, inode, acl, - ACL_TYPE_ACCESS, 1); + ACL_TYPE_ACCESS); posix_acl_release(acl); } @@ -988,7 +986,7 @@ set_new_fa: } #endif /* Deal with NTFS extended attribute. */ - err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0); + err = ntfs_set_ea(inode, name, name_len, value, size, flags); out: return err; @@ -1004,28 +1002,29 @@ int ntfs_save_wsl_perm(struct inode *inode) int err; __le32 value; + /* TODO: refactor this, so we don't lock 4 times in ntfs_set_ea */ value = cpu_to_le32(i_uid_read(inode)); err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value, - sizeof(value), 0, 0); + sizeof(value), 0); if (err) goto out; value = cpu_to_le32(i_gid_read(inode)); err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value, - sizeof(value), 0, 0); + sizeof(value), 0); if (err) goto out; value = cpu_to_le32(inode->i_mode); err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value, - sizeof(value), 0, 0); + sizeof(value), 0); if (err) goto out; if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { value = cpu_to_le32(inode->i_rdev); err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value, - sizeof(value), 0, 0); + sizeof(value), 0); if (err) goto out; } -- cgit v1.2.3 From cff32466bf851bf29cd491d8a3cbeb4dc4a36ab6 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Fri, 24 Sep 2021 17:53:56 +0300 Subject: fs/ntfs3: Refactoring of ntfs_set_ea Make code more readable. Don't try to read zero bytes. Add warning when size of exteneded attribute exceeds limit. Signed-off-by: Konstantin Komarov --- fs/ntfs3/xattr.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index 29f571b53083..cdc01877227a 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -75,6 +75,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea, size_t add_bytes, const struct EA_INFO **info) { int err; + struct ntfs_sb_info *sbi = ni->mi.sbi; struct ATTR_LIST_ENTRY *le = NULL; struct ATTRIB *attr_info, *attr_ea; void *ea_p; @@ -99,10 +100,10 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea, /* Check Ea limit. */ size = le32_to_cpu((*info)->size); - if (size > ni->mi.sbi->ea_max_size) + if (size > sbi->ea_max_size) return -EFBIG; - if (attr_size(attr_ea) > ni->mi.sbi->ea_max_size) + if (attr_size(attr_ea) > sbi->ea_max_size) return -EFBIG; /* Allocate memory for packed Ea. */ @@ -110,15 +111,16 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea, if (!ea_p) return -ENOMEM; - if (attr_ea->non_res) { + if (!size) { + ; + } else if (attr_ea->non_res) { struct runs_tree run; run_init(&run); err = attr_load_runs(attr_ea, ni, &run, NULL); if (!err) - err = ntfs_read_run_nb(ni->mi.sbi, &run, 0, ea_p, size, - NULL); + err = ntfs_read_run_nb(sbi, &run, 0, ea_p, size, NULL); run_close(&run); if (err) @@ -366,21 +368,22 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name, new_ea->name[name_len] = 0; memcpy(new_ea->name + name_len + 1, value, val_size); new_pack = le16_to_cpu(ea_info.size_pack) + packed_ea_size(new_ea); - - /* Should fit into 16 bits. */ - if (new_pack > 0xffff) { - err = -EFBIG; // -EINVAL? - goto out; - } ea_info.size_pack = cpu_to_le16(new_pack); - /* New size of ATTR_EA. */ size += add; - if (size > sbi->ea_max_size) { + ea_info.size = cpu_to_le32(size); + + /* + * 1. Check ea_info.size_pack for overflow. + * 2. New attibute size must fit value from $AttrDef + */ + if (new_pack > 0xffff || size > sbi->ea_max_size) { + ntfs_inode_warn( + inode, + "The size of extended attributes must not exceed 64KiB"); err = -EFBIG; // -EINVAL? goto out; } - ea_info.size = cpu_to_le32(size); update_ea: -- cgit v1.2.3 From 8241fffae7c8bab5cec5fc8bcaceccd03079e3aa Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 28 Sep 2021 20:04:10 +0300 Subject: fs/ntfs3: Forbid FALLOC_FL_PUNCH_HOLE for normal files FALLOC_FL_PUNCH_HOLE isn't allowed with normal files. Filesystem must remember info about hole, but for normal file we can only zero it and forget. Fixes: 4342306f0f0d ("fs/ntfs3: Add file operations and implementation") Now xfstests generic/016 generic/021 generic/022 pass. Signed-off-by: Konstantin Komarov --- fs/ntfs3/file.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index 5fb3508e5422..43b1451bff53 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -587,8 +587,11 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) truncate_pagecache(inode, vbo_down); if (!is_sparsed(ni) && !is_compressed(ni)) { - /* Normal file. */ - err = ntfs_zero_range(inode, vbo, end); + /* + * Normal file, can't make hole. + * TODO: Try to find way to save info about hole. + */ + err = -EOPNOTSUPP; goto out; } -- cgit v1.2.3 From 95dd8b2c1ed00c76aaf41b552041c90724749a53 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 5 Oct 2021 17:22:29 +0300 Subject: fs/ntfs3: Remove unnecessary functions We don't need ntfs_xattr_get_acl and ntfs_xattr_set_acl. There are ntfs_get_acl_ex and ntfs_set_acl_ex. Signed-off-by: Konstantin Komarov --- fs/ntfs3/xattr.c | 94 -------------------------------------------------------- 1 file changed, 94 deletions(-) diff --git a/fs/ntfs3/xattr.c b/fs/ntfs3/xattr.c index cdc01877227a..2143099cffdf 100644 --- a/fs/ntfs3/xattr.c +++ b/fs/ntfs3/xattr.c @@ -616,67 +616,6 @@ int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode, return ntfs_set_acl_ex(mnt_userns, inode, acl, type); } -static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns, - struct inode *inode, int type, void *buffer, - size_t size) -{ - struct posix_acl *acl; - int err; - - if (!(inode->i_sb->s_flags & SB_POSIXACL)) { - ntfs_inode_warn(inode, "add mount option \"acl\" to use acl"); - return -EOPNOTSUPP; - } - - acl = ntfs_get_acl(inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - - if (!acl) - return -ENODATA; - - err = posix_acl_to_xattr(mnt_userns, acl, buffer, size); - posix_acl_release(acl); - - return err; -} - -static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns, - struct inode *inode, int type, const void *value, - size_t size) -{ - struct posix_acl *acl; - int err; - - if (!(inode->i_sb->s_flags & SB_POSIXACL)) { - ntfs_inode_warn(inode, "add mount option \"acl\" to use acl"); - return -EOPNOTSUPP; - } - - if (!inode_owner_or_capable(mnt_userns, inode)) - return -EPERM; - - if (!value) { - acl = NULL; - } else { - acl = posix_acl_from_xattr(mnt_userns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - - if (acl) { - err = posix_acl_valid(mnt_userns, acl); - if (err) - goto release_and_out; - } - } - - err = ntfs_set_acl(mnt_userns, inode, acl, type); - -release_and_out: - posix_acl_release(acl); - return err; -} - /* * ntfs_init_acl - Initialize the ACLs of a new inode. * @@ -843,23 +782,6 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de, goto out; } -#ifdef CONFIG_NTFS3_FS_POSIX_ACL - if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 && - !memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS, - sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) || - (name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 && - !memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT, - sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) { - /* TODO: init_user_ns? */ - err = ntfs_xattr_get_acl( - &init_user_ns, inode, - name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 - ? ACL_TYPE_ACCESS - : ACL_TYPE_DEFAULT, - buffer, size); - goto out; - } -#endif /* Deal with NTFS extended attribute. */ err = ntfs_get_ea(inode, name, name_len, buffer, size, NULL); @@ -972,22 +894,6 @@ set_new_fa: goto out; } -#ifdef CONFIG_NTFS3_FS_POSIX_ACL - if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 && - !memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS, - sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) || - (name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 && - !memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT, - sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) { - err = ntfs_xattr_set_acl( - mnt_userns, inode, - name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 - ? ACL_TYPE_ACCESS - : ACL_TYPE_DEFAULT, - value, size); - goto out; - } -#endif /* Deal with NTFS extended attribute. */ err = ntfs_set_ea(inode, name, name_len, value, size, flags); -- cgit v1.2.3 From ce46ae0c3e31400dc89d1e4620a812647cab9c72 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Fri, 1 Oct 2021 18:48:49 +0300 Subject: fs/ntfs3: Keep prealloc for all types of files Before we haven't kept prealloc for sparse files because we thought that it will speed up create / write operations. It lead to situation, when user reserved some space for sparse file, filled volume, and wasn't able to write in reserved file. With this commit we keep prealloc. Now xfstest generic/274 pass. Fixes: be71b5cba2e6 ("fs/ntfs3: Add attrib operations") Signed-off-by: Konstantin Komarov --- fs/ntfs3/attrib.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index 8a00fa978f5f..e8c00dda42ad 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -447,11 +447,8 @@ again: again_1: align = sbi->cluster_size; - if (is_ext) { + if (is_ext) align <<= attr_b->nres.c_unit; - if (is_attr_sparsed(attr_b)) - keep_prealloc = false; - } old_valid = le64_to_cpu(attr_b->nres.valid_size); old_size = le64_to_cpu(attr_b->nres.data_size); @@ -461,9 +458,6 @@ again_1: new_alloc = (new_size + align - 1) & ~(u64)(align - 1); new_alen = new_alloc >> cluster_bits; - if (keep_prealloc && is_ext) - keep_prealloc = false; - if (keep_prealloc && new_size < old_size) { attr_b->nres.data_size = cpu_to_le64(new_size); mi_b->dirty = true; -- cgit v1.2.3 From 9b75450d6c580100611743fa7e690ea3cb47cd4a Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 28 Sep 2021 19:00:30 +0300 Subject: fs/ntfs3: Fix memory leak if fill_super failed In ntfs_init_fs_context we allocate memory in fc->s_fs_info. In case of failed mount we must free it in ntfs_fill_super. We can't do it in ntfs_fs_free, because ntfs_fs_free called with fc->s_fs_info == NULL. fc->s_fs_info became NULL in sget_fc. Signed-off-by: Konstantin Komarov --- fs/ntfs3/super.c | 90 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 705d8b4f4894..d41d76979e12 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -908,7 +908,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) if (IS_ERR(sbi->options->nls)) { sbi->options->nls = NULL; errorf(fc, "Cannot load nls %s", sbi->options->nls_name); - return -EINVAL; + err = -EINVAL; + goto out; } rq = bdev_get_queue(bdev); @@ -922,7 +923,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) err = ntfs_init_from_boot(sb, rq ? queue_logical_block_size(rq) : 512, bdev->bd_inode->i_size); if (err) - return err; + goto out; /* * Load $Volume. This should be done before $LogFile @@ -933,7 +934,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) inode = ntfs_iget5(sb, &ref, &NAME_VOLUME); if (IS_ERR(inode)) { ntfs_err(sb, "Failed to load $Volume."); - return PTR_ERR(inode); + err = PTR_ERR(inode); + goto out; } ni = ntfs_i(inode); @@ -954,19 +956,19 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) } else { /* Should we break mounting here? */ //err = -EINVAL; - //goto out; + //goto put_inode_out; } attr = ni_find_attr(ni, attr, NULL, ATTR_VOL_INFO, NULL, 0, NULL, NULL); if (!attr || is_attr_ext(attr)) { err = -EINVAL; - goto out; + goto put_inode_out; } info = resident_data_ex(attr, SIZEOF_ATTRIBUTE_VOLUME_INFO); if (!info) { err = -EINVAL; - goto out; + goto put_inode_out; } sbi->volume.major_ver = info->major_ver; @@ -980,7 +982,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) inode = ntfs_iget5(sb, &ref, &NAME_MIRROR); if (IS_ERR(inode)) { ntfs_err(sb, "Failed to load $MFTMirr."); - return PTR_ERR(inode); + err = PTR_ERR(inode); + goto out; } sbi->mft.recs_mirr = @@ -994,14 +997,15 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) inode = ntfs_iget5(sb, &ref, &NAME_LOGFILE); if (IS_ERR(inode)) { ntfs_err(sb, "Failed to load \x24LogFile."); - return PTR_ERR(inode); + err = PTR_ERR(inode); + goto out; } ni = ntfs_i(inode); err = ntfs_loadlog_and_replay(ni, sbi); if (err) - goto out; + goto put_inode_out; iput(inode); @@ -1009,14 +1013,16 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) if (!sb_rdonly(sb)) { ntfs_warn(sb, "failed to replay log file. Can't mount rw!"); - return -EINVAL; + err = -EINVAL; + goto out; } } else if (sbi->volume.flags & VOLUME_FLAG_DIRTY) { if (!sb_rdonly(sb) && !sbi->options->force) { ntfs_warn( sb, "volume is dirty and \"force\" flag is not set!"); - return -EINVAL; + err = -EINVAL; + goto out; } } @@ -1027,7 +1033,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) inode = ntfs_iget5(sb, &ref, &NAME_MFT); if (IS_ERR(inode)) { ntfs_err(sb, "Failed to load $MFT."); - return PTR_ERR(inode); + err = PTR_ERR(inode); + goto out; } ni = ntfs_i(inode); @@ -1038,11 +1045,11 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) err = wnd_init(&sbi->mft.bitmap, sb, tt); if (err) - goto out; + goto put_inode_out; err = ni_load_all_mi(ni); if (err) - goto out; + goto put_inode_out; sbi->mft.ni = ni; @@ -1052,7 +1059,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) inode = ntfs_iget5(sb, &ref, &NAME_BADCLUS); if (IS_ERR(inode)) { ntfs_err(sb, "Failed to load $BadClus."); - return PTR_ERR(inode); + err = PTR_ERR(inode); + goto out; } ni = ntfs_i(inode); @@ -1075,13 +1083,14 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) inode = ntfs_iget5(sb, &ref, &NAME_BITMAP); if (IS_ERR(inode)) { ntfs_err(sb, "Failed to load $Bitmap."); - return PTR_ERR(inode); + err = PTR_ERR(inode); + goto out; } #ifndef CONFIG_NTFS3_64BIT_CLUSTER if (inode->i_size >> 32) { err = -EINVAL; - goto out; + goto put_inode_out; } #endif @@ -1089,21 +1098,21 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) tt = sbi->used.bitmap.nbits; if (inode->i_size < bitmap_size(tt)) { err = -EINVAL; - goto out; + goto put_inode_out; } /* Not necessary. */ sbi->used.bitmap.set_tail = true; err = wnd_init(&sbi->used.bitmap, sb, tt); if (err) - goto out; + goto put_inode_out; iput(inode); /* Compute the MFT zone. */ err = ntfs_refresh_zone(sbi); if (err) - return err; + goto out; /* Load $AttrDef. */ ref.low = cpu_to_le32(MFT_REC_ATTR); @@ -1111,18 +1120,19 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) inode = ntfs_iget5(sb, &ref, &NAME_ATTRDEF); if (IS_ERR(inode)) { ntfs_err(sb, "Failed to load $AttrDef -> %d", err); - return PTR_ERR(inode); + err = PTR_ERR(inode); + goto out; } if (inode->i_size < sizeof(struct ATTR_DEF_ENTRY)) { err = -EINVAL; - goto out; + goto put_inode_out; } bytes = inode->i_size; sbi->def_table = t = kmalloc(bytes, GFP_NOFS); if (!t) { err = -ENOMEM; - goto out; + goto put_inode_out; } for (done = idx = 0; done < bytes; done += PAGE_SIZE, idx++) { @@ -1131,7 +1141,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) if (IS_ERR(page)) { err = PTR_ERR(page); - goto out; + goto put_inode_out; } memcpy(Add2Ptr(t, done), page_address(page), min(PAGE_SIZE, tail)); @@ -1139,7 +1149,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) if (!idx && ATTR_STD != t->type) { err = -EINVAL; - goto out; + goto put_inode_out; } } @@ -1173,12 +1183,13 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) inode = ntfs_iget5(sb, &ref, &NAME_UPCASE); if (IS_ERR(inode)) { ntfs_err(sb, "Failed to load $UpCase."); - return PTR_ERR(inode); + err = PTR_ERR(inode); + goto out; } if (inode->i_size != 0x10000 * sizeof(short)) { err = -EINVAL; - goto out; + goto put_inode_out; } for (idx = 0; idx < (0x10000 * sizeof(short) >> PAGE_SHIFT); idx++) { @@ -1188,7 +1199,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) if (IS_ERR(page)) { err = PTR_ERR(page); - goto out; + goto put_inode_out; } src = page_address(page); @@ -1214,7 +1225,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) /* Load $Secure. */ err = ntfs_security_init(sbi); if (err) - return err; + goto out; /* Load $Extend. */ err = ntfs_extend_init(sbi); @@ -1239,19 +1250,30 @@ load_root: inode = ntfs_iget5(sb, &ref, &NAME_ROOT); if (IS_ERR(inode)) { ntfs_err(sb, "Failed to load root."); - return PTR_ERR(inode); + err = PTR_ERR(inode); + goto out; } sb->s_root = d_make_root(inode); - if (!sb->s_root) - return -ENOMEM; + if (!sb->s_root) { + err = -ENOMEM; + goto put_inode_out; + } fc->fs_private = NULL; - fc->s_fs_info = NULL; return 0; -out: + +put_inode_out: iput(inode); +out: + /* + * Free resources here. + * ntfs_fs_free will be called with fc->s_fs_info = NULL + */ + put_ntfs(sbi); + sb->s_fs_info = NULL; + return err; } -- cgit v1.2.3 From 2c69078851b3d7495eb191158d0bcb9c91a6d148 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Mon, 4 Oct 2021 18:22:45 +0300 Subject: fs/ntfs3: Rework ntfs_utf16_to_nls Now ntfs_utf16_to_nls takes length as one of arguments. If length of symlink > 255, then we tried to convert length of symlink +- some random number. Now 255 symbols limit was removed. Signed-off-by: Konstantin Komarov --- fs/ntfs3/dir.c | 19 ++++++++----------- fs/ntfs3/ntfs_fs.h | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/fs/ntfs3/dir.c b/fs/ntfs3/dir.c index 785e72d4392e..fb438d604040 100644 --- a/fs/ntfs3/dir.c +++ b/fs/ntfs3/dir.c @@ -15,11 +15,10 @@ #include "ntfs_fs.h" /* Convert little endian UTF-16 to NLS string. */ -int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni, +int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const __le16 *name, u32 len, u8 *buf, int buf_len) { - int ret, uni_len, warn; - const __le16 *ip; + int ret, warn; u8 *op; struct nls_table *nls = sbi->options->nls; @@ -27,18 +26,16 @@ int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni, if (!nls) { /* UTF-16 -> UTF-8 */ - ret = utf16s_to_utf8s((wchar_t *)uni->name, uni->len, - UTF16_LITTLE_ENDIAN, buf, buf_len); + ret = utf16s_to_utf8s(name, len, UTF16_LITTLE_ENDIAN, buf, + buf_len); buf[ret] = '\0'; return ret; } - ip = uni->name; op = buf; - uni_len = uni->len; warn = 0; - while (uni_len--) { + while (len--) { u16 ec; int charlen; char dump[5]; @@ -49,7 +46,7 @@ int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni, break; } - ec = le16_to_cpu(*ip++); + ec = le16_to_cpu(*name++); charlen = nls->uni2char(ec, op, buf_len); if (charlen > 0) { @@ -304,8 +301,8 @@ static inline int ntfs_filldir(struct ntfs_sb_info *sbi, struct ntfs_inode *ni, if (sbi->options->nohidden && (fname->dup.fa & FILE_ATTRIBUTE_HIDDEN)) return 0; - name_len = ntfs_utf16_to_nls(sbi, (struct le_str *)&fname->name_len, - name, PATH_MAX); + name_len = ntfs_utf16_to_nls(sbi, fname->name, fname->name_len, name, + PATH_MAX); if (name_len <= 0) { ntfs_warn(sbi->sb, "failed to convert name for inode %lx.", ino); diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 38b7c1a9dc52..9277b552f257 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -475,7 +475,7 @@ bool are_bits_set(const ulong *map, size_t bit, size_t nbits); size_t get_set_bits_ex(const ulong *map, size_t bit, size_t nbits); /* Globals from dir.c */ -int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const struct le_str *uni, +int ntfs_utf16_to_nls(struct ntfs_sb_info *sbi, const __le16 *name, u32 len, u8 *buf, int buf_len); int ntfs_nls_to_utf16(struct ntfs_sb_info *sbi, const u8 *name, u32 name_len, struct cpu_str *uni, u32 max_ulen, -- cgit v1.2.3 From 4dbe8e4413d70ac4f163592d69eef74d7824783a Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Mon, 4 Oct 2021 18:59:55 +0300 Subject: fs/ntfs3: Refactor ntfs_readlink_hlp Rename some variables. Returned err by default is EINVAL. Signed-off-by: Konstantin Komarov --- fs/ntfs3/inode.c | 91 ++++++++++++++++++++++++++------------------------------ 1 file changed, 43 insertions(+), 48 deletions(-) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 7dd162f6a7e2..d618b0573533 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -1763,15 +1763,15 @@ void ntfs_evict_inode(struct inode *inode) static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer, int buflen) { - int i, err = 0; + int i, err = -EINVAL; struct ntfs_inode *ni = ntfs_i(inode); struct super_block *sb = inode->i_sb; struct ntfs_sb_info *sbi = sb->s_fs_info; - u64 i_size = inode->i_size; - u16 nlen = 0; + u64 size; + u16 ulen = 0; void *to_free = NULL; struct REPARSE_DATA_BUFFER *rp; - struct le_str *uni; + const __le16 *uname; struct ATTRIB *attr; /* Reparse data present. Try to parse it. */ @@ -1780,68 +1780,64 @@ static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer, *buffer = 0; - /* Read into temporal buffer. */ - if (i_size > sbi->reparse.max_size || i_size <= sizeof(u32)) { - err = -EINVAL; - goto out; - } - attr = ni_find_attr(ni, NULL, NULL, ATTR_REPARSE, NULL, 0, NULL, NULL); - if (!attr) { - err = -EINVAL; + if (!attr) goto out; - } if (!attr->non_res) { - rp = resident_data_ex(attr, i_size); - if (!rp) { - err = -EINVAL; + rp = resident_data_ex(attr, sizeof(struct REPARSE_DATA_BUFFER)); + if (!rp) goto out; - } + size = le32_to_cpu(attr->res.data_size); } else { - rp = kmalloc(i_size, GFP_NOFS); + size = le64_to_cpu(attr->nres.data_size); + rp = NULL; + } + + if (size > sbi->reparse.max_size || size <= sizeof(u32)) + goto out; + + if (!rp) { + rp = kmalloc(size, GFP_NOFS); if (!rp) { err = -ENOMEM; goto out; } to_free = rp; - err = ntfs_read_run_nb(sbi, &ni->file.run, 0, rp, i_size, NULL); + /* Read into temporal buffer. */ + err = ntfs_read_run_nb(sbi, &ni->file.run, 0, rp, size, NULL); if (err) goto out; } - err = -EINVAL; - /* Microsoft Tag. */ switch (rp->ReparseTag) { case IO_REPARSE_TAG_MOUNT_POINT: /* Mount points and junctions. */ /* Can we use 'Rp->MountPointReparseBuffer.PrintNameLength'? */ - if (i_size <= offsetof(struct REPARSE_DATA_BUFFER, - MountPointReparseBuffer.PathBuffer)) + if (size <= offsetof(struct REPARSE_DATA_BUFFER, + MountPointReparseBuffer.PathBuffer)) goto out; - uni = Add2Ptr(rp, - offsetof(struct REPARSE_DATA_BUFFER, - MountPointReparseBuffer.PathBuffer) + - le16_to_cpu(rp->MountPointReparseBuffer - .PrintNameOffset) - - 2); - nlen = le16_to_cpu(rp->MountPointReparseBuffer.PrintNameLength); + uname = Add2Ptr(rp, + offsetof(struct REPARSE_DATA_BUFFER, + MountPointReparseBuffer.PathBuffer) + + le16_to_cpu(rp->MountPointReparseBuffer + .PrintNameOffset)); + ulen = le16_to_cpu(rp->MountPointReparseBuffer.PrintNameLength); break; case IO_REPARSE_TAG_SYMLINK: /* FolderSymbolicLink */ /* Can we use 'Rp->SymbolicLinkReparseBuffer.PrintNameLength'? */ - if (i_size <= offsetof(struct REPARSE_DATA_BUFFER, - SymbolicLinkReparseBuffer.PathBuffer)) + if (size <= offsetof(struct REPARSE_DATA_BUFFER, + SymbolicLinkReparseBuffer.PathBuffer)) goto out; - uni = Add2Ptr(rp, - offsetof(struct REPARSE_DATA_BUFFER, - SymbolicLinkReparseBuffer.PathBuffer) + - le16_to_cpu(rp->SymbolicLinkReparseBuffer - .PrintNameOffset) - - 2); - nlen = le16_to_cpu( + uname = Add2Ptr( + rp, offsetof(struct REPARSE_DATA_BUFFER, + SymbolicLinkReparseBuffer.PathBuffer) + + le16_to_cpu(rp->SymbolicLinkReparseBuffer + .PrintNameOffset)); + ulen = le16_to_cpu( rp->SymbolicLinkReparseBuffer.PrintNameLength); break; @@ -1873,29 +1869,28 @@ static noinline int ntfs_readlink_hlp(struct inode *inode, char *buffer, goto out; } if (!IsReparseTagNameSurrogate(rp->ReparseTag) || - i_size <= sizeof(struct REPARSE_POINT)) { + size <= sizeof(struct REPARSE_POINT)) { goto out; } /* Users tag. */ - uni = Add2Ptr(rp, sizeof(struct REPARSE_POINT) - 2); - nlen = le16_to_cpu(rp->ReparseDataLength) - + uname = Add2Ptr(rp, sizeof(struct REPARSE_POINT)); + ulen = le16_to_cpu(rp->ReparseDataLength) - sizeof(struct REPARSE_POINT); } /* Convert nlen from bytes to UNICODE chars. */ - nlen >>= 1; + ulen >>= 1; /* Check that name is available. */ - if (!nlen || &uni->name[nlen] > (__le16 *)Add2Ptr(rp, i_size)) + if (!ulen || uname + ulen > (__le16 *)Add2Ptr(rp, size)) goto out; /* If name is already zero terminated then truncate it now. */ - if (!uni->name[nlen - 1]) - nlen -= 1; - uni->len = nlen; + if (!uname[ulen - 1]) + ulen -= 1; - err = ntfs_utf16_to_nls(sbi, uni, buffer, buflen); + err = ntfs_utf16_to_nls(sbi, uname, ulen, buffer, buflen); if (err < 0) goto out; -- cgit v1.2.3 From 14a981193e409d8ca3f89768cfbd7a9a516d9927 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Mon, 4 Oct 2021 18:52:24 +0300 Subject: fs/ntfs3: Refactor ntfs_create_inode Set size for symlink, so we don't need to calculate it on the fly. Signed-off-by: Konstantin Komarov --- fs/ntfs3/inode.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index d618b0573533..bdebbbd53e76 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -1488,7 +1488,10 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns, asize = ALIGN(SIZEOF_RESIDENT + nsize, 8); t16 = PtrOffset(rec, attr); - /* 0x78 - the size of EA + EAINFO to store WSL */ + /* + * Below function 'ntfs_save_wsl_perm' requires 0x78 bytes. + * It is good idea to keep extened attributes resident. + */ if (asize + t16 + 0x78 + 8 > sbi->record_size) { CLST alen; CLST clst = bytes_to_cluster(sbi, nsize); @@ -1523,14 +1526,14 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns, } asize = SIZEOF_NONRESIDENT + ALIGN(err, 8); - inode->i_size = nsize; } else { attr->res.data_off = SIZEOF_RESIDENT_LE; attr->res.data_size = cpu_to_le32(nsize); memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), rp, nsize); - inode->i_size = nsize; nsize = 0; } + /* Size of symlink equals the length of input string. */ + inode->i_size = size; attr->size = cpu_to_le32(asize); @@ -1567,6 +1570,8 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns, inode->i_op = &ntfs_link_inode_operations; inode->i_fop = NULL; inode->i_mapping->a_ops = &ntfs_aops; + inode->i_size = size; + inode_nohighmem(inode); } else if (S_ISREG(mode)) { inode->i_op = &ntfs_file_inode_operations; inode->i_fop = &ntfs_file_operations; -- cgit v1.2.3 From cd4c76ff807c1afeed89f1b7e311760c0e296349 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 5 Oct 2021 19:08:08 +0300 Subject: fs/ntfs3: Refactor ni_parse_reparse Change argument from void* to struct REPARSE_DATA_BUFFER* We copy data to buffer, so we can read it later in ntfs_read_mft. Signed-off-by: Konstantin Komarov --- fs/ntfs3/frecord.c | 9 +++++---- fs/ntfs3/ntfs_fs.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 007602badd90..ecb965e4afd0 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -1710,18 +1710,16 @@ out: /* * ni_parse_reparse * - * Buffer is at least 24 bytes. + * buffer - memory for reparse buffer header */ enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr, - void *buffer) + struct REPARSE_DATA_BUFFER *buffer) { const struct REPARSE_DATA_BUFFER *rp = NULL; u8 bits; u16 len; typeof(rp->CompressReparseBuffer) *cmpr; - static_assert(sizeof(struct REPARSE_DATA_BUFFER) <= 24); - /* Try to estimate reparse point. */ if (!attr->non_res) { rp = resident_data_ex(attr, sizeof(struct REPARSE_DATA_BUFFER)); @@ -1807,6 +1805,9 @@ enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr, return REPARSE_NONE; } + if (buffer != rp) + memcpy(buffer, rp, sizeof(struct REPARSE_DATA_BUFFER)); + /* Looks like normal symlink. */ return REPARSE_LINK; } diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 9277b552f257..e95d93c683ed 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -547,7 +547,7 @@ struct ATTR_FILE_NAME *ni_fname_type(struct ntfs_inode *ni, u8 name_type, struct ATTR_LIST_ENTRY **entry); int ni_new_attr_flags(struct ntfs_inode *ni, enum FILE_ATTRIBUTE new_fa); enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr, - void *buffer); + struct REPARSE_DATA_BUFFER *buffer); int ni_write_inode(struct inode *inode, int sync, const char *hint); #define _ni_write_inode(i, w) ni_write_inode(i, w, __func__) int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo, -- cgit v1.2.3 From 22b05f1ac0332cb47701649206997d8d9a1a7f24 Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Tue, 5 Oct 2021 19:33:26 +0300 Subject: fs/ntfs3: Refactor ntfs_read_mft Don't save size of attribute reparse point as size of symlink. Signed-off-by: Konstantin Komarov --- fs/ntfs3/inode.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index bdebbbd53e76..859951d785cb 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -222,9 +222,6 @@ next_attr: if (!attr->non_res) { ni->i_valid = inode->i_size = rsize; inode_set_bytes(inode, rsize); - t32 = asize; - } else { - t32 = le16_to_cpu(attr->nres.run_off); } mode = S_IFREG | (0777 & sbi->options->fs_fmask_inv); @@ -313,17 +310,14 @@ next_attr: rp_fa = ni_parse_reparse(ni, attr, &rp); switch (rp_fa) { case REPARSE_LINK: - if (!attr->non_res) { - inode->i_size = rsize; - inode_set_bytes(inode, rsize); - t32 = asize; - } else { - inode->i_size = - le64_to_cpu(attr->nres.data_size); - t32 = le16_to_cpu(attr->nres.run_off); - } + /* + * Normal symlink. + * Assume one unicode symbol == one utf8. + */ + inode->i_size = le16_to_cpu(rp.SymbolicLinkReparseBuffer + .PrintNameLength) / + sizeof(u16); - /* Looks like normal symlink. */ ni->i_valid = inode->i_size; /* Clear directory bit. */ @@ -420,7 +414,7 @@ end_enum: ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY; inode->i_op = &ntfs_link_inode_operations; inode->i_fop = NULL; - inode_nohighmem(inode); // ?? + inode_nohighmem(inode); } else if (S_ISREG(mode)) { ni->std_fa &= ~FILE_ATTRIBUTE_DIRECTORY; inode->i_op = &ntfs_file_inode_operations; -- cgit v1.2.3 From 8607954cf255329d1c6dfc073ff1508b7585573c Mon Sep 17 00:00:00 2001 From: Konstantin Komarov Date: Mon, 11 Oct 2021 19:43:29 +0300 Subject: fs/ntfs3: Check for NULL pointers in ni_try_remove_attr_list Check for potential NULL pointers. Print error message if found. Thread, that leads to this commit: https://lore.kernel.org/ntfs3/227c13e3-5a22-0cba-41eb-fcaf41940711@paragon-software.com/ Reported-by: Mohammad Rasim Signed-off-by: Konstantin Komarov --- fs/ntfs3/frecord.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index ecb965e4afd0..6f47a9c17f89 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -705,18 +705,35 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) continue; mi = ni_find_mi(ni, ino_get(&le->ref)); + if (!mi) { + /* Should never happened, 'cause already checked. */ + goto bad; + } attr = mi_find_attr(mi, NULL, le->type, le_name(le), le->name_len, &le->id); + if (!attr) { + /* Should never happened, 'cause already checked. */ + goto bad; + } asize = le32_to_cpu(attr->size); /* Insert into primary record. */ attr_ins = mi_insert_attr(&ni->mi, le->type, le_name(le), le->name_len, asize, le16_to_cpu(attr->name_off)); - id = attr_ins->id; + if (!attr_ins) { + /* + * Internal error. + * Either no space in primary record (already checked). + * Either tried to insert another + * non indexed attribute (logic error). + */ + goto bad; + } /* Copy all except id. */ + id = attr_ins->id; memcpy(attr_ins, attr, asize); attr_ins->id = id; @@ -732,6 +749,10 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) ni->attr_list.dirty = false; return 0; +bad: + ntfs_inode_err(&ni->vfs_inode, "Internal error"); + make_bad_inode(&ni->vfs_inode); + return -EINVAL; } /* -- cgit v1.2.3