162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * terminology 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * cluster - allocation unit - 512,1K,2K,4K,...,2M 1062306a36Sopenharmony_ci * vcn - virtual cluster number - Offset inside the file in clusters. 1162306a36Sopenharmony_ci * vbo - virtual byte offset - Offset inside the file in bytes. 1262306a36Sopenharmony_ci * lcn - logical cluster number - 0 based cluster in clusters heap. 1362306a36Sopenharmony_ci * lbo - logical byte offset - Absolute position inside volume. 1462306a36Sopenharmony_ci * run - maps VCN to LCN - Stored in attributes in packed form. 1562306a36Sopenharmony_ci * attr - attribute segment - std/name/data etc records inside MFT. 1662306a36Sopenharmony_ci * mi - MFT inode - One MFT record(usually 1024 bytes or 4K), consists of attributes. 1762306a36Sopenharmony_ci * ni - NTFS inode - Extends linux inode. consists of one or more mft inodes. 1862306a36Sopenharmony_ci * index - unit inside directory - 2K, 4K, <=page size, does not depend on cluster size. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * WSL - Windows Subsystem for Linux 2162306a36Sopenharmony_ci * https://docs.microsoft.com/en-us/windows/wsl/file-permissions 2262306a36Sopenharmony_ci * It stores uid/gid/mode/dev in xattr 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * ntfs allows up to 2^64 clusters per volume. 2562306a36Sopenharmony_ci * It means you should use 64 bits lcn to operate with ntfs. 2662306a36Sopenharmony_ci * Implementation of ntfs.sys uses only 32 bits lcn. 2762306a36Sopenharmony_ci * Default ntfs3 uses 32 bits lcn too. 2862306a36Sopenharmony_ci * ntfs3 built with CONFIG_NTFS3_64BIT_CLUSTER (ntfs3_64) uses 64 bits per lcn. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * ntfs limits, cluster size is 4K (2^12) 3262306a36Sopenharmony_ci * ----------------------------------------------------------------------------- 3362306a36Sopenharmony_ci * | Volume size | Clusters | ntfs.sys | ntfs3 | ntfs3_64 | mkntfs | chkdsk | 3462306a36Sopenharmony_ci * ----------------------------------------------------------------------------- 3562306a36Sopenharmony_ci * | < 16T, 2^44 | < 2^32 | yes | yes | yes | yes | yes | 3662306a36Sopenharmony_ci * | > 16T, 2^44 | > 2^32 | no | no | yes | yes | yes | 3762306a36Sopenharmony_ci * ----------------------------------------------------------|------------------ 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * To mount large volumes as ntfs one should use large cluster size (up to 2M) 4062306a36Sopenharmony_ci * The maximum volume size in this case is 2^32 * 2^21 = 2^53 = 8P 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * ntfs limits, cluster size is 2M (2^21) 4362306a36Sopenharmony_ci * ----------------------------------------------------------------------------- 4462306a36Sopenharmony_ci * | < 8P, 2^53 | < 2^32 | yes | yes | yes | yes | yes | 4562306a36Sopenharmony_ci * | > 8P, 2^53 | > 2^32 | no | no | yes | yes | yes | 4662306a36Sopenharmony_ci * ----------------------------------------------------------|------------------ 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#include <linux/blkdev.h> 5162306a36Sopenharmony_ci#include <linux/buffer_head.h> 5262306a36Sopenharmony_ci#include <linux/exportfs.h> 5362306a36Sopenharmony_ci#include <linux/fs.h> 5462306a36Sopenharmony_ci#include <linux/fs_context.h> 5562306a36Sopenharmony_ci#include <linux/fs_parser.h> 5662306a36Sopenharmony_ci#include <linux/log2.h> 5762306a36Sopenharmony_ci#include <linux/minmax.h> 5862306a36Sopenharmony_ci#include <linux/module.h> 5962306a36Sopenharmony_ci#include <linux/nls.h> 6062306a36Sopenharmony_ci#include <linux/proc_fs.h> 6162306a36Sopenharmony_ci#include <linux/seq_file.h> 6262306a36Sopenharmony_ci#include <linux/statfs.h> 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#include "debug.h" 6562306a36Sopenharmony_ci#include "ntfs.h" 6662306a36Sopenharmony_ci#include "ntfs_fs.h" 6762306a36Sopenharmony_ci#ifdef CONFIG_NTFS3_LZX_XPRESS 6862306a36Sopenharmony_ci#include "lib/lib.h" 6962306a36Sopenharmony_ci#endif 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#ifdef CONFIG_PRINTK 7262306a36Sopenharmony_ci/* 7362306a36Sopenharmony_ci * ntfs_printk - Trace warnings/notices/errors. 7462306a36Sopenharmony_ci * 7562306a36Sopenharmony_ci * Thanks Joe Perches <joe@perches.com> for implementation 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_civoid ntfs_printk(const struct super_block *sb, const char *fmt, ...) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct va_format vaf; 8062306a36Sopenharmony_ci va_list args; 8162306a36Sopenharmony_ci int level; 8262306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* Should we use different ratelimits for warnings/notices/errors? */ 8562306a36Sopenharmony_ci if (!___ratelimit(&sbi->msg_ratelimit, "ntfs3")) 8662306a36Sopenharmony_ci return; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci va_start(args, fmt); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci level = printk_get_level(fmt); 9162306a36Sopenharmony_ci vaf.fmt = printk_skip_level(fmt); 9262306a36Sopenharmony_ci vaf.va = &args; 9362306a36Sopenharmony_ci printk("%c%cntfs3: %s: %pV\n", KERN_SOH_ASCII, level, sb->s_id, &vaf); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci va_end(args); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic char s_name_buf[512]; 9962306a36Sopenharmony_cistatic atomic_t s_name_buf_cnt = ATOMIC_INIT(1); // 1 means 'free s_name_buf'. 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* 10262306a36Sopenharmony_ci * ntfs_inode_printk 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * Print warnings/notices/errors about inode using name or inode number. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_civoid ntfs_inode_printk(struct inode *inode, const char *fmt, ...) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 10962306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 11062306a36Sopenharmony_ci char *name; 11162306a36Sopenharmony_ci va_list args; 11262306a36Sopenharmony_ci struct va_format vaf; 11362306a36Sopenharmony_ci int level; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (!___ratelimit(&sbi->msg_ratelimit, "ntfs3")) 11662306a36Sopenharmony_ci return; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* Use static allocated buffer, if possible. */ 11962306a36Sopenharmony_ci name = atomic_dec_and_test(&s_name_buf_cnt) ? 12062306a36Sopenharmony_ci s_name_buf : 12162306a36Sopenharmony_ci kmalloc(sizeof(s_name_buf), GFP_NOFS); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (name) { 12462306a36Sopenharmony_ci struct dentry *de = d_find_alias(inode); 12562306a36Sopenharmony_ci const u32 name_len = ARRAY_SIZE(s_name_buf) - 1; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (de) { 12862306a36Sopenharmony_ci spin_lock(&de->d_lock); 12962306a36Sopenharmony_ci snprintf(name, name_len, " \"%s\"", de->d_name.name); 13062306a36Sopenharmony_ci spin_unlock(&de->d_lock); 13162306a36Sopenharmony_ci name[name_len] = 0; /* To be sure. */ 13262306a36Sopenharmony_ci } else { 13362306a36Sopenharmony_ci name[0] = 0; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci dput(de); /* Cocci warns if placed in branch "if (de)" */ 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci va_start(args, fmt); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci level = printk_get_level(fmt); 14162306a36Sopenharmony_ci vaf.fmt = printk_skip_level(fmt); 14262306a36Sopenharmony_ci vaf.va = &args; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci printk("%c%cntfs3: %s: ino=%lx,%s %pV\n", KERN_SOH_ASCII, level, 14562306a36Sopenharmony_ci sb->s_id, inode->i_ino, name ? name : "", &vaf); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci va_end(args); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci atomic_inc(&s_name_buf_cnt); 15062306a36Sopenharmony_ci if (name != s_name_buf) 15162306a36Sopenharmony_ci kfree(name); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci#endif 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* 15662306a36Sopenharmony_ci * Shared memory struct. 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * On-disk ntfs's upcase table is created by ntfs formatter. 15962306a36Sopenharmony_ci * 'upcase' table is 128K bytes of memory. 16062306a36Sopenharmony_ci * We should read it into memory when mounting. 16162306a36Sopenharmony_ci * Several ntfs volumes likely use the same 'upcase' table. 16262306a36Sopenharmony_ci * It is good idea to share in-memory 'upcase' table between different volumes. 16362306a36Sopenharmony_ci * Unfortunately winxp/vista/win7 use different upcase tables. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(s_shared_lock); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic struct { 16862306a36Sopenharmony_ci void *ptr; 16962306a36Sopenharmony_ci u32 len; 17062306a36Sopenharmony_ci int cnt; 17162306a36Sopenharmony_ci} s_shared[8]; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* 17462306a36Sopenharmony_ci * ntfs_set_shared 17562306a36Sopenharmony_ci * 17662306a36Sopenharmony_ci * Return: 17762306a36Sopenharmony_ci * * @ptr - If pointer was saved in shared memory. 17862306a36Sopenharmony_ci * * NULL - If pointer was not shared. 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_civoid *ntfs_set_shared(void *ptr, u32 bytes) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci void *ret = NULL; 18362306a36Sopenharmony_ci int i, j = -1; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci spin_lock(&s_shared_lock); 18662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s_shared); i++) { 18762306a36Sopenharmony_ci if (!s_shared[i].cnt) { 18862306a36Sopenharmony_ci j = i; 18962306a36Sopenharmony_ci } else if (bytes == s_shared[i].len && 19062306a36Sopenharmony_ci !memcmp(s_shared[i].ptr, ptr, bytes)) { 19162306a36Sopenharmony_ci s_shared[i].cnt += 1; 19262306a36Sopenharmony_ci ret = s_shared[i].ptr; 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (!ret && j != -1) { 19862306a36Sopenharmony_ci s_shared[j].ptr = ptr; 19962306a36Sopenharmony_ci s_shared[j].len = bytes; 20062306a36Sopenharmony_ci s_shared[j].cnt = 1; 20162306a36Sopenharmony_ci ret = ptr; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci spin_unlock(&s_shared_lock); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return ret; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/* 20962306a36Sopenharmony_ci * ntfs_put_shared 21062306a36Sopenharmony_ci * 21162306a36Sopenharmony_ci * Return: 21262306a36Sopenharmony_ci * * @ptr - If pointer is not shared anymore. 21362306a36Sopenharmony_ci * * NULL - If pointer is still shared. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_civoid *ntfs_put_shared(void *ptr) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci void *ret = ptr; 21862306a36Sopenharmony_ci int i; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci spin_lock(&s_shared_lock); 22162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(s_shared); i++) { 22262306a36Sopenharmony_ci if (s_shared[i].cnt && s_shared[i].ptr == ptr) { 22362306a36Sopenharmony_ci if (--s_shared[i].cnt) 22462306a36Sopenharmony_ci ret = NULL; 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci spin_unlock(&s_shared_lock); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return ret; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic inline void put_mount_options(struct ntfs_mount_options *options) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci kfree(options->nls_name); 23662306a36Sopenharmony_ci unload_nls(options->nls); 23762306a36Sopenharmony_ci kfree(options); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cienum Opt { 24162306a36Sopenharmony_ci Opt_uid, 24262306a36Sopenharmony_ci Opt_gid, 24362306a36Sopenharmony_ci Opt_umask, 24462306a36Sopenharmony_ci Opt_dmask, 24562306a36Sopenharmony_ci Opt_fmask, 24662306a36Sopenharmony_ci Opt_immutable, 24762306a36Sopenharmony_ci Opt_discard, 24862306a36Sopenharmony_ci Opt_force, 24962306a36Sopenharmony_ci Opt_sparse, 25062306a36Sopenharmony_ci Opt_nohidden, 25162306a36Sopenharmony_ci Opt_hide_dot_files, 25262306a36Sopenharmony_ci Opt_windows_names, 25362306a36Sopenharmony_ci Opt_showmeta, 25462306a36Sopenharmony_ci Opt_acl, 25562306a36Sopenharmony_ci Opt_iocharset, 25662306a36Sopenharmony_ci Opt_prealloc, 25762306a36Sopenharmony_ci Opt_nocase, 25862306a36Sopenharmony_ci Opt_err, 25962306a36Sopenharmony_ci}; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci// clang-format off 26262306a36Sopenharmony_cistatic const struct fs_parameter_spec ntfs_fs_parameters[] = { 26362306a36Sopenharmony_ci fsparam_u32("uid", Opt_uid), 26462306a36Sopenharmony_ci fsparam_u32("gid", Opt_gid), 26562306a36Sopenharmony_ci fsparam_u32oct("umask", Opt_umask), 26662306a36Sopenharmony_ci fsparam_u32oct("dmask", Opt_dmask), 26762306a36Sopenharmony_ci fsparam_u32oct("fmask", Opt_fmask), 26862306a36Sopenharmony_ci fsparam_flag_no("sys_immutable", Opt_immutable), 26962306a36Sopenharmony_ci fsparam_flag_no("discard", Opt_discard), 27062306a36Sopenharmony_ci fsparam_flag_no("force", Opt_force), 27162306a36Sopenharmony_ci fsparam_flag_no("sparse", Opt_sparse), 27262306a36Sopenharmony_ci fsparam_flag_no("hidden", Opt_nohidden), 27362306a36Sopenharmony_ci fsparam_flag_no("hide_dot_files", Opt_hide_dot_files), 27462306a36Sopenharmony_ci fsparam_flag_no("windows_names", Opt_windows_names), 27562306a36Sopenharmony_ci fsparam_flag_no("showmeta", Opt_showmeta), 27662306a36Sopenharmony_ci fsparam_flag_no("acl", Opt_acl), 27762306a36Sopenharmony_ci fsparam_string("iocharset", Opt_iocharset), 27862306a36Sopenharmony_ci fsparam_flag_no("prealloc", Opt_prealloc), 27962306a36Sopenharmony_ci fsparam_flag_no("nocase", Opt_nocase), 28062306a36Sopenharmony_ci {} 28162306a36Sopenharmony_ci}; 28262306a36Sopenharmony_ci// clang-format on 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/* 28562306a36Sopenharmony_ci * Load nls table or if @nls is utf8 then return NULL. 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * It is good idea to use here "const char *nls". 28862306a36Sopenharmony_ci * But load_nls accepts "char*". 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_cistatic struct nls_table *ntfs_load_nls(char *nls) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct nls_table *ret; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (!nls) 29562306a36Sopenharmony_ci nls = CONFIG_NLS_DEFAULT; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (strcmp(nls, "utf8") == 0) 29862306a36Sopenharmony_ci return NULL; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (strcmp(nls, CONFIG_NLS_DEFAULT) == 0) 30162306a36Sopenharmony_ci return load_nls_default(); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ret = load_nls(nls); 30462306a36Sopenharmony_ci if (ret) 30562306a36Sopenharmony_ci return ret; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int ntfs_fs_parse_param(struct fs_context *fc, 31162306a36Sopenharmony_ci struct fs_parameter *param) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct ntfs_mount_options *opts = fc->fs_private; 31462306a36Sopenharmony_ci struct fs_parse_result result; 31562306a36Sopenharmony_ci int opt; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci opt = fs_parse(fc, ntfs_fs_parameters, param, &result); 31862306a36Sopenharmony_ci if (opt < 0) 31962306a36Sopenharmony_ci return opt; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci switch (opt) { 32262306a36Sopenharmony_ci case Opt_uid: 32362306a36Sopenharmony_ci opts->fs_uid = make_kuid(current_user_ns(), result.uint_32); 32462306a36Sopenharmony_ci if (!uid_valid(opts->fs_uid)) 32562306a36Sopenharmony_ci return invalf(fc, "ntfs3: Invalid value for uid."); 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci case Opt_gid: 32862306a36Sopenharmony_ci opts->fs_gid = make_kgid(current_user_ns(), result.uint_32); 32962306a36Sopenharmony_ci if (!gid_valid(opts->fs_gid)) 33062306a36Sopenharmony_ci return invalf(fc, "ntfs3: Invalid value for gid."); 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci case Opt_umask: 33362306a36Sopenharmony_ci if (result.uint_32 & ~07777) 33462306a36Sopenharmony_ci return invalf(fc, "ntfs3: Invalid value for umask."); 33562306a36Sopenharmony_ci opts->fs_fmask_inv = ~result.uint_32; 33662306a36Sopenharmony_ci opts->fs_dmask_inv = ~result.uint_32; 33762306a36Sopenharmony_ci opts->fmask = 1; 33862306a36Sopenharmony_ci opts->dmask = 1; 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci case Opt_dmask: 34162306a36Sopenharmony_ci if (result.uint_32 & ~07777) 34262306a36Sopenharmony_ci return invalf(fc, "ntfs3: Invalid value for dmask."); 34362306a36Sopenharmony_ci opts->fs_dmask_inv = ~result.uint_32; 34462306a36Sopenharmony_ci opts->dmask = 1; 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci case Opt_fmask: 34762306a36Sopenharmony_ci if (result.uint_32 & ~07777) 34862306a36Sopenharmony_ci return invalf(fc, "ntfs3: Invalid value for fmask."); 34962306a36Sopenharmony_ci opts->fs_fmask_inv = ~result.uint_32; 35062306a36Sopenharmony_ci opts->fmask = 1; 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci case Opt_immutable: 35362306a36Sopenharmony_ci opts->sys_immutable = result.negated ? 0 : 1; 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci case Opt_discard: 35662306a36Sopenharmony_ci opts->discard = result.negated ? 0 : 1; 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci case Opt_force: 35962306a36Sopenharmony_ci opts->force = result.negated ? 0 : 1; 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci case Opt_sparse: 36262306a36Sopenharmony_ci opts->sparse = result.negated ? 0 : 1; 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci case Opt_nohidden: 36562306a36Sopenharmony_ci opts->nohidden = result.negated ? 1 : 0; 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci case Opt_hide_dot_files: 36862306a36Sopenharmony_ci opts->hide_dot_files = result.negated ? 0 : 1; 36962306a36Sopenharmony_ci break; 37062306a36Sopenharmony_ci case Opt_windows_names: 37162306a36Sopenharmony_ci opts->windows_names = result.negated ? 0 : 1; 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci case Opt_showmeta: 37462306a36Sopenharmony_ci opts->showmeta = result.negated ? 0 : 1; 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci case Opt_acl: 37762306a36Sopenharmony_ci if (!result.negated) 37862306a36Sopenharmony_ci#ifdef CONFIG_NTFS3_FS_POSIX_ACL 37962306a36Sopenharmony_ci fc->sb_flags |= SB_POSIXACL; 38062306a36Sopenharmony_ci#else 38162306a36Sopenharmony_ci return invalf( 38262306a36Sopenharmony_ci fc, "ntfs3: Support for ACL not compiled in!"); 38362306a36Sopenharmony_ci#endif 38462306a36Sopenharmony_ci else 38562306a36Sopenharmony_ci fc->sb_flags &= ~SB_POSIXACL; 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci case Opt_iocharset: 38862306a36Sopenharmony_ci kfree(opts->nls_name); 38962306a36Sopenharmony_ci opts->nls_name = param->string; 39062306a36Sopenharmony_ci param->string = NULL; 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci case Opt_prealloc: 39362306a36Sopenharmony_ci opts->prealloc = result.negated ? 0 : 1; 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci case Opt_nocase: 39662306a36Sopenharmony_ci opts->nocase = result.negated ? 1 : 0; 39762306a36Sopenharmony_ci break; 39862306a36Sopenharmony_ci default: 39962306a36Sopenharmony_ci /* Should not be here unless we forget add case. */ 40062306a36Sopenharmony_ci return -EINVAL; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int ntfs_fs_reconfigure(struct fs_context *fc) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct super_block *sb = fc->root->d_sb; 40862306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 40962306a36Sopenharmony_ci struct ntfs_mount_options *new_opts = fc->fs_private; 41062306a36Sopenharmony_ci int ro_rw; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci ro_rw = sb_rdonly(sb) && !(fc->sb_flags & SB_RDONLY); 41362306a36Sopenharmony_ci if (ro_rw && (sbi->flags & NTFS_FLAGS_NEED_REPLAY)) { 41462306a36Sopenharmony_ci errorf(fc, 41562306a36Sopenharmony_ci "ntfs3: Couldn't remount rw because journal is not replayed. Please umount/remount instead\n"); 41662306a36Sopenharmony_ci return -EINVAL; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci new_opts->nls = ntfs_load_nls(new_opts->nls_name); 42062306a36Sopenharmony_ci if (IS_ERR(new_opts->nls)) { 42162306a36Sopenharmony_ci new_opts->nls = NULL; 42262306a36Sopenharmony_ci errorf(fc, "ntfs3: Cannot load iocharset %s", 42362306a36Sopenharmony_ci new_opts->nls_name); 42462306a36Sopenharmony_ci return -EINVAL; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci if (new_opts->nls != sbi->options->nls) 42762306a36Sopenharmony_ci return invalf( 42862306a36Sopenharmony_ci fc, 42962306a36Sopenharmony_ci "ntfs3: Cannot use different iocharset when remounting!"); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci sync_filesystem(sb); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (ro_rw && (sbi->volume.flags & VOLUME_FLAG_DIRTY) && 43462306a36Sopenharmony_ci !new_opts->force) { 43562306a36Sopenharmony_ci errorf(fc, 43662306a36Sopenharmony_ci "ntfs3: Volume is dirty and \"force\" flag is not set!"); 43762306a36Sopenharmony_ci return -EINVAL; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci swap(sbi->options, fc->fs_private); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 44662306a36Sopenharmony_cistatic struct proc_dir_entry *proc_info_root; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci/* 44962306a36Sopenharmony_ci * ntfs3_volinfo: 45062306a36Sopenharmony_ci * 45162306a36Sopenharmony_ci * The content of /proc/fs/ntfs3/<dev>/volinfo 45262306a36Sopenharmony_ci * 45362306a36Sopenharmony_ci * ntfs3.1 45462306a36Sopenharmony_ci * cluster size 45562306a36Sopenharmony_ci * number of clusters 45662306a36Sopenharmony_ci * total number of mft records 45762306a36Sopenharmony_ci * number of used mft records ~= number of files + folders 45862306a36Sopenharmony_ci * real state of ntfs "dirty"/"clean" 45962306a36Sopenharmony_ci * current state of ntfs "dirty"/"clean" 46062306a36Sopenharmony_ci*/ 46162306a36Sopenharmony_cistatic int ntfs3_volinfo(struct seq_file *m, void *o) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct super_block *sb = m->private; 46462306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci seq_printf(m, "ntfs%d.%d\n%u\n%zu\n\%zu\n%zu\n%s\n%s\n", 46762306a36Sopenharmony_ci sbi->volume.major_ver, sbi->volume.minor_ver, 46862306a36Sopenharmony_ci sbi->cluster_size, sbi->used.bitmap.nbits, 46962306a36Sopenharmony_ci sbi->mft.bitmap.nbits, 47062306a36Sopenharmony_ci sbi->mft.bitmap.nbits - wnd_zeroes(&sbi->mft.bitmap), 47162306a36Sopenharmony_ci sbi->volume.real_dirty ? "dirty" : "clean", 47262306a36Sopenharmony_ci (sbi->volume.flags & VOLUME_FLAG_DIRTY) ? "dirty" : "clean"); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int ntfs3_volinfo_open(struct inode *inode, struct file *file) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci return single_open(file, ntfs3_volinfo, pde_data(inode)); 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci/* read /proc/fs/ntfs3/<dev>/label */ 48362306a36Sopenharmony_cistatic int ntfs3_label_show(struct seq_file *m, void *o) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct super_block *sb = m->private; 48662306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci seq_printf(m, "%s\n", sbi->volume.label); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci return 0; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci/* write /proc/fs/ntfs3/<dev>/label */ 49462306a36Sopenharmony_cistatic ssize_t ntfs3_label_write(struct file *file, const char __user *buffer, 49562306a36Sopenharmony_ci size_t count, loff_t *ppos) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci int err; 49862306a36Sopenharmony_ci struct super_block *sb = pde_data(file_inode(file)); 49962306a36Sopenharmony_ci ssize_t ret = count; 50062306a36Sopenharmony_ci u8 *label; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (sb_rdonly(sb)) 50362306a36Sopenharmony_ci return -EROFS; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci label = kmalloc(count, GFP_NOFS); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (!label) 50862306a36Sopenharmony_ci return -ENOMEM; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (copy_from_user(label, buffer, ret)) { 51162306a36Sopenharmony_ci ret = -EFAULT; 51262306a36Sopenharmony_ci goto out; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci while (ret > 0 && label[ret - 1] == '\n') 51562306a36Sopenharmony_ci ret -= 1; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci err = ntfs_set_label(sb->s_fs_info, label, ret); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (err < 0) { 52062306a36Sopenharmony_ci ntfs_err(sb, "failed (%d) to write label", err); 52162306a36Sopenharmony_ci ret = err; 52262306a36Sopenharmony_ci goto out; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci *ppos += count; 52662306a36Sopenharmony_ci ret = count; 52762306a36Sopenharmony_ciout: 52862306a36Sopenharmony_ci kfree(label); 52962306a36Sopenharmony_ci return ret; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic int ntfs3_label_open(struct inode *inode, struct file *file) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci return single_open(file, ntfs3_label_show, pde_data(inode)); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic const struct proc_ops ntfs3_volinfo_fops = { 53862306a36Sopenharmony_ci .proc_read = seq_read, 53962306a36Sopenharmony_ci .proc_lseek = seq_lseek, 54062306a36Sopenharmony_ci .proc_release = single_release, 54162306a36Sopenharmony_ci .proc_open = ntfs3_volinfo_open, 54262306a36Sopenharmony_ci}; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic const struct proc_ops ntfs3_label_fops = { 54562306a36Sopenharmony_ci .proc_read = seq_read, 54662306a36Sopenharmony_ci .proc_lseek = seq_lseek, 54762306a36Sopenharmony_ci .proc_release = single_release, 54862306a36Sopenharmony_ci .proc_open = ntfs3_label_open, 54962306a36Sopenharmony_ci .proc_write = ntfs3_label_write, 55062306a36Sopenharmony_ci}; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci#endif 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic struct kmem_cache *ntfs_inode_cachep; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic struct inode *ntfs_alloc_inode(struct super_block *sb) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct ntfs_inode *ni = alloc_inode_sb(sb, ntfs_inode_cachep, GFP_NOFS); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (!ni) 56162306a36Sopenharmony_ci return NULL; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci memset(ni, 0, offsetof(struct ntfs_inode, vfs_inode)); 56462306a36Sopenharmony_ci mutex_init(&ni->ni_lock); 56562306a36Sopenharmony_ci return &ni->vfs_inode; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic void ntfs_free_inode(struct inode *inode) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct ntfs_inode *ni = ntfs_i(inode); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci mutex_destroy(&ni->ni_lock); 57362306a36Sopenharmony_ci kmem_cache_free(ntfs_inode_cachep, ni); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic void init_once(void *foo) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct ntfs_inode *ni = foo; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci inode_init_once(&ni->vfs_inode); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci/* 58462306a36Sopenharmony_ci * Noinline to reduce binary size. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_cistatic noinline void ntfs3_put_sbi(struct ntfs_sb_info *sbi) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci wnd_close(&sbi->mft.bitmap); 58962306a36Sopenharmony_ci wnd_close(&sbi->used.bitmap); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (sbi->mft.ni) { 59262306a36Sopenharmony_ci iput(&sbi->mft.ni->vfs_inode); 59362306a36Sopenharmony_ci sbi->mft.ni = NULL; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (sbi->security.ni) { 59762306a36Sopenharmony_ci iput(&sbi->security.ni->vfs_inode); 59862306a36Sopenharmony_ci sbi->security.ni = NULL; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (sbi->reparse.ni) { 60262306a36Sopenharmony_ci iput(&sbi->reparse.ni->vfs_inode); 60362306a36Sopenharmony_ci sbi->reparse.ni = NULL; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (sbi->objid.ni) { 60762306a36Sopenharmony_ci iput(&sbi->objid.ni->vfs_inode); 60862306a36Sopenharmony_ci sbi->objid.ni = NULL; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (sbi->volume.ni) { 61262306a36Sopenharmony_ci iput(&sbi->volume.ni->vfs_inode); 61362306a36Sopenharmony_ci sbi->volume.ni = NULL; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci ntfs_update_mftmirr(sbi, 0); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci indx_clear(&sbi->security.index_sii); 61962306a36Sopenharmony_ci indx_clear(&sbi->security.index_sdh); 62062306a36Sopenharmony_ci indx_clear(&sbi->reparse.index_r); 62162306a36Sopenharmony_ci indx_clear(&sbi->objid.index_o); 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic void ntfs3_free_sbi(struct ntfs_sb_info *sbi) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci kfree(sbi->new_rec); 62762306a36Sopenharmony_ci kvfree(ntfs_put_shared(sbi->upcase)); 62862306a36Sopenharmony_ci kvfree(sbi->def_table); 62962306a36Sopenharmony_ci kfree(sbi->compress.lznt); 63062306a36Sopenharmony_ci#ifdef CONFIG_NTFS3_LZX_XPRESS 63162306a36Sopenharmony_ci xpress_free_decompressor(sbi->compress.xpress); 63262306a36Sopenharmony_ci lzx_free_decompressor(sbi->compress.lzx); 63362306a36Sopenharmony_ci#endif 63462306a36Sopenharmony_ci kfree(sbi); 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic void ntfs_put_super(struct super_block *sb) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 64262306a36Sopenharmony_ci // Remove /proc/fs/ntfs3/.. 64362306a36Sopenharmony_ci if (sbi->procdir) { 64462306a36Sopenharmony_ci remove_proc_entry("label", sbi->procdir); 64562306a36Sopenharmony_ci remove_proc_entry("volinfo", sbi->procdir); 64662306a36Sopenharmony_ci remove_proc_entry(sb->s_id, proc_info_root); 64762306a36Sopenharmony_ci sbi->procdir = NULL; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci#endif 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Mark rw ntfs as clear, if possible. */ 65262306a36Sopenharmony_ci ntfs_set_state(sbi, NTFS_DIRTY_CLEAR); 65362306a36Sopenharmony_ci ntfs3_put_sbi(sbi); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int ntfs_statfs(struct dentry *dentry, struct kstatfs *buf) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci struct super_block *sb = dentry->d_sb; 65962306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 66062306a36Sopenharmony_ci struct wnd_bitmap *wnd = &sbi->used.bitmap; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci buf->f_type = sb->s_magic; 66362306a36Sopenharmony_ci buf->f_bsize = sbi->cluster_size; 66462306a36Sopenharmony_ci buf->f_blocks = wnd->nbits; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci buf->f_bfree = buf->f_bavail = wnd_zeroes(wnd); 66762306a36Sopenharmony_ci buf->f_fsid.val[0] = sbi->volume.ser_num; 66862306a36Sopenharmony_ci buf->f_fsid.val[1] = (sbi->volume.ser_num >> 32); 66962306a36Sopenharmony_ci buf->f_namelen = NTFS_NAME_LEN; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci return 0; 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic int ntfs_show_options(struct seq_file *m, struct dentry *root) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci struct super_block *sb = root->d_sb; 67762306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 67862306a36Sopenharmony_ci struct ntfs_mount_options *opts = sbi->options; 67962306a36Sopenharmony_ci struct user_namespace *user_ns = seq_user_ns(m); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci seq_printf(m, ",uid=%u", from_kuid_munged(user_ns, opts->fs_uid)); 68262306a36Sopenharmony_ci seq_printf(m, ",gid=%u", from_kgid_munged(user_ns, opts->fs_gid)); 68362306a36Sopenharmony_ci if (opts->dmask) 68462306a36Sopenharmony_ci seq_printf(m, ",dmask=%04o", opts->fs_dmask_inv ^ 0xffff); 68562306a36Sopenharmony_ci if (opts->fmask) 68662306a36Sopenharmony_ci seq_printf(m, ",fmask=%04o", opts->fs_fmask_inv ^ 0xffff); 68762306a36Sopenharmony_ci if (opts->sys_immutable) 68862306a36Sopenharmony_ci seq_puts(m, ",sys_immutable"); 68962306a36Sopenharmony_ci if (opts->discard) 69062306a36Sopenharmony_ci seq_puts(m, ",discard"); 69162306a36Sopenharmony_ci if (opts->force) 69262306a36Sopenharmony_ci seq_puts(m, ",force"); 69362306a36Sopenharmony_ci if (opts->sparse) 69462306a36Sopenharmony_ci seq_puts(m, ",sparse"); 69562306a36Sopenharmony_ci if (opts->nohidden) 69662306a36Sopenharmony_ci seq_puts(m, ",nohidden"); 69762306a36Sopenharmony_ci if (opts->hide_dot_files) 69862306a36Sopenharmony_ci seq_puts(m, ",hide_dot_files"); 69962306a36Sopenharmony_ci if (opts->windows_names) 70062306a36Sopenharmony_ci seq_puts(m, ",windows_names"); 70162306a36Sopenharmony_ci if (opts->showmeta) 70262306a36Sopenharmony_ci seq_puts(m, ",showmeta"); 70362306a36Sopenharmony_ci if (sb->s_flags & SB_POSIXACL) 70462306a36Sopenharmony_ci seq_puts(m, ",acl"); 70562306a36Sopenharmony_ci if (opts->nls) 70662306a36Sopenharmony_ci seq_printf(m, ",iocharset=%s", opts->nls->charset); 70762306a36Sopenharmony_ci else 70862306a36Sopenharmony_ci seq_puts(m, ",iocharset=utf8"); 70962306a36Sopenharmony_ci if (opts->prealloc) 71062306a36Sopenharmony_ci seq_puts(m, ",prealloc"); 71162306a36Sopenharmony_ci if (opts->nocase) 71262306a36Sopenharmony_ci seq_puts(m, ",nocase"); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci return 0; 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci/* 71862306a36Sopenharmony_ci * ntfs_shutdown - super_operations::shutdown 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_cistatic void ntfs_shutdown(struct super_block *sb) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci set_bit(NTFS_FLAGS_SHUTDOWN_BIT, &ntfs_sb(sb)->flags); 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci/* 72662306a36Sopenharmony_ci * ntfs_sync_fs - super_operations::sync_fs 72762306a36Sopenharmony_ci */ 72862306a36Sopenharmony_cistatic int ntfs_sync_fs(struct super_block *sb, int wait) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci int err = 0, err2; 73162306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 73262306a36Sopenharmony_ci struct ntfs_inode *ni; 73362306a36Sopenharmony_ci struct inode *inode; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (unlikely(ntfs3_forced_shutdown(sb))) 73662306a36Sopenharmony_ci return -EIO; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci ni = sbi->security.ni; 73962306a36Sopenharmony_ci if (ni) { 74062306a36Sopenharmony_ci inode = &ni->vfs_inode; 74162306a36Sopenharmony_ci err2 = _ni_write_inode(inode, wait); 74262306a36Sopenharmony_ci if (err2 && !err) 74362306a36Sopenharmony_ci err = err2; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci ni = sbi->objid.ni; 74762306a36Sopenharmony_ci if (ni) { 74862306a36Sopenharmony_ci inode = &ni->vfs_inode; 74962306a36Sopenharmony_ci err2 = _ni_write_inode(inode, wait); 75062306a36Sopenharmony_ci if (err2 && !err) 75162306a36Sopenharmony_ci err = err2; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ni = sbi->reparse.ni; 75562306a36Sopenharmony_ci if (ni) { 75662306a36Sopenharmony_ci inode = &ni->vfs_inode; 75762306a36Sopenharmony_ci err2 = _ni_write_inode(inode, wait); 75862306a36Sopenharmony_ci if (err2 && !err) 75962306a36Sopenharmony_ci err = err2; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (!err) 76362306a36Sopenharmony_ci ntfs_set_state(sbi, NTFS_DIRTY_CLEAR); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci ntfs_update_mftmirr(sbi, wait); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci return err; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic const struct super_operations ntfs_sops = { 77162306a36Sopenharmony_ci .alloc_inode = ntfs_alloc_inode, 77262306a36Sopenharmony_ci .free_inode = ntfs_free_inode, 77362306a36Sopenharmony_ci .evict_inode = ntfs_evict_inode, 77462306a36Sopenharmony_ci .put_super = ntfs_put_super, 77562306a36Sopenharmony_ci .statfs = ntfs_statfs, 77662306a36Sopenharmony_ci .show_options = ntfs_show_options, 77762306a36Sopenharmony_ci .shutdown = ntfs_shutdown, 77862306a36Sopenharmony_ci .sync_fs = ntfs_sync_fs, 77962306a36Sopenharmony_ci .write_inode = ntfs3_write_inode, 78062306a36Sopenharmony_ci}; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic struct inode *ntfs_export_get_inode(struct super_block *sb, u64 ino, 78362306a36Sopenharmony_ci u32 generation) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct MFT_REF ref; 78662306a36Sopenharmony_ci struct inode *inode; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci ref.low = cpu_to_le32(ino); 78962306a36Sopenharmony_ci#ifdef CONFIG_NTFS3_64BIT_CLUSTER 79062306a36Sopenharmony_ci ref.high = cpu_to_le16(ino >> 32); 79162306a36Sopenharmony_ci#else 79262306a36Sopenharmony_ci ref.high = 0; 79362306a36Sopenharmony_ci#endif 79462306a36Sopenharmony_ci ref.seq = cpu_to_le16(generation); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci inode = ntfs_iget5(sb, &ref, NULL); 79762306a36Sopenharmony_ci if (!IS_ERR(inode) && is_bad_inode(inode)) { 79862306a36Sopenharmony_ci iput(inode); 79962306a36Sopenharmony_ci inode = ERR_PTR(-ESTALE); 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return inode; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic struct dentry *ntfs_fh_to_dentry(struct super_block *sb, struct fid *fid, 80662306a36Sopenharmony_ci int fh_len, int fh_type) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 80962306a36Sopenharmony_ci ntfs_export_get_inode); 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic struct dentry *ntfs_fh_to_parent(struct super_block *sb, struct fid *fid, 81362306a36Sopenharmony_ci int fh_len, int fh_type) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci return generic_fh_to_parent(sb, fid, fh_len, fh_type, 81662306a36Sopenharmony_ci ntfs_export_get_inode); 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci/* TODO: == ntfs_sync_inode */ 82062306a36Sopenharmony_cistatic int ntfs_nfs_commit_metadata(struct inode *inode) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci return _ni_write_inode(inode, 1); 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic const struct export_operations ntfs_export_ops = { 82662306a36Sopenharmony_ci .fh_to_dentry = ntfs_fh_to_dentry, 82762306a36Sopenharmony_ci .fh_to_parent = ntfs_fh_to_parent, 82862306a36Sopenharmony_ci .get_parent = ntfs3_get_parent, 82962306a36Sopenharmony_ci .commit_metadata = ntfs_nfs_commit_metadata, 83062306a36Sopenharmony_ci}; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci/* 83362306a36Sopenharmony_ci * format_size_gb - Return Gb,Mb to print with "%u.%02u Gb". 83462306a36Sopenharmony_ci */ 83562306a36Sopenharmony_cistatic u32 format_size_gb(const u64 bytes, u32 *mb) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci /* Do simple right 30 bit shift of 64 bit value. */ 83862306a36Sopenharmony_ci u64 kbytes = bytes >> 10; 83962306a36Sopenharmony_ci u32 kbytes32 = kbytes; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci *mb = (100 * (kbytes32 & 0xfffff) + 0x7ffff) >> 20; 84262306a36Sopenharmony_ci if (*mb >= 100) 84362306a36Sopenharmony_ci *mb = 99; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci return (kbytes32 >> 20) | (((u32)(kbytes >> 32)) << 12); 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic u32 true_sectors_per_clst(const struct NTFS_BOOT *boot) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci if (boot->sectors_per_clusters <= 0x80) 85162306a36Sopenharmony_ci return boot->sectors_per_clusters; 85262306a36Sopenharmony_ci if (boot->sectors_per_clusters >= 0xf4) /* limit shift to 2MB max */ 85362306a36Sopenharmony_ci return 1U << (-(s8)boot->sectors_per_clusters); 85462306a36Sopenharmony_ci return -EINVAL; 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci/* 85862306a36Sopenharmony_ci * ntfs_init_from_boot - Init internal info from on-disk boot sector. 85962306a36Sopenharmony_ci * 86062306a36Sopenharmony_ci * NTFS mount begins from boot - special formatted 512 bytes. 86162306a36Sopenharmony_ci * There are two boots: the first and the last 512 bytes of volume. 86262306a36Sopenharmony_ci * The content of boot is not changed during ntfs life. 86362306a36Sopenharmony_ci * 86462306a36Sopenharmony_ci * NOTE: ntfs.sys checks only first (primary) boot. 86562306a36Sopenharmony_ci * chkdsk checks both boots. 86662306a36Sopenharmony_ci */ 86762306a36Sopenharmony_cistatic int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, 86862306a36Sopenharmony_ci u64 dev_size, struct NTFS_BOOT **boot2) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 87162306a36Sopenharmony_ci int err; 87262306a36Sopenharmony_ci u32 mb, gb, boot_sector_size, sct_per_clst, record_size; 87362306a36Sopenharmony_ci u64 sectors, clusters, mlcn, mlcn2, dev_size0; 87462306a36Sopenharmony_ci struct NTFS_BOOT *boot; 87562306a36Sopenharmony_ci struct buffer_head *bh; 87662306a36Sopenharmony_ci struct MFT_REC *rec; 87762306a36Sopenharmony_ci u16 fn, ao; 87862306a36Sopenharmony_ci u8 cluster_bits; 87962306a36Sopenharmony_ci u32 boot_off = 0; 88062306a36Sopenharmony_ci sector_t boot_block = 0; 88162306a36Sopenharmony_ci const char *hint = "Primary boot"; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* Save original dev_size. Used with alternative boot. */ 88462306a36Sopenharmony_ci dev_size0 = dev_size; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci sbi->volume.blocks = dev_size >> PAGE_SHIFT; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ciread_boot: 88962306a36Sopenharmony_ci bh = ntfs_bread(sb, boot_block); 89062306a36Sopenharmony_ci if (!bh) 89162306a36Sopenharmony_ci return boot_block ? -EINVAL : -EIO; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci err = -EINVAL; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* Corrupted image; do not read OOB */ 89662306a36Sopenharmony_ci if (bh->b_size - sizeof(*boot) < boot_off) 89762306a36Sopenharmony_ci goto out; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci boot = (struct NTFS_BOOT *)Add2Ptr(bh->b_data, boot_off); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (memcmp(boot->system_id, "NTFS ", sizeof("NTFS ") - 1)) { 90262306a36Sopenharmony_ci ntfs_err(sb, "%s signature is not NTFS.", hint); 90362306a36Sopenharmony_ci goto out; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci /* 0x55AA is not mandaroty. Thanks Maxim Suhanov*/ 90762306a36Sopenharmony_ci /*if (0x55 != boot->boot_magic[0] || 0xAA != boot->boot_magic[1]) 90862306a36Sopenharmony_ci * goto out; 90962306a36Sopenharmony_ci */ 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci boot_sector_size = ((u32)boot->bytes_per_sector[1] << 8) | 91262306a36Sopenharmony_ci boot->bytes_per_sector[0]; 91362306a36Sopenharmony_ci if (boot_sector_size < SECTOR_SIZE || 91462306a36Sopenharmony_ci !is_power_of_2(boot_sector_size)) { 91562306a36Sopenharmony_ci ntfs_err(sb, "%s: invalid bytes per sector %u.", hint, 91662306a36Sopenharmony_ci boot_sector_size); 91762306a36Sopenharmony_ci goto out; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci /* cluster size: 512, 1K, 2K, 4K, ... 2M */ 92162306a36Sopenharmony_ci sct_per_clst = true_sectors_per_clst(boot); 92262306a36Sopenharmony_ci if ((int)sct_per_clst < 0 || !is_power_of_2(sct_per_clst)) { 92362306a36Sopenharmony_ci ntfs_err(sb, "%s: invalid sectors per cluster %u.", hint, 92462306a36Sopenharmony_ci sct_per_clst); 92562306a36Sopenharmony_ci goto out; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci sbi->cluster_size = boot_sector_size * sct_per_clst; 92962306a36Sopenharmony_ci sbi->cluster_bits = cluster_bits = blksize_bits(sbi->cluster_size); 93062306a36Sopenharmony_ci sbi->cluster_mask = sbi->cluster_size - 1; 93162306a36Sopenharmony_ci sbi->cluster_mask_inv = ~(u64)sbi->cluster_mask; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci mlcn = le64_to_cpu(boot->mft_clst); 93462306a36Sopenharmony_ci mlcn2 = le64_to_cpu(boot->mft2_clst); 93562306a36Sopenharmony_ci sectors = le64_to_cpu(boot->sectors_per_volume); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (mlcn * sct_per_clst >= sectors || mlcn2 * sct_per_clst >= sectors) { 93862306a36Sopenharmony_ci ntfs_err( 93962306a36Sopenharmony_ci sb, 94062306a36Sopenharmony_ci "%s: start of MFT 0x%llx (0x%llx) is out of volume 0x%llx.", 94162306a36Sopenharmony_ci hint, mlcn, mlcn2, sectors); 94262306a36Sopenharmony_ci goto out; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (boot->record_size >= 0) { 94662306a36Sopenharmony_ci record_size = (u32)boot->record_size << cluster_bits; 94762306a36Sopenharmony_ci } else if (-boot->record_size <= MAXIMUM_SHIFT_BYTES_PER_MFT) { 94862306a36Sopenharmony_ci record_size = 1u << (-boot->record_size); 94962306a36Sopenharmony_ci } else { 95062306a36Sopenharmony_ci ntfs_err(sb, "%s: invalid record size %d.", hint, 95162306a36Sopenharmony_ci boot->record_size); 95262306a36Sopenharmony_ci goto out; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci sbi->record_size = record_size; 95662306a36Sopenharmony_ci sbi->record_bits = blksize_bits(record_size); 95762306a36Sopenharmony_ci sbi->attr_size_tr = (5 * record_size >> 4); // ~320 bytes 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* Check MFT record size. */ 96062306a36Sopenharmony_ci if (record_size < SECTOR_SIZE || !is_power_of_2(record_size)) { 96162306a36Sopenharmony_ci ntfs_err(sb, "%s: invalid bytes per MFT record %u (%d).", hint, 96262306a36Sopenharmony_ci record_size, boot->record_size); 96362306a36Sopenharmony_ci goto out; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (record_size > MAXIMUM_BYTES_PER_MFT) { 96762306a36Sopenharmony_ci ntfs_err(sb, "Unsupported bytes per MFT record %u.", 96862306a36Sopenharmony_ci record_size); 96962306a36Sopenharmony_ci goto out; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (boot->index_size >= 0) { 97362306a36Sopenharmony_ci sbi->index_size = (u32)boot->index_size << cluster_bits; 97462306a36Sopenharmony_ci } else if (-boot->index_size <= MAXIMUM_SHIFT_BYTES_PER_INDEX) { 97562306a36Sopenharmony_ci sbi->index_size = 1u << (-boot->index_size); 97662306a36Sopenharmony_ci } else { 97762306a36Sopenharmony_ci ntfs_err(sb, "%s: invalid index size %d.", hint, 97862306a36Sopenharmony_ci boot->index_size); 97962306a36Sopenharmony_ci goto out; 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* Check index record size. */ 98362306a36Sopenharmony_ci if (sbi->index_size < SECTOR_SIZE || !is_power_of_2(sbi->index_size)) { 98462306a36Sopenharmony_ci ntfs_err(sb, "%s: invalid bytes per index %u(%d).", hint, 98562306a36Sopenharmony_ci sbi->index_size, boot->index_size); 98662306a36Sopenharmony_ci goto out; 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (sbi->index_size > MAXIMUM_BYTES_PER_INDEX) { 99062306a36Sopenharmony_ci ntfs_err(sb, "%s: unsupported bytes per index %u.", hint, 99162306a36Sopenharmony_ci sbi->index_size); 99262306a36Sopenharmony_ci goto out; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci sbi->volume.size = sectors * boot_sector_size; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci gb = format_size_gb(sbi->volume.size + boot_sector_size, &mb); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* 100062306a36Sopenharmony_ci * - Volume formatted and mounted with the same sector size. 100162306a36Sopenharmony_ci * - Volume formatted 4K and mounted as 512. 100262306a36Sopenharmony_ci * - Volume formatted 512 and mounted as 4K. 100362306a36Sopenharmony_ci */ 100462306a36Sopenharmony_ci if (boot_sector_size != sector_size) { 100562306a36Sopenharmony_ci ntfs_warn( 100662306a36Sopenharmony_ci sb, 100762306a36Sopenharmony_ci "Different NTFS sector size (%u) and media sector size (%u).", 100862306a36Sopenharmony_ci boot_sector_size, sector_size); 100962306a36Sopenharmony_ci dev_size += sector_size - 1; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci sbi->mft.lbo = mlcn << cluster_bits; 101362306a36Sopenharmony_ci sbi->mft.lbo2 = mlcn2 << cluster_bits; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci /* Compare boot's cluster and sector. */ 101662306a36Sopenharmony_ci if (sbi->cluster_size < boot_sector_size) { 101762306a36Sopenharmony_ci ntfs_err(sb, "%s: invalid bytes per cluster (%u).", hint, 101862306a36Sopenharmony_ci sbi->cluster_size); 101962306a36Sopenharmony_ci goto out; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* Compare boot's cluster and media sector. */ 102362306a36Sopenharmony_ci if (sbi->cluster_size < sector_size) { 102462306a36Sopenharmony_ci /* No way to use ntfs_get_block in this case. */ 102562306a36Sopenharmony_ci ntfs_err( 102662306a36Sopenharmony_ci sb, 102762306a36Sopenharmony_ci "Failed to mount 'cause NTFS's cluster size (%u) is less than media sector size (%u).", 102862306a36Sopenharmony_ci sbi->cluster_size, sector_size); 102962306a36Sopenharmony_ci goto out; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci sbi->max_bytes_per_attr = 103362306a36Sopenharmony_ci record_size - ALIGN(MFTRECORD_FIXUP_OFFSET, 8) - 103462306a36Sopenharmony_ci ALIGN(((record_size >> SECTOR_SHIFT) * sizeof(short)), 8) - 103562306a36Sopenharmony_ci ALIGN(sizeof(enum ATTR_TYPE), 8); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci sbi->volume.ser_num = le64_to_cpu(boot->serial_num); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci /* Warning if RAW volume. */ 104062306a36Sopenharmony_ci if (dev_size < sbi->volume.size + boot_sector_size) { 104162306a36Sopenharmony_ci u32 mb0, gb0; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci gb0 = format_size_gb(dev_size, &mb0); 104462306a36Sopenharmony_ci ntfs_warn( 104562306a36Sopenharmony_ci sb, 104662306a36Sopenharmony_ci "RAW NTFS volume: Filesystem size %u.%02u Gb > volume size %u.%02u Gb. Mount in read-only.", 104762306a36Sopenharmony_ci gb, mb, gb0, mb0); 104862306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci clusters = sbi->volume.size >> cluster_bits; 105262306a36Sopenharmony_ci#ifndef CONFIG_NTFS3_64BIT_CLUSTER 105362306a36Sopenharmony_ci /* 32 bits per cluster. */ 105462306a36Sopenharmony_ci if (clusters >> 32) { 105562306a36Sopenharmony_ci ntfs_notice( 105662306a36Sopenharmony_ci sb, 105762306a36Sopenharmony_ci "NTFS %u.%02u Gb is too big to use 32 bits per cluster.", 105862306a36Sopenharmony_ci gb, mb); 105962306a36Sopenharmony_ci goto out; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci#elif BITS_PER_LONG < 64 106262306a36Sopenharmony_ci#error "CONFIG_NTFS3_64BIT_CLUSTER incompatible in 32 bit OS" 106362306a36Sopenharmony_ci#endif 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci sbi->used.bitmap.nbits = clusters; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci rec = kzalloc(record_size, GFP_NOFS); 106862306a36Sopenharmony_ci if (!rec) { 106962306a36Sopenharmony_ci err = -ENOMEM; 107062306a36Sopenharmony_ci goto out; 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci sbi->new_rec = rec; 107462306a36Sopenharmony_ci rec->rhdr.sign = NTFS_FILE_SIGNATURE; 107562306a36Sopenharmony_ci rec->rhdr.fix_off = cpu_to_le16(MFTRECORD_FIXUP_OFFSET); 107662306a36Sopenharmony_ci fn = (sbi->record_size >> SECTOR_SHIFT) + 1; 107762306a36Sopenharmony_ci rec->rhdr.fix_num = cpu_to_le16(fn); 107862306a36Sopenharmony_ci ao = ALIGN(MFTRECORD_FIXUP_OFFSET + sizeof(short) * fn, 8); 107962306a36Sopenharmony_ci rec->attr_off = cpu_to_le16(ao); 108062306a36Sopenharmony_ci rec->used = cpu_to_le32(ao + ALIGN(sizeof(enum ATTR_TYPE), 8)); 108162306a36Sopenharmony_ci rec->total = cpu_to_le32(sbi->record_size); 108262306a36Sopenharmony_ci ((struct ATTRIB *)Add2Ptr(rec, ao))->type = ATTR_END; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci sb_set_blocksize(sb, min_t(u32, sbi->cluster_size, PAGE_SIZE)); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci sbi->block_mask = sb->s_blocksize - 1; 108762306a36Sopenharmony_ci sbi->blocks_per_cluster = sbi->cluster_size >> sb->s_blocksize_bits; 108862306a36Sopenharmony_ci sbi->volume.blocks = sbi->volume.size >> sb->s_blocksize_bits; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci /* Maximum size for normal files. */ 109162306a36Sopenharmony_ci sbi->maxbytes = (clusters << cluster_bits) - 1; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci#ifdef CONFIG_NTFS3_64BIT_CLUSTER 109462306a36Sopenharmony_ci if (clusters >= (1ull << (64 - cluster_bits))) 109562306a36Sopenharmony_ci sbi->maxbytes = -1; 109662306a36Sopenharmony_ci sbi->maxbytes_sparse = -1; 109762306a36Sopenharmony_ci sb->s_maxbytes = MAX_LFS_FILESIZE; 109862306a36Sopenharmony_ci#else 109962306a36Sopenharmony_ci /* Maximum size for sparse file. */ 110062306a36Sopenharmony_ci sbi->maxbytes_sparse = (1ull << (cluster_bits + 32)) - 1; 110162306a36Sopenharmony_ci sb->s_maxbytes = 0xFFFFFFFFull << cluster_bits; 110262306a36Sopenharmony_ci#endif 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci /* 110562306a36Sopenharmony_ci * Compute the MFT zone at two steps. 110662306a36Sopenharmony_ci * It would be nice if we are able to allocate 1/8 of 110762306a36Sopenharmony_ci * total clusters for MFT but not more then 512 MB. 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_ci sbi->zone_max = min_t(CLST, 0x20000000 >> cluster_bits, clusters >> 3); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci err = 0; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci if (bh->b_blocknr && !sb_rdonly(sb)) { 111462306a36Sopenharmony_ci /* 111562306a36Sopenharmony_ci * Alternative boot is ok but primary is not ok. 111662306a36Sopenharmony_ci * Do not update primary boot here 'cause it may be faked boot. 111762306a36Sopenharmony_ci * Let ntfs to be mounted and update boot later. 111862306a36Sopenharmony_ci */ 111962306a36Sopenharmony_ci *boot2 = kmemdup(boot, sizeof(*boot), GFP_NOFS | __GFP_NOWARN); 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ciout: 112362306a36Sopenharmony_ci brelse(bh); 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (err == -EINVAL && !boot_block && dev_size0 > PAGE_SHIFT) { 112662306a36Sopenharmony_ci u32 block_size = min_t(u32, sector_size, PAGE_SIZE); 112762306a36Sopenharmony_ci u64 lbo = dev_size0 - sizeof(*boot); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci boot_block = lbo >> blksize_bits(block_size); 113062306a36Sopenharmony_ci boot_off = lbo & (block_size - 1); 113162306a36Sopenharmony_ci if (boot_block && block_size >= boot_off + sizeof(*boot)) { 113262306a36Sopenharmony_ci /* 113362306a36Sopenharmony_ci * Try alternative boot (last sector) 113462306a36Sopenharmony_ci */ 113562306a36Sopenharmony_ci sb_set_blocksize(sb, block_size); 113662306a36Sopenharmony_ci hint = "Alternative boot"; 113762306a36Sopenharmony_ci dev_size = dev_size0; /* restore original size. */ 113862306a36Sopenharmony_ci goto read_boot; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci return err; 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci/* 114662306a36Sopenharmony_ci * ntfs_fill_super - Try to mount. 114762306a36Sopenharmony_ci */ 114862306a36Sopenharmony_cistatic int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci int err; 115162306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 115262306a36Sopenharmony_ci struct block_device *bdev = sb->s_bdev; 115362306a36Sopenharmony_ci struct ntfs_mount_options *options; 115462306a36Sopenharmony_ci struct inode *inode; 115562306a36Sopenharmony_ci struct ntfs_inode *ni; 115662306a36Sopenharmony_ci size_t i, tt, bad_len, bad_frags; 115762306a36Sopenharmony_ci CLST vcn, lcn, len; 115862306a36Sopenharmony_ci struct ATTRIB *attr; 115962306a36Sopenharmony_ci const struct VOLUME_INFO *info; 116062306a36Sopenharmony_ci u32 idx, done, bytes; 116162306a36Sopenharmony_ci struct ATTR_DEF_ENTRY *t; 116262306a36Sopenharmony_ci u16 *shared; 116362306a36Sopenharmony_ci struct MFT_REF ref; 116462306a36Sopenharmony_ci bool ro = sb_rdonly(sb); 116562306a36Sopenharmony_ci struct NTFS_BOOT *boot2 = NULL; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci ref.high = 0; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci sbi->sb = sb; 117062306a36Sopenharmony_ci sbi->options = options = fc->fs_private; 117162306a36Sopenharmony_ci fc->fs_private = NULL; 117262306a36Sopenharmony_ci sb->s_flags |= SB_NODIRATIME; 117362306a36Sopenharmony_ci sb->s_magic = 0x7366746e; // "ntfs" 117462306a36Sopenharmony_ci sb->s_op = &ntfs_sops; 117562306a36Sopenharmony_ci sb->s_export_op = &ntfs_export_ops; 117662306a36Sopenharmony_ci sb->s_time_gran = NTFS_TIME_GRAN; // 100 nsec 117762306a36Sopenharmony_ci sb->s_xattr = ntfs_xattr_handlers; 117862306a36Sopenharmony_ci sb->s_d_op = options->nocase ? &ntfs_dentry_ops : NULL; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci options->nls = ntfs_load_nls(options->nls_name); 118162306a36Sopenharmony_ci if (IS_ERR(options->nls)) { 118262306a36Sopenharmony_ci options->nls = NULL; 118362306a36Sopenharmony_ci errorf(fc, "Cannot load nls %s", options->nls_name); 118462306a36Sopenharmony_ci err = -EINVAL; 118562306a36Sopenharmony_ci goto out; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (bdev_max_discard_sectors(bdev) && bdev_discard_granularity(bdev)) { 118962306a36Sopenharmony_ci sbi->discard_granularity = bdev_discard_granularity(bdev); 119062306a36Sopenharmony_ci sbi->discard_granularity_mask_inv = 119162306a36Sopenharmony_ci ~(u64)(sbi->discard_granularity - 1); 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci /* Parse boot. */ 119562306a36Sopenharmony_ci err = ntfs_init_from_boot(sb, bdev_logical_block_size(bdev), 119662306a36Sopenharmony_ci bdev_nr_bytes(bdev), &boot2); 119762306a36Sopenharmony_ci if (err) 119862306a36Sopenharmony_ci goto out; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci /* 120162306a36Sopenharmony_ci * Load $Volume. This should be done before $LogFile 120262306a36Sopenharmony_ci * 'cause 'sbi->volume.ni' is used 'ntfs_set_state'. 120362306a36Sopenharmony_ci */ 120462306a36Sopenharmony_ci ref.low = cpu_to_le32(MFT_REC_VOL); 120562306a36Sopenharmony_ci ref.seq = cpu_to_le16(MFT_REC_VOL); 120662306a36Sopenharmony_ci inode = ntfs_iget5(sb, &ref, &NAME_VOLUME); 120762306a36Sopenharmony_ci if (IS_ERR(inode)) { 120862306a36Sopenharmony_ci err = PTR_ERR(inode); 120962306a36Sopenharmony_ci ntfs_err(sb, "Failed to load $Volume (%d).", err); 121062306a36Sopenharmony_ci goto out; 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci ni = ntfs_i(inode); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci /* Load and save label (not necessary). */ 121662306a36Sopenharmony_ci attr = ni_find_attr(ni, NULL, NULL, ATTR_LABEL, NULL, 0, NULL, NULL); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci if (!attr) { 121962306a36Sopenharmony_ci /* It is ok if no ATTR_LABEL */ 122062306a36Sopenharmony_ci } else if (!attr->non_res && !is_attr_ext(attr)) { 122162306a36Sopenharmony_ci /* $AttrDef allows labels to be up to 128 symbols. */ 122262306a36Sopenharmony_ci err = utf16s_to_utf8s(resident_data(attr), 122362306a36Sopenharmony_ci le32_to_cpu(attr->res.data_size) >> 1, 122462306a36Sopenharmony_ci UTF16_LITTLE_ENDIAN, sbi->volume.label, 122562306a36Sopenharmony_ci sizeof(sbi->volume.label)); 122662306a36Sopenharmony_ci if (err < 0) 122762306a36Sopenharmony_ci sbi->volume.label[0] = 0; 122862306a36Sopenharmony_ci } else { 122962306a36Sopenharmony_ci /* Should we break mounting here? */ 123062306a36Sopenharmony_ci //err = -EINVAL; 123162306a36Sopenharmony_ci //goto put_inode_out; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci attr = ni_find_attr(ni, attr, NULL, ATTR_VOL_INFO, NULL, 0, NULL, NULL); 123562306a36Sopenharmony_ci if (!attr || is_attr_ext(attr) || 123662306a36Sopenharmony_ci !(info = resident_data_ex(attr, SIZEOF_ATTRIBUTE_VOLUME_INFO))) { 123762306a36Sopenharmony_ci ntfs_err(sb, "$Volume is corrupted."); 123862306a36Sopenharmony_ci err = -EINVAL; 123962306a36Sopenharmony_ci goto put_inode_out; 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci sbi->volume.major_ver = info->major_ver; 124362306a36Sopenharmony_ci sbi->volume.minor_ver = info->minor_ver; 124462306a36Sopenharmony_ci sbi->volume.flags = info->flags; 124562306a36Sopenharmony_ci sbi->volume.ni = ni; 124662306a36Sopenharmony_ci if (info->flags & VOLUME_FLAG_DIRTY) { 124762306a36Sopenharmony_ci sbi->volume.real_dirty = true; 124862306a36Sopenharmony_ci ntfs_info(sb, "It is recommened to use chkdsk."); 124962306a36Sopenharmony_ci } 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci /* Load $MFTMirr to estimate recs_mirr. */ 125262306a36Sopenharmony_ci ref.low = cpu_to_le32(MFT_REC_MIRR); 125362306a36Sopenharmony_ci ref.seq = cpu_to_le16(MFT_REC_MIRR); 125462306a36Sopenharmony_ci inode = ntfs_iget5(sb, &ref, &NAME_MIRROR); 125562306a36Sopenharmony_ci if (IS_ERR(inode)) { 125662306a36Sopenharmony_ci err = PTR_ERR(inode); 125762306a36Sopenharmony_ci ntfs_err(sb, "Failed to load $MFTMirr (%d).", err); 125862306a36Sopenharmony_ci goto out; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci sbi->mft.recs_mirr = ntfs_up_cluster(sbi, inode->i_size) >> 126262306a36Sopenharmony_ci sbi->record_bits; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci iput(inode); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci /* Load LogFile to replay. */ 126762306a36Sopenharmony_ci ref.low = cpu_to_le32(MFT_REC_LOG); 126862306a36Sopenharmony_ci ref.seq = cpu_to_le16(MFT_REC_LOG); 126962306a36Sopenharmony_ci inode = ntfs_iget5(sb, &ref, &NAME_LOGFILE); 127062306a36Sopenharmony_ci if (IS_ERR(inode)) { 127162306a36Sopenharmony_ci err = PTR_ERR(inode); 127262306a36Sopenharmony_ci ntfs_err(sb, "Failed to load \x24LogFile (%d).", err); 127362306a36Sopenharmony_ci goto out; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci ni = ntfs_i(inode); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci err = ntfs_loadlog_and_replay(ni, sbi); 127962306a36Sopenharmony_ci if (err) 128062306a36Sopenharmony_ci goto put_inode_out; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci iput(inode); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci if ((sbi->flags & NTFS_FLAGS_NEED_REPLAY) && !ro) { 128562306a36Sopenharmony_ci ntfs_warn(sb, "failed to replay log file. Can't mount rw!"); 128662306a36Sopenharmony_ci err = -EINVAL; 128762306a36Sopenharmony_ci goto out; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if ((sbi->volume.flags & VOLUME_FLAG_DIRTY) && !ro && !options->force) { 129162306a36Sopenharmony_ci ntfs_warn(sb, "volume is dirty and \"force\" flag is not set!"); 129262306a36Sopenharmony_ci err = -EINVAL; 129362306a36Sopenharmony_ci goto out; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci /* Load $MFT. */ 129762306a36Sopenharmony_ci ref.low = cpu_to_le32(MFT_REC_MFT); 129862306a36Sopenharmony_ci ref.seq = cpu_to_le16(1); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci inode = ntfs_iget5(sb, &ref, &NAME_MFT); 130162306a36Sopenharmony_ci if (IS_ERR(inode)) { 130262306a36Sopenharmony_ci err = PTR_ERR(inode); 130362306a36Sopenharmony_ci ntfs_err(sb, "Failed to load $MFT (%d).", err); 130462306a36Sopenharmony_ci goto out; 130562306a36Sopenharmony_ci } 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci ni = ntfs_i(inode); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci sbi->mft.used = ni->i_valid >> sbi->record_bits; 131062306a36Sopenharmony_ci tt = inode->i_size >> sbi->record_bits; 131162306a36Sopenharmony_ci sbi->mft.next_free = MFT_REC_USER; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci err = wnd_init(&sbi->mft.bitmap, sb, tt); 131462306a36Sopenharmony_ci if (err) 131562306a36Sopenharmony_ci goto put_inode_out; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci err = ni_load_all_mi(ni); 131862306a36Sopenharmony_ci if (err) { 131962306a36Sopenharmony_ci ntfs_err(sb, "Failed to load $MFT's subrecords (%d).", err); 132062306a36Sopenharmony_ci goto put_inode_out; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci sbi->mft.ni = ni; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci /* Load $Bitmap. */ 132662306a36Sopenharmony_ci ref.low = cpu_to_le32(MFT_REC_BITMAP); 132762306a36Sopenharmony_ci ref.seq = cpu_to_le16(MFT_REC_BITMAP); 132862306a36Sopenharmony_ci inode = ntfs_iget5(sb, &ref, &NAME_BITMAP); 132962306a36Sopenharmony_ci if (IS_ERR(inode)) { 133062306a36Sopenharmony_ci err = PTR_ERR(inode); 133162306a36Sopenharmony_ci ntfs_err(sb, "Failed to load $Bitmap (%d).", err); 133262306a36Sopenharmony_ci goto out; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci#ifndef CONFIG_NTFS3_64BIT_CLUSTER 133662306a36Sopenharmony_ci if (inode->i_size >> 32) { 133762306a36Sopenharmony_ci err = -EINVAL; 133862306a36Sopenharmony_ci goto put_inode_out; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci#endif 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci /* Check bitmap boundary. */ 134362306a36Sopenharmony_ci tt = sbi->used.bitmap.nbits; 134462306a36Sopenharmony_ci if (inode->i_size < bitmap_size(tt)) { 134562306a36Sopenharmony_ci ntfs_err(sb, "$Bitmap is corrupted."); 134662306a36Sopenharmony_ci err = -EINVAL; 134762306a36Sopenharmony_ci goto put_inode_out; 134862306a36Sopenharmony_ci } 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci err = wnd_init(&sbi->used.bitmap, sb, tt); 135162306a36Sopenharmony_ci if (err) { 135262306a36Sopenharmony_ci ntfs_err(sb, "Failed to initialize $Bitmap (%d).", err); 135362306a36Sopenharmony_ci goto put_inode_out; 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci iput(inode); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci /* Compute the MFT zone. */ 135962306a36Sopenharmony_ci err = ntfs_refresh_zone(sbi); 136062306a36Sopenharmony_ci if (err) { 136162306a36Sopenharmony_ci ntfs_err(sb, "Failed to initialize MFT zone (%d).", err); 136262306a36Sopenharmony_ci goto out; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci /* Load $BadClus. */ 136662306a36Sopenharmony_ci ref.low = cpu_to_le32(MFT_REC_BADCLUST); 136762306a36Sopenharmony_ci ref.seq = cpu_to_le16(MFT_REC_BADCLUST); 136862306a36Sopenharmony_ci inode = ntfs_iget5(sb, &ref, &NAME_BADCLUS); 136962306a36Sopenharmony_ci if (IS_ERR(inode)) { 137062306a36Sopenharmony_ci err = PTR_ERR(inode); 137162306a36Sopenharmony_ci ntfs_err(sb, "Failed to load $BadClus (%d).", err); 137262306a36Sopenharmony_ci goto out; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci ni = ntfs_i(inode); 137662306a36Sopenharmony_ci bad_len = bad_frags = 0; 137762306a36Sopenharmony_ci for (i = 0; run_get_entry(&ni->file.run, i, &vcn, &lcn, &len); i++) { 137862306a36Sopenharmony_ci if (lcn == SPARSE_LCN) 137962306a36Sopenharmony_ci continue; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci bad_len += len; 138262306a36Sopenharmony_ci bad_frags += 1; 138362306a36Sopenharmony_ci if (ro) 138462306a36Sopenharmony_ci continue; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (wnd_set_used_safe(&sbi->used.bitmap, lcn, len, &tt) || tt) { 138762306a36Sopenharmony_ci /* Bad blocks marked as free in bitmap. */ 138862306a36Sopenharmony_ci ntfs_set_state(sbi, NTFS_DIRTY_ERROR); 138962306a36Sopenharmony_ci } 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci if (bad_len) { 139262306a36Sopenharmony_ci /* 139362306a36Sopenharmony_ci * Notice about bad blocks. 139462306a36Sopenharmony_ci * In normal cases these blocks are marked as used in bitmap. 139562306a36Sopenharmony_ci * And we never allocate space in it. 139662306a36Sopenharmony_ci */ 139762306a36Sopenharmony_ci ntfs_notice(sb, 139862306a36Sopenharmony_ci "Volume contains %zu bad blocks in %zu fragments.", 139962306a36Sopenharmony_ci bad_len, bad_frags); 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci iput(inode); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci /* Load $AttrDef. */ 140462306a36Sopenharmony_ci ref.low = cpu_to_le32(MFT_REC_ATTR); 140562306a36Sopenharmony_ci ref.seq = cpu_to_le16(MFT_REC_ATTR); 140662306a36Sopenharmony_ci inode = ntfs_iget5(sb, &ref, &NAME_ATTRDEF); 140762306a36Sopenharmony_ci if (IS_ERR(inode)) { 140862306a36Sopenharmony_ci err = PTR_ERR(inode); 140962306a36Sopenharmony_ci ntfs_err(sb, "Failed to load $AttrDef (%d)", err); 141062306a36Sopenharmony_ci goto out; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci /* 141462306a36Sopenharmony_ci * Typical $AttrDef contains up to 20 entries. 141562306a36Sopenharmony_ci * Check for extremely large/small size. 141662306a36Sopenharmony_ci */ 141762306a36Sopenharmony_ci if (inode->i_size < sizeof(struct ATTR_DEF_ENTRY) || 141862306a36Sopenharmony_ci inode->i_size > 100 * sizeof(struct ATTR_DEF_ENTRY)) { 141962306a36Sopenharmony_ci ntfs_err(sb, "Looks like $AttrDef is corrupted (size=%llu).", 142062306a36Sopenharmony_ci inode->i_size); 142162306a36Sopenharmony_ci err = -EINVAL; 142262306a36Sopenharmony_ci goto put_inode_out; 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci bytes = inode->i_size; 142662306a36Sopenharmony_ci sbi->def_table = t = kvmalloc(bytes, GFP_KERNEL); 142762306a36Sopenharmony_ci if (!t) { 142862306a36Sopenharmony_ci err = -ENOMEM; 142962306a36Sopenharmony_ci goto put_inode_out; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci for (done = idx = 0; done < bytes; done += PAGE_SIZE, idx++) { 143362306a36Sopenharmony_ci unsigned long tail = bytes - done; 143462306a36Sopenharmony_ci struct page *page = ntfs_map_page(inode->i_mapping, idx); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci if (IS_ERR(page)) { 143762306a36Sopenharmony_ci err = PTR_ERR(page); 143862306a36Sopenharmony_ci ntfs_err(sb, "Failed to read $AttrDef (%d).", err); 143962306a36Sopenharmony_ci goto put_inode_out; 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci memcpy(Add2Ptr(t, done), page_address(page), 144262306a36Sopenharmony_ci min(PAGE_SIZE, tail)); 144362306a36Sopenharmony_ci ntfs_unmap_page(page); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci if (!idx && ATTR_STD != t->type) { 144662306a36Sopenharmony_ci ntfs_err(sb, "$AttrDef is corrupted."); 144762306a36Sopenharmony_ci err = -EINVAL; 144862306a36Sopenharmony_ci goto put_inode_out; 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci t += 1; 145362306a36Sopenharmony_ci sbi->def_entries = 1; 145462306a36Sopenharmony_ci done = sizeof(struct ATTR_DEF_ENTRY); 145562306a36Sopenharmony_ci sbi->reparse.max_size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; 145662306a36Sopenharmony_ci sbi->ea_max_size = 0x10000; /* default formatter value */ 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci while (done + sizeof(struct ATTR_DEF_ENTRY) <= bytes) { 145962306a36Sopenharmony_ci u32 t32 = le32_to_cpu(t->type); 146062306a36Sopenharmony_ci u64 sz = le64_to_cpu(t->max_sz); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if ((t32 & 0xF) || le32_to_cpu(t[-1].type) >= t32) 146362306a36Sopenharmony_ci break; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci if (t->type == ATTR_REPARSE) 146662306a36Sopenharmony_ci sbi->reparse.max_size = sz; 146762306a36Sopenharmony_ci else if (t->type == ATTR_EA) 146862306a36Sopenharmony_ci sbi->ea_max_size = sz; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci done += sizeof(struct ATTR_DEF_ENTRY); 147162306a36Sopenharmony_ci t += 1; 147262306a36Sopenharmony_ci sbi->def_entries += 1; 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci iput(inode); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci /* Load $UpCase. */ 147762306a36Sopenharmony_ci ref.low = cpu_to_le32(MFT_REC_UPCASE); 147862306a36Sopenharmony_ci ref.seq = cpu_to_le16(MFT_REC_UPCASE); 147962306a36Sopenharmony_ci inode = ntfs_iget5(sb, &ref, &NAME_UPCASE); 148062306a36Sopenharmony_ci if (IS_ERR(inode)) { 148162306a36Sopenharmony_ci err = PTR_ERR(inode); 148262306a36Sopenharmony_ci ntfs_err(sb, "Failed to load $UpCase (%d).", err); 148362306a36Sopenharmony_ci goto out; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci if (inode->i_size != 0x10000 * sizeof(short)) { 148762306a36Sopenharmony_ci err = -EINVAL; 148862306a36Sopenharmony_ci ntfs_err(sb, "$UpCase is corrupted."); 148962306a36Sopenharmony_ci goto put_inode_out; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci for (idx = 0; idx < (0x10000 * sizeof(short) >> PAGE_SHIFT); idx++) { 149362306a36Sopenharmony_ci const __le16 *src; 149462306a36Sopenharmony_ci u16 *dst = Add2Ptr(sbi->upcase, idx << PAGE_SHIFT); 149562306a36Sopenharmony_ci struct page *page = ntfs_map_page(inode->i_mapping, idx); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci if (IS_ERR(page)) { 149862306a36Sopenharmony_ci err = PTR_ERR(page); 149962306a36Sopenharmony_ci ntfs_err(sb, "Failed to read $UpCase (%d).", err); 150062306a36Sopenharmony_ci goto put_inode_out; 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci src = page_address(page); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 150662306a36Sopenharmony_ci for (i = 0; i < PAGE_SIZE / sizeof(u16); i++) 150762306a36Sopenharmony_ci *dst++ = le16_to_cpu(*src++); 150862306a36Sopenharmony_ci#else 150962306a36Sopenharmony_ci memcpy(dst, src, PAGE_SIZE); 151062306a36Sopenharmony_ci#endif 151162306a36Sopenharmony_ci ntfs_unmap_page(page); 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci shared = ntfs_set_shared(sbi->upcase, 0x10000 * sizeof(short)); 151562306a36Sopenharmony_ci if (shared && sbi->upcase != shared) { 151662306a36Sopenharmony_ci kvfree(sbi->upcase); 151762306a36Sopenharmony_ci sbi->upcase = shared; 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci iput(inode); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci if (is_ntfs3(sbi)) { 152362306a36Sopenharmony_ci /* Load $Secure. */ 152462306a36Sopenharmony_ci err = ntfs_security_init(sbi); 152562306a36Sopenharmony_ci if (err) { 152662306a36Sopenharmony_ci ntfs_err(sb, "Failed to initialize $Secure (%d).", err); 152762306a36Sopenharmony_ci goto out; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci /* Load $Extend. */ 153162306a36Sopenharmony_ci err = ntfs_extend_init(sbi); 153262306a36Sopenharmony_ci if (err) { 153362306a36Sopenharmony_ci ntfs_warn(sb, "Failed to initialize $Extend."); 153462306a36Sopenharmony_ci goto load_root; 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci /* Load $Extend/$Reparse. */ 153862306a36Sopenharmony_ci err = ntfs_reparse_init(sbi); 153962306a36Sopenharmony_ci if (err) { 154062306a36Sopenharmony_ci ntfs_warn(sb, "Failed to initialize $Extend/$Reparse."); 154162306a36Sopenharmony_ci goto load_root; 154262306a36Sopenharmony_ci } 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci /* Load $Extend/$ObjId. */ 154562306a36Sopenharmony_ci err = ntfs_objid_init(sbi); 154662306a36Sopenharmony_ci if (err) { 154762306a36Sopenharmony_ci ntfs_warn(sb, "Failed to initialize $Extend/$ObjId."); 154862306a36Sopenharmony_ci goto load_root; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ciload_root: 155362306a36Sopenharmony_ci /* Load root. */ 155462306a36Sopenharmony_ci ref.low = cpu_to_le32(MFT_REC_ROOT); 155562306a36Sopenharmony_ci ref.seq = cpu_to_le16(MFT_REC_ROOT); 155662306a36Sopenharmony_ci inode = ntfs_iget5(sb, &ref, &NAME_ROOT); 155762306a36Sopenharmony_ci if (IS_ERR(inode)) { 155862306a36Sopenharmony_ci err = PTR_ERR(inode); 155962306a36Sopenharmony_ci ntfs_err(sb, "Failed to load root (%d).", err); 156062306a36Sopenharmony_ci goto out; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci /* 156462306a36Sopenharmony_ci * Final check. Looks like this case should never occurs. 156562306a36Sopenharmony_ci */ 156662306a36Sopenharmony_ci if (!inode->i_op) { 156762306a36Sopenharmony_ci err = -EINVAL; 156862306a36Sopenharmony_ci ntfs_err(sb, "Failed to load root (%d).", err); 156962306a36Sopenharmony_ci goto put_inode_out; 157062306a36Sopenharmony_ci } 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci sb->s_root = d_make_root(inode); 157362306a36Sopenharmony_ci if (!sb->s_root) { 157462306a36Sopenharmony_ci err = -ENOMEM; 157562306a36Sopenharmony_ci goto put_inode_out; 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci if (boot2) { 157962306a36Sopenharmony_ci /* 158062306a36Sopenharmony_ci * Alternative boot is ok but primary is not ok. 158162306a36Sopenharmony_ci * Volume is recognized as NTFS. Update primary boot. 158262306a36Sopenharmony_ci */ 158362306a36Sopenharmony_ci struct buffer_head *bh0 = sb_getblk(sb, 0); 158462306a36Sopenharmony_ci if (bh0) { 158562306a36Sopenharmony_ci if (buffer_locked(bh0)) 158662306a36Sopenharmony_ci __wait_on_buffer(bh0); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci lock_buffer(bh0); 158962306a36Sopenharmony_ci memcpy(bh0->b_data, boot2, sizeof(*boot2)); 159062306a36Sopenharmony_ci set_buffer_uptodate(bh0); 159162306a36Sopenharmony_ci mark_buffer_dirty(bh0); 159262306a36Sopenharmony_ci unlock_buffer(bh0); 159362306a36Sopenharmony_ci if (!sync_dirty_buffer(bh0)) 159462306a36Sopenharmony_ci ntfs_warn(sb, "primary boot is updated"); 159562306a36Sopenharmony_ci put_bh(bh0); 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci kfree(boot2); 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 160262306a36Sopenharmony_ci /* Create /proc/fs/ntfs3/.. */ 160362306a36Sopenharmony_ci if (proc_info_root) { 160462306a36Sopenharmony_ci struct proc_dir_entry *e = proc_mkdir(sb->s_id, proc_info_root); 160562306a36Sopenharmony_ci static_assert((S_IRUGO | S_IWUSR) == 0644); 160662306a36Sopenharmony_ci if (e) { 160762306a36Sopenharmony_ci proc_create_data("volinfo", S_IRUGO, e, 160862306a36Sopenharmony_ci &ntfs3_volinfo_fops, sb); 160962306a36Sopenharmony_ci proc_create_data("label", S_IRUGO | S_IWUSR, e, 161062306a36Sopenharmony_ci &ntfs3_label_fops, sb); 161162306a36Sopenharmony_ci sbi->procdir = e; 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci#endif 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci return 0; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ciput_inode_out: 161962306a36Sopenharmony_ci iput(inode); 162062306a36Sopenharmony_ciout: 162162306a36Sopenharmony_ci ntfs3_put_sbi(sbi); 162262306a36Sopenharmony_ci kfree(boot2); 162362306a36Sopenharmony_ci ntfs3_put_sbi(sbi); 162462306a36Sopenharmony_ci return err; 162562306a36Sopenharmony_ci} 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_civoid ntfs_unmap_meta(struct super_block *sb, CLST lcn, CLST len) 162862306a36Sopenharmony_ci{ 162962306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 163062306a36Sopenharmony_ci struct block_device *bdev = sb->s_bdev; 163162306a36Sopenharmony_ci sector_t devblock = (u64)lcn * sbi->blocks_per_cluster; 163262306a36Sopenharmony_ci unsigned long blocks = (u64)len * sbi->blocks_per_cluster; 163362306a36Sopenharmony_ci unsigned long cnt = 0; 163462306a36Sopenharmony_ci unsigned long limit = global_zone_page_state(NR_FREE_PAGES) 163562306a36Sopenharmony_ci << (PAGE_SHIFT - sb->s_blocksize_bits); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci if (limit >= 0x2000) 163862306a36Sopenharmony_ci limit -= 0x1000; 163962306a36Sopenharmony_ci else if (limit < 32) 164062306a36Sopenharmony_ci limit = 32; 164162306a36Sopenharmony_ci else 164262306a36Sopenharmony_ci limit >>= 1; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci while (blocks--) { 164562306a36Sopenharmony_ci clean_bdev_aliases(bdev, devblock++, 1); 164662306a36Sopenharmony_ci if (cnt++ >= limit) { 164762306a36Sopenharmony_ci sync_blockdev(bdev); 164862306a36Sopenharmony_ci cnt = 0; 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci} 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci/* 165462306a36Sopenharmony_ci * ntfs_discard - Issue a discard request (trim for SSD). 165562306a36Sopenharmony_ci */ 165662306a36Sopenharmony_ciint ntfs_discard(struct ntfs_sb_info *sbi, CLST lcn, CLST len) 165762306a36Sopenharmony_ci{ 165862306a36Sopenharmony_ci int err; 165962306a36Sopenharmony_ci u64 lbo, bytes, start, end; 166062306a36Sopenharmony_ci struct super_block *sb; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci if (sbi->used.next_free_lcn == lcn + len) 166362306a36Sopenharmony_ci sbi->used.next_free_lcn = lcn; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci if (sbi->flags & NTFS_FLAGS_NODISCARD) 166662306a36Sopenharmony_ci return -EOPNOTSUPP; 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci if (!sbi->options->discard) 166962306a36Sopenharmony_ci return -EOPNOTSUPP; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci lbo = (u64)lcn << sbi->cluster_bits; 167262306a36Sopenharmony_ci bytes = (u64)len << sbi->cluster_bits; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci /* Align up 'start' on discard_granularity. */ 167562306a36Sopenharmony_ci start = (lbo + sbi->discard_granularity - 1) & 167662306a36Sopenharmony_ci sbi->discard_granularity_mask_inv; 167762306a36Sopenharmony_ci /* Align down 'end' on discard_granularity. */ 167862306a36Sopenharmony_ci end = (lbo + bytes) & sbi->discard_granularity_mask_inv; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci sb = sbi->sb; 168162306a36Sopenharmony_ci if (start >= end) 168262306a36Sopenharmony_ci return 0; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci err = blkdev_issue_discard(sb->s_bdev, start >> 9, (end - start) >> 9, 168562306a36Sopenharmony_ci GFP_NOFS); 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci if (err == -EOPNOTSUPP) 168862306a36Sopenharmony_ci sbi->flags |= NTFS_FLAGS_NODISCARD; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci return err; 169162306a36Sopenharmony_ci} 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_cistatic int ntfs_fs_get_tree(struct fs_context *fc) 169462306a36Sopenharmony_ci{ 169562306a36Sopenharmony_ci return get_tree_bdev(fc, ntfs_fill_super); 169662306a36Sopenharmony_ci} 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci/* 169962306a36Sopenharmony_ci * ntfs_fs_free - Free fs_context. 170062306a36Sopenharmony_ci * 170162306a36Sopenharmony_ci * Note that this will be called after fill_super and reconfigure 170262306a36Sopenharmony_ci * even when they pass. So they have to take pointers if they pass. 170362306a36Sopenharmony_ci */ 170462306a36Sopenharmony_cistatic void ntfs_fs_free(struct fs_context *fc) 170562306a36Sopenharmony_ci{ 170662306a36Sopenharmony_ci struct ntfs_mount_options *opts = fc->fs_private; 170762306a36Sopenharmony_ci struct ntfs_sb_info *sbi = fc->s_fs_info; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci if (sbi) { 171062306a36Sopenharmony_ci ntfs3_put_sbi(sbi); 171162306a36Sopenharmony_ci ntfs3_free_sbi(sbi); 171262306a36Sopenharmony_ci } 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci if (opts) 171562306a36Sopenharmony_ci put_mount_options(opts); 171662306a36Sopenharmony_ci} 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci// clang-format off 171962306a36Sopenharmony_cistatic const struct fs_context_operations ntfs_context_ops = { 172062306a36Sopenharmony_ci .parse_param = ntfs_fs_parse_param, 172162306a36Sopenharmony_ci .get_tree = ntfs_fs_get_tree, 172262306a36Sopenharmony_ci .reconfigure = ntfs_fs_reconfigure, 172362306a36Sopenharmony_ci .free = ntfs_fs_free, 172462306a36Sopenharmony_ci}; 172562306a36Sopenharmony_ci// clang-format on 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci/* 172862306a36Sopenharmony_ci * ntfs_init_fs_context - Initialize sbi and opts 172962306a36Sopenharmony_ci * 173062306a36Sopenharmony_ci * This will called when mount/remount. We will first initialize 173162306a36Sopenharmony_ci * options so that if remount we can use just that. 173262306a36Sopenharmony_ci */ 173362306a36Sopenharmony_cistatic int ntfs_init_fs_context(struct fs_context *fc) 173462306a36Sopenharmony_ci{ 173562306a36Sopenharmony_ci struct ntfs_mount_options *opts; 173662306a36Sopenharmony_ci struct ntfs_sb_info *sbi; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci opts = kzalloc(sizeof(struct ntfs_mount_options), GFP_NOFS); 173962306a36Sopenharmony_ci if (!opts) 174062306a36Sopenharmony_ci return -ENOMEM; 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci /* Default options. */ 174362306a36Sopenharmony_ci opts->fs_uid = current_uid(); 174462306a36Sopenharmony_ci opts->fs_gid = current_gid(); 174562306a36Sopenharmony_ci opts->fs_fmask_inv = ~current_umask(); 174662306a36Sopenharmony_ci opts->fs_dmask_inv = ~current_umask(); 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) 174962306a36Sopenharmony_ci goto ok; 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci sbi = kzalloc(sizeof(struct ntfs_sb_info), GFP_NOFS); 175262306a36Sopenharmony_ci if (!sbi) 175362306a36Sopenharmony_ci goto free_opts; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci sbi->upcase = kvmalloc(0x10000 * sizeof(short), GFP_KERNEL); 175662306a36Sopenharmony_ci if (!sbi->upcase) 175762306a36Sopenharmony_ci goto free_sbi; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci ratelimit_state_init(&sbi->msg_ratelimit, DEFAULT_RATELIMIT_INTERVAL, 176062306a36Sopenharmony_ci DEFAULT_RATELIMIT_BURST); 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci mutex_init(&sbi->compress.mtx_lznt); 176362306a36Sopenharmony_ci#ifdef CONFIG_NTFS3_LZX_XPRESS 176462306a36Sopenharmony_ci mutex_init(&sbi->compress.mtx_xpress); 176562306a36Sopenharmony_ci mutex_init(&sbi->compress.mtx_lzx); 176662306a36Sopenharmony_ci#endif 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci fc->s_fs_info = sbi; 176962306a36Sopenharmony_ciok: 177062306a36Sopenharmony_ci fc->fs_private = opts; 177162306a36Sopenharmony_ci fc->ops = &ntfs_context_ops; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci return 0; 177462306a36Sopenharmony_cifree_sbi: 177562306a36Sopenharmony_ci kfree(sbi); 177662306a36Sopenharmony_cifree_opts: 177762306a36Sopenharmony_ci kfree(opts); 177862306a36Sopenharmony_ci return -ENOMEM; 177962306a36Sopenharmony_ci} 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_cistatic void ntfs3_kill_sb(struct super_block *sb) 178262306a36Sopenharmony_ci{ 178362306a36Sopenharmony_ci struct ntfs_sb_info *sbi = sb->s_fs_info; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci kill_block_super(sb); 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci if (sbi->options) 178862306a36Sopenharmony_ci put_mount_options(sbi->options); 178962306a36Sopenharmony_ci ntfs3_free_sbi(sbi); 179062306a36Sopenharmony_ci} 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci// clang-format off 179362306a36Sopenharmony_cistatic struct file_system_type ntfs_fs_type = { 179462306a36Sopenharmony_ci .owner = THIS_MODULE, 179562306a36Sopenharmony_ci .name = "ntfs3", 179662306a36Sopenharmony_ci .init_fs_context = ntfs_init_fs_context, 179762306a36Sopenharmony_ci .parameters = ntfs_fs_parameters, 179862306a36Sopenharmony_ci .kill_sb = ntfs3_kill_sb, 179962306a36Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP, 180062306a36Sopenharmony_ci}; 180162306a36Sopenharmony_ci// clang-format on 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_cistatic int __init init_ntfs_fs(void) 180462306a36Sopenharmony_ci{ 180562306a36Sopenharmony_ci int err; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci pr_info("ntfs3: Max link count %u\n", NTFS_LINK_MAX); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_NTFS3_FS_POSIX_ACL)) 181062306a36Sopenharmony_ci pr_info("ntfs3: Enabled Linux POSIX ACLs support\n"); 181162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_NTFS3_64BIT_CLUSTER)) 181262306a36Sopenharmony_ci pr_notice( 181362306a36Sopenharmony_ci "ntfs3: Warning: Activated 64 bits per cluster. Windows does not support this\n"); 181462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_NTFS3_LZX_XPRESS)) 181562306a36Sopenharmony_ci pr_info("ntfs3: Read-only LZX/Xpress compression included\n"); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 181862306a36Sopenharmony_ci /* Create "/proc/fs/ntfs3" */ 181962306a36Sopenharmony_ci proc_info_root = proc_mkdir("fs/ntfs3", NULL); 182062306a36Sopenharmony_ci#endif 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci err = ntfs3_init_bitmap(); 182362306a36Sopenharmony_ci if (err) 182462306a36Sopenharmony_ci return err; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci ntfs_inode_cachep = kmem_cache_create( 182762306a36Sopenharmony_ci "ntfs_inode_cache", sizeof(struct ntfs_inode), 0, 182862306a36Sopenharmony_ci (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD | SLAB_ACCOUNT), 182962306a36Sopenharmony_ci init_once); 183062306a36Sopenharmony_ci if (!ntfs_inode_cachep) { 183162306a36Sopenharmony_ci err = -ENOMEM; 183262306a36Sopenharmony_ci goto out1; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci err = register_filesystem(&ntfs_fs_type); 183662306a36Sopenharmony_ci if (err) 183762306a36Sopenharmony_ci goto out; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci return 0; 184062306a36Sopenharmony_ciout: 184162306a36Sopenharmony_ci kmem_cache_destroy(ntfs_inode_cachep); 184262306a36Sopenharmony_ciout1: 184362306a36Sopenharmony_ci ntfs3_exit_bitmap(); 184462306a36Sopenharmony_ci return err; 184562306a36Sopenharmony_ci} 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_cistatic void __exit exit_ntfs_fs(void) 184862306a36Sopenharmony_ci{ 184962306a36Sopenharmony_ci rcu_barrier(); 185062306a36Sopenharmony_ci kmem_cache_destroy(ntfs_inode_cachep); 185162306a36Sopenharmony_ci unregister_filesystem(&ntfs_fs_type); 185262306a36Sopenharmony_ci ntfs3_exit_bitmap(); 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 185562306a36Sopenharmony_ci if (proc_info_root) 185662306a36Sopenharmony_ci remove_proc_entry("fs/ntfs3", NULL); 185762306a36Sopenharmony_ci#endif 185862306a36Sopenharmony_ci} 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 186162306a36Sopenharmony_ciMODULE_DESCRIPTION("ntfs3 read/write filesystem"); 186262306a36Sopenharmony_ci#ifdef CONFIG_NTFS3_FS_POSIX_ACL 186362306a36Sopenharmony_ciMODULE_INFO(behaviour, "Enabled Linux POSIX ACLs support"); 186462306a36Sopenharmony_ci#endif 186562306a36Sopenharmony_ci#ifdef CONFIG_NTFS3_64BIT_CLUSTER 186662306a36Sopenharmony_ciMODULE_INFO( 186762306a36Sopenharmony_ci cluster, 186862306a36Sopenharmony_ci "Warning: Activated 64 bits per cluster. Windows does not support this"); 186962306a36Sopenharmony_ci#endif 187062306a36Sopenharmony_ci#ifdef CONFIG_NTFS3_LZX_XPRESS 187162306a36Sopenharmony_ciMODULE_INFO(compression, "Read-only lzx/xpress compression included"); 187262306a36Sopenharmony_ci#endif 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ciMODULE_AUTHOR("Konstantin Komarov"); 187562306a36Sopenharmony_ciMODULE_ALIAS_FS("ntfs3"); 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_cimodule_init(init_ntfs_fs); 187862306a36Sopenharmony_cimodule_exit(exit_ntfs_fs); 1879