📄 super.c
字号:
* NOTE: @sb->s_flags contains the mount options flags.
*/
static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
{
ntfs_volume *vol;
struct buffer_head *bh;
struct inode *tmp_ino;
int result;
ntfs_debug("Entering.");
#ifndef NTFS_RW
sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
#endif
/* Allocate a new ntfs_volume and place it in sb->s_fs_info. */
sb->s_fs_info = kmalloc(sizeof(ntfs_volume), GFP_NOFS);
vol = NTFS_SB(sb);
if (!vol) {
if (!silent)
ntfs_error(sb, "Allocation of NTFS volume structure "
"failed. Aborting mount...");
return -ENOMEM;
}
/* Initialize ntfs_volume structure. */
memset(vol, 0, sizeof(ntfs_volume));
vol->sb = sb;
vol->upcase = NULL;
vol->mft_ino = NULL;
vol->mftbmp_ino = NULL;
init_rwsem(&vol->mftbmp_lock);
vol->mftmirr_ino = NULL;
vol->lcnbmp_ino = NULL;
init_rwsem(&vol->lcnbmp_lock);
vol->vol_ino = NULL;
vol->root_ino = NULL;
vol->secure_ino = NULL;
vol->uid = vol->gid = 0;
vol->flags = 0;
vol->on_errors = 0;
vol->mft_zone_multiplier = 0;
vol->nls_map = NULL;
/*
* Default is group and other don't have any access to files or
* directories while owner has full access. Further, files by default
* are not executable but directories are of course browseable.
*/
vol->fmask = 0177;
vol->dmask = 0077;
/* Important to get the mount options dealt with now. */
if (!parse_options(vol, (char*)opt))
goto err_out_now;
/*
* TODO: Fail safety check. In the future we should really be able to
* cope with this being the case, but for now just bail out.
*/
if (bdev_hardsect_size(sb->s_bdev) > NTFS_BLOCK_SIZE) {
if (!silent)
ntfs_error(sb, "Device has unsupported hardsect_size.");
goto err_out_now;
}
/* Setup the device access block size to NTFS_BLOCK_SIZE. */
if (sb_set_blocksize(sb, NTFS_BLOCK_SIZE) != NTFS_BLOCK_SIZE) {
if (!silent)
ntfs_error(sb, "Unable to set block size.");
goto err_out_now;
}
/* Get the size of the device in units of NTFS_BLOCK_SIZE bytes. */
vol->nr_blocks = sb->s_bdev->bd_inode->i_size >> NTFS_BLOCK_SIZE_BITS;
/* Read the boot sector and return unlocked buffer head to it. */
if (!(bh = read_ntfs_boot_sector(sb, silent))) {
if (!silent)
ntfs_error(sb, "Not an NTFS volume.");
goto err_out_now;
}
/*
* Extract the data from the boot sector and setup the ntfs super block
* using it.
*/
result = parse_ntfs_boot_sector(vol, (NTFS_BOOT_SECTOR*)bh->b_data);
brelse(bh);
if (!result) {
if (!silent)
ntfs_error(sb, "Unsupported NTFS filesystem.");
goto err_out_now;
}
/*
* TODO: When we start coping with sector sizes different from
* NTFS_BLOCK_SIZE, we now probably need to set the blocksize of the
* device (probably to NTFS_BLOCK_SIZE).
*/
/* Setup remaining fields in the super block. */
sb->s_magic = NTFS_SB_MAGIC;
/*
* Ntfs allows 63 bits for the file size, i.e. correct would be:
* sb->s_maxbytes = ~0ULL >> 1;
* But the kernel uses a long as the page cache page index which on
* 32-bit architectures is only 32-bits. MAX_LFS_FILESIZE is kernel
* defined to the maximum the page cache page index can cope with
* without overflowing the index or to 2^63 - 1, whichever is smaller.
*/
sb->s_maxbytes = MAX_LFS_FILESIZE;
/*
* Now load the metadata required for the page cache and our address
* space operations to function. We do this by setting up a specialised
* read_inode method and then just calling the normal iget() to obtain
* the inode for $MFT which is sufficient to allow our normal inode
* operations and associated address space operations to function.
*/
/*
* Poison vol->mft_ino so we know whether iget() called into our
* ntfs_read_inode_mount() method.
*/
#define OGIN ((struct inode*)le32_to_cpu(0x4e49474f)) /* OGIN */
vol->mft_ino = OGIN;
sb->s_op = &ntfs_mount_sops;
tmp_ino = iget(vol->sb, FILE_MFT);
if (!tmp_ino || tmp_ino != vol->mft_ino || is_bad_inode(tmp_ino)) {
if (!silent)
ntfs_error(sb, "Failed to load essential metadata.");
if (tmp_ino && vol->mft_ino == OGIN)
ntfs_error(sb, "BUG: iget() did not call "
"ntfs_read_inode_mount() method!\n");
if (!tmp_ino)
goto cond_iput_mft_ino_err_out_now;
goto iput_tmp_ino_err_out_now;
}
/*
* Note: sb->s_op has already been set to &ntfs_sops by our specialized
* ntfs_read_inode_mount() method when it was invoked by iget().
*/
down(&ntfs_lock);
/*
* The current mount is a compression user if the cluster size is
* less than or equal 4kiB.
*/
if (vol->cluster_size <= 4096 && !ntfs_nr_compression_users++) {
result = allocate_compression_buffers();
if (result) {
ntfs_error(NULL, "Failed to allocate buffers "
"for compression engine.");
ntfs_nr_compression_users--;
up(&ntfs_lock);
goto iput_tmp_ino_err_out_now;
}
}
/*
* Increment the number of mounts and generate the global default
* upcase table if necessary. Also temporarily increment the number of
* upcase users to avoid race conditions with concurrent (u)mounts.
*/
if (!ntfs_nr_mounts++)
default_upcase = generate_default_upcase();
ntfs_nr_upcase_users++;
up(&ntfs_lock);
/*
* From now on, ignore @silent parameter. If we fail below this line,
* it will be due to a corrupt fs or a system error, so we report it.
*/
/*
* Open the system files with normal access functions and complete
* setting up the ntfs super block.
*/
if (!load_system_files(vol)) {
ntfs_error(sb, "Failed to load system files.");
goto unl_upcase_iput_tmp_ino_err_out_now;
}
if ((sb->s_root = d_alloc_root(vol->root_ino))) {
/* We increment i_count simulating an ntfs_iget(). */
atomic_inc(&vol->root_ino->i_count);
ntfs_debug("Exiting, status successful.");
/* Release the default upcase if it has no users. */
down(&ntfs_lock);
if (!--ntfs_nr_upcase_users && default_upcase) {
ntfs_free(default_upcase);
default_upcase = NULL;
}
up(&ntfs_lock);
return 0;
}
ntfs_error(sb, "Failed to allocate root directory.");
/* Clean up after the successful load_system_files() call from above. */
iput(vol->vol_ino);
vol->vol_ino = NULL;
/* NTFS 3.0+ specific clean up. */
if (vol->major_ver >= 3) {
iput(vol->secure_ino);
vol->secure_ino = NULL;
}
iput(vol->root_ino);
vol->root_ino = NULL;
iput(vol->lcnbmp_ino);
vol->lcnbmp_ino = NULL;
iput(vol->mftmirr_ino);
vol->mftmirr_ino = NULL;
iput(vol->mftbmp_ino);
vol->mftbmp_ino = NULL;
vol->upcase_len = 0;
if (vol->upcase != default_upcase)
ntfs_free(vol->upcase);
vol->upcase = NULL;
if (vol->nls_map) {
unload_nls(vol->nls_map);
vol->nls_map = NULL;
}
/* Error exit code path. */
unl_upcase_iput_tmp_ino_err_out_now:
/*
* Decrease the number of mounts and destroy the global default upcase
* table if necessary.
*/
down(&ntfs_lock);
ntfs_nr_mounts--;
if (!--ntfs_nr_upcase_users && default_upcase) {
ntfs_free(default_upcase);
default_upcase = NULL;
}
if (vol->cluster_size <= 4096 && !--ntfs_nr_compression_users)
free_compression_buffers();
up(&ntfs_lock);
iput_tmp_ino_err_out_now:
iput(tmp_ino);
cond_iput_mft_ino_err_out_now:
if (vol->mft_ino && vol->mft_ino != OGIN && vol->mft_ino != tmp_ino) {
iput(vol->mft_ino);
vol->mft_ino = NULL;
}
#undef OGIN
/*
* This is needed to get ntfs_clear_extent_inode() called for each
* inode we have ever called ntfs_iget()/iput() on, otherwise we A)
* leak resources and B) a subsequent mount fails automatically due to
* ntfs_iget() never calling down into our ntfs_read_locked_inode()
* method again... FIXME: Do we need to do this twice now because of
* attribute inodes? I think not, so leave as is for now... (AIA)
*/
if (invalidate_inodes(sb)) {
ntfs_error(sb, "Busy inodes left. This is most likely a NTFS "
"driver bug.");
/* Copied from fs/super.c. I just love this message. (-; */
printk("NTFS: Busy inodes after umount. Self-destruct in 5 "
"seconds. Have a nice day...\n");
}
/* Errors at this stage are irrelevant. */
err_out_now:
sb->s_fs_info = NULL;
kfree(vol);
ntfs_debug("Failed, returning -EINVAL.");
return -EINVAL;
}
/*
* This is a slab cache to optimize allocations and deallocations of Unicode
* strings of the maximum length allowed by NTFS, which is NTFS_MAX_NAME_LEN
* (255) Unicode characters + a terminating NULL Unicode character.
*/
kmem_cache_t *ntfs_name_cache;
/* Slab caches for efficient allocation/deallocation of of inodes. */
kmem_cache_t *ntfs_inode_cache;
kmem_cache_t *ntfs_big_inode_cache;
/* Init once constructor for the inode slab cache. */
static void ntfs_big_inode_init_once(void *foo, kmem_cache_t *cachep,
unsigned long flags)
{
ntfs_inode *ni = (ntfs_inode *)foo;
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR)
inode_init_once(VFS_I(ni));
}
/*
* Slab cache to optimize allocations and deallocations of attribute search
* contexts.
*/
kmem_cache_t *ntfs_attr_ctx_cache;
/* A global default upcase table and a corresponding reference count. */
wchar_t *default_upcase = NULL;
unsigned long ntfs_nr_upcase_users = 0;
/* The number of mounted filesystems. */
unsigned long ntfs_nr_mounts = 0;
/* Driver wide semaphore. */
DECLARE_MUTEX(ntfs_lock);
static struct super_block *ntfs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, ntfs_fill_super);
}
static struct file_system_type ntfs_fs_type = {
.owner = THIS_MODULE,
.name = "ntfs",
.get_sb = ntfs_get_sb,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
/* Stable names for the slab caches. */
static const char ntfs_attr_ctx_cache_name[] = "ntfs_attr_ctx_cache";
static const char ntfs_name_cache_name[] = "ntfs_name_cache";
static const char ntfs_inode_cache_name[] = "ntfs_inode_cache";
static const char ntfs_big_inode_cache_name[] = "ntfs_big_inode_cache";
static int __init init_ntfs_fs(void)
{
int err = 0;
/* This may be ugly but it results in pretty output so who cares. (-8 */
printk(KERN_INFO "NTFS driver " NTFS_VERSION " [Flags: R/"
#ifdef NTFS_RW
"W"
#else
"O"
#endif
#ifdef DEBUG
" DEBUG"
#endif
#ifdef MODULE
" MODULE"
#endif
"].\n");
ntfs_debug("Debug messages are enabled.");
ntfs_attr_ctx_cache = kmem_cache_create(ntfs_attr_ctx_cache_name,
sizeof(attr_search_context), 0 /* offset */,
SLAB_HWCACHE_ALIGN, NULL /* ctor */, NULL /* dtor */);
if (!ntfs_attr_ctx_cache) {
printk(KERN_CRIT "NTFS: Failed to create %s!\n",
ntfs_attr_ctx_cache_name);
goto ctx_err_out;
}
ntfs_name_cache = kmem_cache_create(ntfs_name_cache_name,
(NTFS_MAX_NAME_LEN+1) * sizeof(uchar_t), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (!ntfs_name_cache) {
printk(KERN_CRIT "NTFS: Failed to create %s!\n",
ntfs_name_cache_name);
goto name_err_out;
}
ntfs_inode_cache = kmem_cache_create(ntfs_inode_cache_name,
sizeof(ntfs_inode), 0,
SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, NULL, NULL);
if (!ntfs_inode_cache) {
printk(KERN_CRIT "NTFS: Failed to create %s!\n",
ntfs_inode_cache_name);
goto inode_err_out;
}
ntfs_big_inode_cache = kmem_cache_create(ntfs_big_inode_cache_name,
sizeof(big_ntfs_inode), 0,
SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
ntfs_big_inode_init_once, NULL);
if (!ntfs_big_inode_cache) {
printk(KERN_CRIT "NTFS: Failed to create %s!\n",
ntfs_big_inode_cache_name);
goto big_inode_err_out;
}
/* Register the ntfs sysctls. */
err = ntfs_sysctl(1);
if (err) {
printk(KERN_CRIT "NTFS: Failed to register NTFS sysctls!\n");
goto sysctl_err_out;
}
err = register_filesystem(&ntfs_fs_type);
if (!err) {
ntfs_debug("NTFS driver registered successfully.");
return 0; /* Success! */
}
printk(KERN_CRIT "NTFS: Failed to register NTFS file system driver!\n");
sysctl_err_out:
kmem_cache_destroy(ntfs_big_inode_cache);
big_inode_err_out:
kmem_cache_destroy(ntfs_inode_cache);
inode_err_out:
kmem_cache_destroy(ntfs_name_cache);
name_err_out:
kmem_cache_destroy(ntfs_attr_ctx_cache);
ctx_err_out:
if (!err) {
printk(KERN_CRIT "NTFS: Aborting NTFS file system driver "
"registration...\n");
err = -ENOMEM;
}
return err;
}
static void __exit exit_ntfs_fs(void)
{
int err = 0;
ntfs_debug("Unregistering NTFS driver.");
unregister_filesystem(&ntfs_fs_type);
if (kmem_cache_destroy(ntfs_big_inode_cache) && (err = 1))
printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
ntfs_big_inode_cache_name);
if (kmem_cache_destroy(ntfs_inode_cache) && (err = 1))
printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
ntfs_inode_cache_name);
if (kmem_cache_destroy(ntfs_name_cache) && (err = 1))
printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
ntfs_name_cache_name);
if (kmem_cache_destroy(ntfs_attr_ctx_cache) && (err = 1))
printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
ntfs_attr_ctx_cache_name);
if (err)
printk(KERN_CRIT "NTFS: This causes memory to leak! There is "
"probably a BUG in the driver! Please report "
"you saw this message to "
"linux-ntfs-dev@lists.sf.net\n");
/* Unregister the ntfs sysctls. */
ntfs_sysctl(0);
}
MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>");
MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2003 Anton Altaparmakov");
MODULE_LICENSE("GPL");
#ifdef DEBUG
MODULE_PARM(debug_msgs, "i");
MODULE_PARM_DESC(debug_msgs, "Enable debug messages.");
#endif
module_init(init_ntfs_fs)
module_exit(exit_ntfs_fs)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -