diff options
Diffstat (limited to 'fs/ntfs3/super.c')
| -rw-r--r-- | fs/ntfs3/super.c | 161 |
1 files changed, 117 insertions, 44 deletions
diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c index 6a0f6b0a3ab2..8b0cf0ed4f72 100644 --- a/fs/ntfs3/super.c +++ b/fs/ntfs3/super.c @@ -16,6 +16,13 @@ * mi - MFT inode - One MFT record(usually 1024 bytes or 4K), consists of attributes. * ni - NTFS inode - Extends linux inode. consists of one or more mft inodes. * index - unit inside directory - 2K, 4K, <=page size, does not depend on cluster size. + * resident attribute - Attribute with content stored directly in the MFT record + * non-resident attribute - Attribute with content stored in clusters + * data_size - Size of attribute content in bytes. Equal to inode->i_size + * valid_size - Number of bytes written to the non-resident attribute + * allocated_size - Total size of clusters allocated for non-resident content + * total_size - Actual size of allocated clusters for sparse or compressed attributes + * - Constraint: valid_size <= data_size <= allocated_size * * WSL - Windows Subsystem for Linux * https://docs.microsoft.com/en-us/windows/wsl/file-permissions @@ -51,6 +58,7 @@ #include <linux/buffer_head.h> #include <linux/exportfs.h> #include <linux/fs.h> +#include <linux/fs_struct.h> #include <linux/fs_context.h> #include <linux/fs_parser.h> #include <linux/log2.h> @@ -277,9 +285,9 @@ static const struct fs_parameter_spec ntfs_fs_parameters[] = { fsparam_flag("hide_dot_files", Opt_hide_dot_files), fsparam_flag("windows_names", Opt_windows_names), fsparam_flag("showmeta", Opt_showmeta), - fsparam_flag("acl", Opt_acl), + fsparam_flag_no("acl", Opt_acl), fsparam_string("iocharset", Opt_iocharset), - fsparam_flag("prealloc", Opt_prealloc), + fsparam_flag_no("prealloc", Opt_prealloc), fsparam_flag("nocase", Opt_nocase), {} }; @@ -288,10 +296,8 @@ static const struct fs_parameter_spec ntfs_fs_parameters[] = { /* * Load nls table or if @nls is utf8 then return NULL. * - * It is good idea to use here "const char *nls". - * But load_nls accepts "char*". */ -static struct nls_table *ntfs_load_nls(char *nls) +static struct nls_table *ntfs_load_nls(const char *nls) { struct nls_table *ret; @@ -390,7 +396,7 @@ static int ntfs_fs_parse_param(struct fs_context *fc, param->string = NULL; break; case Opt_prealloc: - opts->prealloc = 1; + opts->prealloc = !result.negated; break; case Opt_nocase: opts->nocase = 1; @@ -555,6 +561,55 @@ static const struct proc_ops ntfs3_label_fops = { .proc_write = ntfs3_label_write, }; +static void ntfs_create_procdir(struct super_block *sb) +{ + struct proc_dir_entry *e; + + if (!proc_info_root) + return; + + e = proc_mkdir(sb->s_id, proc_info_root); + if (e) { + struct ntfs_sb_info *sbi = sb->s_fs_info; + + proc_create_data("volinfo", 0444, e, &ntfs3_volinfo_fops, sb); + proc_create_data("label", 0644, e, &ntfs3_label_fops, sb); + sbi->procdir = e; + } +} + +static void ntfs_remove_procdir(struct super_block *sb) +{ + struct ntfs_sb_info *sbi = sb->s_fs_info; + + if (!sbi->procdir) + return; + + remove_proc_entry("label", sbi->procdir); + remove_proc_entry("volinfo", sbi->procdir); + remove_proc_entry(sb->s_id, proc_info_root); + sbi->procdir = NULL; +} + +static void ntfs_create_proc_root(void) +{ + proc_info_root = proc_mkdir("fs/ntfs3", NULL); +} + +static void ntfs_remove_proc_root(void) +{ + if (proc_info_root) { + remove_proc_entry("fs/ntfs3", NULL); + proc_info_root = NULL; + } +} +#else +// clang-format off +static void ntfs_create_procdir(struct super_block *sb){} +static void ntfs_remove_procdir(struct super_block *sb){} +static void ntfs_create_proc_root(void){} +static void ntfs_remove_proc_root(void){} +// clang-format on #endif static struct kmem_cache *ntfs_inode_cachep; @@ -644,18 +699,18 @@ static void ntfs_put_super(struct super_block *sb) { struct ntfs_sb_info *sbi = sb->s_fs_info; -#ifdef CONFIG_PROC_FS - // Remove /proc/fs/ntfs3/.. - if (sbi->procdir) { - remove_proc_entry("label", sbi->procdir); - remove_proc_entry("volinfo", sbi->procdir); - remove_proc_entry(sb->s_id, proc_info_root); - sbi->procdir = NULL; - } -#endif + ntfs_remove_procdir(sb); /* Mark rw ntfs as clear, if possible. */ ntfs_set_state(sbi, NTFS_DIRTY_CLEAR); + + if (sbi->options) { + unload_nls(sbi->options->nls); + kfree(sbi->options->nls_name); + kfree(sbi->options); + sbi->options = NULL; + } + ntfs3_put_sbi(sbi); } @@ -892,6 +947,11 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, sbi->volume.blocks = dev_size >> PAGE_SHIFT; + /* Set dummy blocksize to read boot_block. */ + if (!sb_min_blocksize(sb, PAGE_SIZE)) { + return -EINVAL; + } + read_boot: bh = ntfs_bread(sb, boot_block); if (!bh) @@ -1016,6 +1076,7 @@ read_boot: dev_size += sector_size - 1; } + sbi->bdev_blocksize_mask = max(boot_sector_size, sector_size) - 1; sbi->mft.lbo = mlcn << cluster_bits; sbi->mft.lbo2 = mlcn2 << cluster_bits; @@ -1157,7 +1218,8 @@ 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 ntfs_mount_options *options; + struct ntfs_mount_options *fc_opts; + struct ntfs_mount_options *options = NULL; struct inode *inode; struct ntfs_inode *ni; size_t i, tt, bad_len, bad_frags; @@ -1174,7 +1236,23 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ref.high = 0; sbi->sb = sb; - sbi->options = options = fc->fs_private; + fc_opts = fc->fs_private; + if (!fc_opts) { + errorf(fc, "missing mount options"); + return -EINVAL; + } + options = kmemdup(fc_opts, sizeof(*fc_opts), GFP_KERNEL); + if (!options) + return -ENOMEM; + + if (fc_opts->nls_name) { + options->nls_name = kstrdup(fc_opts->nls_name, GFP_KERNEL); + if (!options->nls_name) { + kfree(options); + return -ENOMEM; + } + } + sbi->options = options; fc->fs_private = NULL; sb->s_flags |= SB_NODIRATIME; sb->s_magic = 0x7366746e; // "ntfs" @@ -1182,7 +1260,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) sb->s_export_op = &ntfs_export_ops; sb->s_time_gran = NTFS_TIME_GRAN; // 100 nsec sb->s_xattr = ntfs_xattr_handlers; - sb->s_d_op = options->nocase ? &ntfs_dentry_ops : NULL; + set_default_d_op(sb, options->nocase ? &ntfs_dentry_ops : NULL); options->nls = ntfs_load_nls(options->nls_name); if (IS_ERR(options->nls)) { @@ -1252,7 +1330,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) sbi->volume.ni = ni; if (info->flags & VOLUME_FLAG_DIRTY) { sbi->volume.real_dirty = true; - ntfs_info(sb, "It is recommened to use chkdsk."); + ntfs_info(sb, "It is recommended to use chkdsk."); } /* Load $MFTMirr to estimate recs_mirr. */ @@ -1590,20 +1668,7 @@ load_root: kfree(boot2); } -#ifdef CONFIG_PROC_FS - /* Create /proc/fs/ntfs3/.. */ - if (proc_info_root) { - struct proc_dir_entry *e = proc_mkdir(sb->s_id, proc_info_root); - static_assert((S_IRUGO | S_IWUSR) == 0644); - if (e) { - proc_create_data("volinfo", S_IRUGO, e, - &ntfs3_volinfo_fops, sb); - proc_create_data("label", S_IRUGO | S_IWUSR, e, - &ntfs3_label_fops, sb); - sbi->procdir = e; - } - } -#endif + ntfs_create_procdir(sb); if (is_legacy_ntfs(sb)) sb->s_flags |= SB_RDONLY; @@ -1612,9 +1677,16 @@ load_root: put_inode_out: iput(inode); out: + /* sbi->options == options */ + if (options) { + unload_nls(options->nls); + kfree(options->nls_name); + kfree(options); + sbi->options = NULL; + } + ntfs3_put_sbi(sbi); kfree(boot2); - ntfs3_put_sbi(sbi); return err; } @@ -1738,6 +1810,12 @@ static int __ntfs_init_fs_context(struct fs_context *fc) opts->fs_gid = current_gid(); opts->fs_fmask_inv = ~current_umask(); opts->fs_dmask_inv = ~current_umask(); + opts->prealloc = 1; + +#ifdef CONFIG_NTFS3_FS_POSIX_ACL + /* Set the default value 'acl' */ + fc->sb_flags |= SB_POSIXACL; +#endif if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) goto ok; @@ -1853,14 +1931,11 @@ static int __init init_ntfs_fs(void) if (IS_ENABLED(CONFIG_NTFS3_LZX_XPRESS)) pr_info("ntfs3: Read-only LZX/Xpress compression included\n"); -#ifdef CONFIG_PROC_FS - /* Create "/proc/fs/ntfs3" */ - proc_info_root = proc_mkdir("fs/ntfs3", NULL); -#endif + ntfs_create_proc_root(); err = ntfs3_init_bitmap(); if (err) - return err; + goto out2; ntfs_inode_cachep = kmem_cache_create( "ntfs_inode_cache", sizeof(struct ntfs_inode), 0, @@ -1880,6 +1955,8 @@ out: kmem_cache_destroy(ntfs_inode_cachep); out1: ntfs3_exit_bitmap(); +out2: + ntfs_remove_proc_root(); return err; } @@ -1890,11 +1967,7 @@ static void __exit exit_ntfs_fs(void) unregister_filesystem(&ntfs_fs_type); unregister_as_ntfs_legacy(); ntfs3_exit_bitmap(); - -#ifdef CONFIG_PROC_FS - if (proc_info_root) - remove_proc_entry("fs/ntfs3", NULL); -#endif + ntfs_remove_proc_root(); } MODULE_LICENSE("GPL"); |
