// SPDX-License-Identifier: GPL-2.0
/*
*
* Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
*
*
* terminology
*
* cluster - allocation unit - 512,1K,2K,4K,...,2M
* vcn - virtual cluster number - Offset inside the file in clusters.
* vbo - virtual byte offset - Offset inside the file in bytes.
* lcn - logical cluster number - 0 based cluster in clusters heap.
* lbo - logical byte offset - Absolute position inside volume.
* run - maps VCN to LCN - Stored in attributes in packed form.
* attr - attribute segment - std/name/data etc records inside MFT.
* mi - MFT inode - One MFT record(usually 1024 bytes or 4K), consists of attributes.
* ni - NTFS inode - Extends linux inode. consists of one or more mft inodes.
* index - unit inside directory - 2K, 4K, <=page size, does not depend on cluster size.
*
* WSL - Windows Subsystem for Linux
* https://docs.microsoft.com/en-us/windows/wsl/file-permissions
* It stores uid/gid/mode/dev in xattr
*
* ntfs allows up to 2^64 clusters per volume.
* It means you should use 64 bits lcn to operate with ntfs.
* Implementation of ntfs.sys uses only 32 bits lcn.
* Default ntfs3 uses 32 bits lcn too.
* ntfs3 built with CONFIG_NTFS3_64BIT_CLUSTER (ntfs3_64) uses 64 bits per lcn.
*
*
* ntfs limits, cluster size is 4K (2^12)
* -----------------------------------------------------------------------------
* | Volume size | Clusters | ntfs.sys | ntfs3 | ntfs3_64 | mkntfs | chkdsk |
* -----------------------------------------------------------------------------
* | < 16T, 2^44 | < 2^32 | yes | yes | yes | yes | yes |
* | > 16T, 2^44 | > 2^32 | no | no | yes | yes | yes |
* ----------------------------------------------------------|------------------
*
* To mount large volumes as ntfs one should use large cluster size (up to 2M)
* The maximum volume size in this case is 2^32 * 2^21 = 2^53 = 8P
*
* ntfs limits, cluster size is 2M (2^21)
* -----------------------------------------------------------------------------
* | < 8P, 2^53 | < 2^32 | yes | yes | yes | yes | yes |
* | > 8P, 2^53 | > 2^32 | no | no | yes | yes | yes |
* ----------------------------------------------------------|------------------
*
*/
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#include <linux/exportfs.h>
#include <linux/fs.h>
#include <linux/fs_context.h>
#include <linux/fs_parser.h>
#include <linux/log2.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/nls.h>
#include <linux/seq_file.h>
#include <linux/statfs.h>
#include "debug.h"
#include "ntfs.h"
#include "ntfs_fs.h"
#ifdef CONFIG_NTFS3_LZX_XPRESS
#include "lib/lib.h"
#endif
#ifdef CONFIG_PRINTK
/*
* ntfs_printk - Trace warnings/notices/errors.
*
* Thanks Joe Perches <joe@perches.com> for implementation
*/
void ntfs_printk(const struct super_block *sb, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
int level;
struct ntfs_sb_info *sbi = sb->s_fs_info;
/* Should we use different ratelimits for warnings/notices/errors? */
if (!___ratelimit(&sbi->msg_ratelimit, "ntfs3"))
return;
va_start(args, fmt);
level = printk_get_level(fmt);
vaf.fmt = printk_skip_level(fmt);
vaf.va = &args;
printk("%c%cntfs3: %s: %pV\n", KERN_SOH_ASCII, level, sb->s_id, &vaf);
va_end(args);
}
static char s_name_buf[512];
static atomic_t s_name_buf_cnt = ATOMIC_INIT(1); // 1 means 'free s_name_buf'.
/*
* ntfs_inode_printk
*
* Print warnings/notices/errors about inode using name or inode number.
*/
void ntfs_inode_printk(struct inode *inode, const char *fmt, ...)
{
struct super_block *sb = inode->i_sb;
struct ntfs_sb_info *sbi = sb->s_fs_info;
char *name;
va_list args;
struct va_format vaf;
int level;
if (!___ratelimit(&sbi->msg_ratelimit, "ntfs3"))
return;
/* Use static allocated buffer, if possible. */
name = atomic_dec_and_test(&s_name_buf_cnt) ?
s_name_buf :
kmalloc(sizeof(s_name_buf), GFP_NOFS);
if (name) {
struct dentry *de = d_find_alias(inode);
const u32 name_len = ARRAY_SIZE(s_name_buf) - 1;
if (de) {
spin_lock(&de->d_lock);
snprintf(name, name_len, " \"%s\"", de->d_name.name);
spin_unlock(&de->d_lock);
name[name_len] = 0; /* To be sure. */
} else {
name[0] = 0;
}
dput(de); /* Cocci warns if placed in branch
|