summaryrefslogtreecommitdiffstats
path: root/fs/ntfs3/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ntfs3/super.c')
-rw-r--r--fs/ntfs3/super.c143
1 files changed, 95 insertions, 48 deletions
diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
index 47012c9bf505..ef4ea3f21905 100644
--- a/fs/ntfs3/super.c
+++ b/fs/ntfs3/super.c
@@ -21,6 +21,30 @@
* https://docs.microsoft.com/en-us/windows/wsl/file-permissions
* It stores uid/gid/mode/dev in xattr
*
+ * ntfs allows up to 2^64 clusters per volume.
+ * It means you should use 64 bits lcn to operate with ntfs.
+ * Implementation of ntfs.sys uses only 32 bits lcn.
+ * Default ntfs3 uses 32 bits lcn too.
+ * ntfs3 built with CONFIG_NTFS3_64BIT_CLUSTER (ntfs3_64) uses 64 bits per lcn.
+ *
+ *
+ * ntfs limits, cluster size is 4K (2^12)
+ * -----------------------------------------------------------------------------
+ * | Volume size | Clusters | ntfs.sys | ntfs3 | ntfs3_64 | mkntfs | chkdsk |
+ * -----------------------------------------------------------------------------
+ * | < 16T, 2^44 | < 2^32 | yes | yes | yes | yes | yes |
+ * | > 16T, 2^44 | > 2^32 | no | no | yes | yes | yes |
+ * ----------------------------------------------------------|------------------
+ *
+ * To mount large volumes as ntfs one should use large cluster size (up to 2M)
+ * The maximum volume size in this case is 2^32 * 2^21 = 2^53 = 8P
+ *
+ * ntfs limits, cluster size is 2M (2^31)
+ * -----------------------------------------------------------------------------
+ * | < 8P, 2^54 | < 2^32 | yes | yes | yes | yes | yes |
+ * | > 8P, 2^54 | > 2^32 | no | no | yes | yes | yes |
+ * ----------------------------------------------------------|------------------
+ *
*/
#include <linux/blkdev.h>
@@ -223,11 +247,14 @@ enum Opt {
Opt_force,
Opt_sparse,
Opt_nohidden,
+ Opt_hide_dot_files,
+ Opt_windows_names,
Opt_showmeta,
Opt_acl,
Opt_iocharset,
Opt_prealloc,
Opt_noacsrules,
+ Opt_nocase,
Opt_err,
};
@@ -242,10 +269,13 @@ static const struct fs_parameter_spec ntfs_fs_parameters[] = {
fsparam_flag_no("force", Opt_force),
fsparam_flag_no("sparse", Opt_sparse),
fsparam_flag_no("hidden", Opt_nohidden),
+ fsparam_flag_no("hide_dot_files", Opt_hide_dot_files),
+ fsparam_flag_no("windows_names", Opt_windows_names),
fsparam_flag_no("acl", Opt_acl),
fsparam_flag_no("showmeta", Opt_showmeta),
fsparam_flag_no("prealloc", Opt_prealloc),
fsparam_flag_no("acsrules", Opt_noacsrules),
+ fsparam_flag_no("nocase", Opt_nocase),
fsparam_string("iocharset", Opt_iocharset),
{}
};
@@ -330,6 +360,12 @@ static int ntfs_fs_parse_param(struct fs_context *fc,
case Opt_nohidden:
opts->nohidden = result.negated ? 1 : 0;
break;
+ case Opt_hide_dot_files:
+ opts->hide_dot_files = result.negated ? 0 : 1;
+ break;
+ case Opt_windows_names:
+ opts->windows_names = result.negated ? 0 : 1;
+ break;
case Opt_acl:
if (!result.negated)
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
@@ -354,6 +390,9 @@ static int ntfs_fs_parse_param(struct fs_context *fc,
case Opt_noacsrules:
opts->noacsrules = result.negated ? 1 : 0;
break;
+ case Opt_nocase:
+ opts->nocase = result.negated ? 1 : 0;
+ break;
default:
/* Should not be here unless we forget add case. */
return -EINVAL;
@@ -406,27 +445,18 @@ static struct inode *ntfs_alloc_inode(struct super_block *sb)
return NULL;
memset(ni, 0, offsetof(struct ntfs_inode, vfs_inode));
-
mutex_init(&ni->ni_lock);
-
return &ni->vfs_inode;
}
-static void ntfs_i_callback(struct rcu_head *head)
+static void ntfs_free_inode(struct inode *inode)
{
- struct inode *inode = container_of(head, struct inode, i_rcu);
struct ntfs_inode *ni = ntfs_i(inode);
mutex_destroy(&ni->ni_lock);
-
kmem_cache_free(ntfs_inode_cachep, ni);
}
-static void ntfs_destroy_inode(struct inode *inode)
-{
- call_rcu(&inode->i_rcu, ntfs_i_callback);
-}
-
static void init_once(void *foo)
{
struct ntfs_inode *ni = foo;
@@ -519,9 +549,9 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root)
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);
+ seq_printf(m, ",fmask=%04o", opts->fs_fmask_inv ^ 0xffff);
if (opts->dmask)
- seq_printf(m, ",dmask=%04o", ~opts->fs_dmask_inv);
+ seq_printf(m, ",dmask=%04o", opts->fs_dmask_inv ^ 0xffff);
if (opts->nls)
seq_printf(m, ",iocharset=%s", opts->nls->charset);
else
@@ -536,6 +566,10 @@ static int ntfs_show_options(struct seq_file *m, struct dentry *root)
seq_puts(m, ",showmeta");
if (opts->nohidden)
seq_puts(m, ",nohidden");
+ if (opts->windows_names)
+ seq_puts(m, ",windows_names");
+ if (opts->hide_dot_files)
+ seq_puts(m, ",hide_dot_files");
if (opts->force)
seq_puts(m, ",force");
if (opts->noacsrules)
@@ -592,7 +626,7 @@ static int ntfs_sync_fs(struct super_block *sb, int wait)
static const struct super_operations ntfs_sops = {
.alloc_inode = ntfs_alloc_inode,
- .destroy_inode = ntfs_destroy_inode,
+ .free_inode = ntfs_free_inode,
.evict_inode = ntfs_evict_inode,
.put_super = ntfs_put_super,
.statfs = ntfs_statfs,
@@ -672,7 +706,7 @@ static u32 true_sectors_per_clst(const struct NTFS_BOOT *boot)
if (boot->sectors_per_clusters <= 0x80)
return boot->sectors_per_clusters;
if (boot->sectors_per_clusters >= 0xf4) /* limit shift to 2MB max */
- return 1U << (0 - boot->sectors_per_clusters);
+ return 1U << -(s8)boot->sectors_per_clusters;
return -EINVAL;
}
@@ -789,7 +823,7 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
: (u32)boot->record_size
<< sbi->cluster_bits;
- if (record_size > MAXIMUM_BYTES_PER_MFT)
+ if (record_size > MAXIMUM_BYTES_PER_MFT || record_size < SECTOR_SIZE)
goto out;
sbi->record_bits = blksize_bits(record_size);
@@ -896,7 +930,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
struct block_device *bdev = sb->s_bdev;
struct inode *inode;
struct ntfs_inode *ni;
- size_t i, tt;
+ size_t i, tt, bad_len, bad_frags;
CLST vcn, lcn, len;
struct ATTRIB *attr;
const struct VOLUME_INFO *info;
@@ -916,6 +950,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 = sbi->options->nocase ? &ntfs_dentry_ops : NULL;
sbi->options->nls = ntfs_load_nls(sbi->options->nls_name);
if (IS_ERR(sbi->options->nls)) {
@@ -1065,30 +1100,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
sbi->mft.ni = ni;
- /* Load $BadClus. */
- ref.low = cpu_to_le32(MFT_REC_BADCLUST);
- ref.seq = cpu_to_le16(MFT_REC_BADCLUST);
- inode = ntfs_iget5(sb, &ref, &NAME_BADCLUS);
- if (IS_ERR(inode)) {
- ntfs_err(sb, "Failed to load $BadClus.");
- err = PTR_ERR(inode);
- goto out;
- }
-
- ni = ntfs_i(inode);
-
- for (i = 0; run_get_entry(&ni->file.run, i, &vcn, &lcn, &len); i++) {
- if (lcn == SPARSE_LCN)
- continue;
-
- if (!sbi->bad_clusters)
- ntfs_notice(sb, "Volume contains bad blocks");
-
- sbi->bad_clusters += len;
- }
-
- iput(inode);
-
/* Load $Bitmap. */
ref.low = cpu_to_le32(MFT_REC_BITMAP);
ref.seq = cpu_to_le16(MFT_REC_BITMAP);
@@ -1126,6 +1137,44 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (err)
goto out;
+ /* Load $BadClus. */
+ ref.low = cpu_to_le32(MFT_REC_BADCLUST);
+ 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 (%d).", err);
+ goto out;
+ }
+
+ ni = ntfs_i(inode);
+ bad_len = bad_frags = 0;
+ for (i = 0; run_get_entry(&ni->file.run, i, &vcn, &lcn, &len); i++) {
+ if (lcn == SPARSE_LCN)
+ continue;
+
+ bad_len += len;
+ bad_frags += 1;
+ if (sb_rdonly(sb))
+ continue;
+
+ if (wnd_set_used_safe(&sbi->used.bitmap, lcn, len, &tt) || tt) {
+ /* Bad blocks marked as free in bitmap. */
+ ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
+ }
+ }
+ if (bad_len) {
+ /*
+ * Notice about bad blocks.
+ * In normal cases these blocks are marked as used in bitmap.
+ * And we never allocate space in it.
+ */
+ ntfs_notice(sb,
+ "Volume contains %zu bad blocks in %zu fragments.",
+ bad_len, bad_frags);
+ }
+ iput(inode);
+
/* Load $AttrDef. */
ref.low = cpu_to_le32(MFT_REC_ATTR);
ref.seq = cpu_to_le16(MFT_REC_ATTR);
@@ -1141,7 +1190,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
goto put_inode_out;
}
bytes = inode->i_size;
- sbi->def_table = t = kmalloc(bytes, GFP_NOFS);
+ sbi->def_table = t = kmalloc(bytes, GFP_NOFS | __GFP_NOWARN);
if (!t) {
err = -ENOMEM;
goto put_inode_out;
@@ -1260,9 +1309,9 @@ load_root:
ref.low = cpu_to_le32(MFT_REC_ROOT);
ref.seq = cpu_to_le16(MFT_REC_ROOT);
inode = ntfs_iget5(sb, &ref, &NAME_ROOT);
- if (IS_ERR(inode)) {
+ if (IS_ERR(inode) || !inode->i_op) {
ntfs_err(sb, "Failed to load root.");
- err = PTR_ERR(inode);
+ err = IS_ERR(inode) ? PTR_ERR(inode) : -EINVAL;
goto out;
}
@@ -1281,6 +1330,7 @@ out:
* Free resources here.
* ntfs_fs_free will be called with fc->s_fs_info = NULL
*/
+ put_mount_options(sbi->options);
put_ntfs(sbi);
sb->s_fs_info = NULL;
@@ -1488,11 +1538,8 @@ out1:
static void __exit exit_ntfs_fs(void)
{
- if (ntfs_inode_cachep) {
- rcu_barrier();
- kmem_cache_destroy(ntfs_inode_cachep);
- }
-
+ rcu_barrier();
+ kmem_cache_destroy(ntfs_inode_cachep);
unregister_filesystem(&ntfs_fs_type);
ntfs3_exit_bitmap();
}