summaryrefslogtreecommitdiff
path: root/fs/ntfs3/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ntfs3/super.c')
-rw-r--r--fs/ntfs3/super.c161
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");