📄 super.c
字号:
if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
ntfs_error(sb, "Failed to load $LogFile.");
// FIMXE: We only want to empty the thing so pointless bailing
// out. Can recover/ignore.
goto iput_vol_err_out;
}
// FIXME: Empty the logfile, but only if not read-only.
// FIXME: What happens if someone remounts rw? We need to empty the file
// then. We need a flag to tell us whether we have done it already.
iput(tmp_ino);
/*
* Get the inode for the attribute definitions file and parse the
* attribute definitions.
*/
tmp_ino = ntfs_iget(sb, FILE_AttrDef);
if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
ntfs_error(sb, "Failed to load $AttrDef.");
goto iput_vol_err_out;
}
// FIXME: Parse the attribute definitions.
iput(tmp_ino);
/* Get the root directory inode. */
vol->root_ino = ntfs_iget(sb, FILE_root);
if (IS_ERR(vol->root_ino) || is_bad_inode(vol->root_ino)) {
if (!IS_ERR(vol->root_ino))
iput(vol->root_ino);
ntfs_error(sb, "Failed to load root directory.");
goto iput_vol_err_out;
}
/* If on NTFS versions before 3.0, we are done. */
if (vol->major_ver < 3)
return TRUE;
/* NTFS 3.0+ specific initialization. */
/* Get the security descriptors inode. */
vol->secure_ino = ntfs_iget(sb, FILE_Secure);
if (IS_ERR(vol->secure_ino) || is_bad_inode(vol->secure_ino)) {
if (!IS_ERR(vol->secure_ino))
iput(vol->secure_ino);
ntfs_error(sb, "Failed to load $Secure.");
goto iput_root_err_out;
}
// FIXME: Initialize security.
/* Get the extended system files' directory inode. */
tmp_ino = ntfs_iget(sb, FILE_Extend);
if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
ntfs_error(sb, "Failed to load $Extend.");
goto iput_sec_err_out;
}
// FIXME: Do something. E.g. want to delete the $UsnJrnl if exists.
// Note we might be doing this at the wrong level; we might want to
// d_alloc_root() and then do a "normal" open(2) of $Extend\$UsnJrnl
// rather than using ntfs_iget here, as we don't know the inode number
// for the files in $Extend directory.
iput(tmp_ino);
return TRUE;
iput_sec_err_out:
iput(vol->secure_ino);
iput_root_err_out:
iput(vol->root_ino);
iput_vol_err_out:
iput(vol->vol_ino);
iput_lcnbmp_err_out:
iput(vol->lcnbmp_ino);
iput_mirr_err_out:
iput(vol->mftmirr_ino);
iput_mftbmp_err_out:
iput(vol->mftbmp_ino);
return FALSE;
}
/**
* ntfs_put_super - called by the vfs to unmount a volume
* @vfs_sb: vfs superblock of volume to unmount
*
* ntfs_put_super() is called by the VFS (from fs/super.c::do_umount()) when
* the volume is being unmounted (umount system call has been invoked) and it
* releases all inodes and memory belonging to the NTFS specific part of the
* super block.
*/
static void ntfs_put_super(struct super_block *vfs_sb)
{
ntfs_volume *vol = NTFS_SB(vfs_sb);
ntfs_debug("Entering.");
iput(vol->vol_ino);
vol->vol_ino = NULL;
/* NTFS 3.0+ specific clean up. */
if (vol->major_ver >= 3) {
if (vol->secure_ino) {
iput(vol->secure_ino);
vol->secure_ino = NULL;
}
}
iput(vol->root_ino);
vol->root_ino = NULL;
down_write(&vol->lcnbmp_lock);
iput(vol->lcnbmp_ino);
vol->lcnbmp_ino = NULL;
up_write(&vol->lcnbmp_lock);
iput(vol->mftmirr_ino);
vol->mftmirr_ino = NULL;
down_write(&vol->mftbmp_lock);
iput(vol->mftbmp_ino);
vol->mftbmp_ino = NULL;
up_write(&vol->mftbmp_lock);
iput(vol->mft_ino);
vol->mft_ino = NULL;
vol->upcase_len = 0;
/*
* Decrease the number of mounts and destroy the global default upcase
* table if necessary. Also decrease the number of upcase users if we
* are a user.
*/
down(&ntfs_lock);
ntfs_nr_mounts--;
if (vol->upcase == default_upcase) {
ntfs_nr_upcase_users--;
vol->upcase = NULL;
}
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);
if (vol->upcase) {
ntfs_free(vol->upcase);
vol->upcase = NULL;
}
if (vol->nls_map) {
unload_nls(vol->nls_map);
vol->nls_map = NULL;
}
vfs_sb->s_fs_info = NULL;
kfree(vol);
return;
}
/**
* get_nr_free_clusters - return the number of free clusters on a volume
* @vol: ntfs volume for which to obtain free cluster count
*
* Calculate the number of free clusters on the mounted NTFS volume @vol. We
* actually calculate the number of clusters in use instead because this
* allows us to not care about partial pages as these will be just zero filled
* and hence not be counted as allocated clusters.
*
* The only particularity is that clusters beyond the end of the logical ntfs
* volume will be marked as allocated to prevent errors which means we have to
* discount those at the end. This is important as the cluster bitmap always
* has a size in multiples of 8 bytes, i.e. up to 63 clusters could be outside
* the logical volume and marked in use when they are not as they do not exist.
*
* If any pages cannot be read we assume all clusters in the erroring pages are
* in use. This means we return an underestimate on errors which is better than
* an overestimate.
*/
static s64 get_nr_free_clusters(ntfs_volume *vol)
{
s64 nr_free = vol->nr_clusters;
u32 *kaddr;
struct address_space *mapping = vol->lcnbmp_ino->i_mapping;
filler_t *readpage = (filler_t*)mapping->a_ops->readpage;
struct page *page;
unsigned long index, max_index;
unsigned int max_size;
ntfs_debug("Entering.");
/* Serialize accesses to the cluster bitmap. */
down_read(&vol->lcnbmp_lock);
/*
* Convert the number of bits into bytes rounded up, then convert into
* multiples of PAGE_CACHE_SIZE, rounding up so that if we have one
* full and one partial page max_index = 2.
*/
max_index = (((vol->nr_clusters + 7) >> 3) + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;
/* Use multiples of 4 bytes. */
max_size = PAGE_CACHE_SIZE >> 2;
ntfs_debug("Reading $Bitmap, max_index = 0x%lx, max_size = 0x%x.",
max_index, max_size);
for (index = 0UL; index < max_index; index++) {
unsigned int i;
/*
* Read the page from page cache, getting it from backing store
* if necessary, and increment the use count.
*/
page = read_cache_page(mapping, index, (filler_t*)readpage,
NULL);
/* Ignore pages which errored synchronously. */
if (IS_ERR(page)) {
ntfs_debug("Sync read_cache_page() error. Skipping "
"page (index 0x%lx).", index);
nr_free -= PAGE_CACHE_SIZE * 8;
continue;
}
wait_on_page_locked(page);
/* Ignore pages which errored asynchronously. */
if (!PageUptodate(page)) {
ntfs_debug("Async read_cache_page() error. Skipping "
"page (index 0x%lx).", index);
page_cache_release(page);
nr_free -= PAGE_CACHE_SIZE * 8;
continue;
}
kaddr = (u32*)kmap_atomic(page, KM_USER0);
/*
* For each 4 bytes, subtract the number of set bits. If this
* is the last page and it is partial we don't really care as
* it just means we do a little extra work but it won't affect
* the result as all out of range bytes are set to zero by
* ntfs_readpage().
*/
for (i = 0; i < max_size; i++)
nr_free -= (s64)hweight32(kaddr[i]);
kunmap_atomic(kaddr, KM_USER0);
page_cache_release(page);
}
ntfs_debug("Finished reading $Bitmap, last index = 0x%lx.", index - 1);
/*
* Fixup for eventual bits outside logical ntfs volume (see function
* description above).
*/
if (vol->nr_clusters & 63)
nr_free += 64 - (vol->nr_clusters & 63);
up_read(&vol->lcnbmp_lock);
/* If errors occured we may well have gone below zero, fix this. */
if (nr_free < 0)
nr_free = 0;
ntfs_debug("Exiting.");
return nr_free;
}
/**
* __get_nr_free_mft_records - return the number of free inodes on a volume
* @vol: ntfs volume for which to obtain free inode count
*
* Calculate the number of free mft records (inodes) on the mounted NTFS
* volume @vol. We actually calculate the number of mft records in use instead
* because this allows us to not care about partial pages as these will be just
* zero filled and hence not be counted as allocated mft record.
*
* If any pages cannot be read we assume all mft records in the erroring pages
* are in use. This means we return an underestimate on errors which is better
* than an overestimate.
*
* NOTE: Caller must hold mftbmp_lock rw_semaphore for reading or writing.
*/
static unsigned long __get_nr_free_mft_records(ntfs_volume *vol)
{
s64 nr_free = vol->nr_mft_records;
u32 *kaddr;
struct address_space *mapping = vol->mftbmp_ino->i_mapping;
filler_t *readpage = (filler_t*)mapping->a_ops->readpage;
struct page *page;
unsigned long index, max_index;
unsigned int max_size;
ntfs_debug("Entering.");
/*
* Convert the number of bits into bytes rounded up, then convert into
* multiples of PAGE_CACHE_SIZE, rounding up so that if we have one
* full and one partial page max_index = 2.
*/
max_index = (((vol->nr_mft_records + 7) >> 3) + PAGE_CACHE_SIZE - 1) >>
PAGE_CACHE_SHIFT;
/* Use multiples of 4 bytes. */
max_size = PAGE_CACHE_SIZE >> 2;
ntfs_debug("Reading $MFT/$BITMAP, max_index = 0x%lx, max_size = "
"0x%x.", max_index, max_size);
for (index = 0UL; index < max_index; index++) {
unsigned int i;
/*
* Read the page from page cache, getting it from backing store
* if necessary, and increment the use count.
*/
page = read_cache_page(mapping, index, (filler_t*)readpage,
NULL);
/* Ignore pages which errored synchronously. */
if (IS_ERR(page)) {
ntfs_debug("Sync read_cache_page() error. Skipping "
"page (index 0x%lx).", index);
nr_free -= PAGE_CACHE_SIZE * 8;
continue;
}
wait_on_page_locked(page);
/* Ignore pages which errored asynchronously. */
if (!PageUptodate(page)) {
ntfs_debug("Async read_cache_page() error. Skipping "
"page (index 0x%lx).", index);
page_cache_release(page);
nr_free -= PAGE_CACHE_SIZE * 8;
continue;
}
kaddr = (u32*)kmap_atomic(page, KM_USER0);
/*
* For each 4 bytes, subtract the number of set bits. If this
* is the last page and it is partial we don't really care as
* it just means we do a little extra work but it won't affect
* the result as all out of range bytes are set to zero by
* ntfs_readpage().
*/
for (i = 0; i < max_size; i++)
nr_free -= (s64)hweight32(kaddr[i]);
kunmap_atomic(kaddr, KM_USER0);
page_cache_release(page);
}
ntfs_debug("Finished reading $MFT/$BITMAP, last index = 0x%lx.",
index - 1);
/* If errors occured we may well have gone below zero, fix this. */
if (nr_free < 0)
nr_free = 0;
ntfs_debug("Exiting.");
return nr_free;
}
/**
* ntfs_statfs - return information about mounted NTFS volume
* @sb: super block of mounted volume
* @sfs: statfs structure in which to return the information
*
* Return information about the mounted NTFS volume @sb in the statfs structure
* pointed to by @sfs (this is initialized with zeros before ntfs_statfs is
* called). We interpret the values to be correct of the moment in time at
* which we are called. Most values are variable otherwise and this isn't just
* the free values but the totals as well. For example we can increase the
* total number of file nodes if we run out and we can keep doing this until
* there is no more space on the volume left at all.
*
* Called from vfs_statfs which is used to handle the statfs, fstatfs, and
* ustat system calls.
*
* Return 0 on success or -errno on error.
*/
static int ntfs_statfs(struct super_block *sb, struct kstatfs *sfs)
{
ntfs_volume *vol = NTFS_SB(sb);
s64 size;
ntfs_debug("Entering.");
/* Type of filesystem. */
sfs->f_type = NTFS_SB_MAGIC;
/* Optimal transfer block size. */
sfs->f_bsize = PAGE_CACHE_SIZE;
/*
* Total data blocks in file system in units of f_bsize and since
* inodes are also stored in data blocs ($MFT is a file) this is just
* the total clusters.
*/
sfs->f_blocks = vol->nr_clusters << vol->cluster_size_bits >>
PAGE_CACHE_SHIFT;
/* Free data blocks in file system in units of f_bsize. */
size = get_nr_free_clusters(vol) << vol->cluster_size_bits >>
PAGE_CACHE_SHIFT;
if (size < 0LL)
size = 0LL;
/* Free blocks avail to non-superuser, same as above on NTFS. */
sfs->f_bavail = sfs->f_bfree = size;
/* Serialize accesses to the inode bitmap. */
down_read(&vol->mftbmp_lock);
/* Total file nodes in file system (at this moment in time). */
sfs->f_files = vol->mft_ino->i_size >> vol->mft_record_size_bits;
/* Free file nodes in fs (based on current total count). */
sfs->f_ffree = __get_nr_free_mft_records(vol);
up_read(&vol->mftbmp_lock);
/*
* File system id. This is extremely *nix flavour dependent and even
* within Linux itself all fs do their own thing. I interpret this to
* mean a unique id associated with the mounted fs and not the id
* associated with the file system driver, the latter is already given
* by the file system type in sfs->f_type. Thus we use the 64-bit
* volume serial number splitting it into two 32-bit parts. We enter
* the least significant 32-bits in f_fsid[0] and the most significant
* 32-bits in f_fsid[1].
*/
sfs->f_fsid.val[0] = vol->serial_no & 0xffffffff;
sfs->f_fsid.val[1] = (vol->serial_no >> 32) & 0xffffffff;
/* Maximum length of filenames. */
sfs->f_namelen = NTFS_MAX_NAME_LEN;
return 0;
}
/**
* Super operations for mount time when we don't have enough setup to use the
* proper functions.
*/
struct super_operations ntfs_mount_sops = {
.alloc_inode = ntfs_alloc_big_inode, /* VFS: Allocate new inode. */
.destroy_inode = ntfs_destroy_big_inode, /* VFS: Deallocate inode. */
.read_inode = ntfs_read_inode_mount, /* VFS: Load inode from disk,
called from iget(). */
.clear_inode = ntfs_clear_big_inode, /* VFS: Called when inode is
removed from memory. */
};
/**
* The complete super operations.
*/
struct super_operations ntfs_sops = {
.alloc_inode = ntfs_alloc_big_inode, /* VFS: Allocate new inode. */
.destroy_inode = ntfs_destroy_big_inode, /* VFS: Deallocate inode. */
//.dirty_inode = ntfs_dirty_inode, /* VFS: Called from
// __mark_inode_dirty(). */
//.write_inode = NULL, /* VFS: Write dirty inode to disk. */
.put_inode = ntfs_put_inode, /* VFS: Called just before the inode
reference count is decreased. */
//.delete_inode = NULL, /* VFS: Delete inode from disk. Called
// when i_count becomes 0 and i_nlink
// is also 0. */
.put_super = ntfs_put_super, /* Syscall: umount. */
//write_super = NULL, /* Flush dirty super block to disk. */
//write_super_lockfs = NULL, /* ? */
//unlockfs = NULL, /* ? */
.statfs = ntfs_statfs, /* Syscall: statfs */
.remount_fs = ntfs_remount, /* Syscall: mount -o remount. */
.clear_inode = ntfs_clear_big_inode, /* VFS: Called when an inode is
removed from memory. */
//.umount_begin = NULL, /* Forced umount. */
.show_options = ntfs_show_options, /* Show mount options in proc. */
};
/**
* ntfs_fill_super - mount an ntfs files system
* @sb: super block of ntfs file system to mount
* @opt: string containing the mount options
* @silent: silence error output
*
* ntfs_fill_super() is called by the VFS to mount the device described by @sb
* with the mount otions in @data with the NTFS file system.
*
* If @silent is true, remain silent even if errors are detected. This is used
* during bootup, when the kernel tries to mount the root file system with all
* registered file systems one after the other until one succeeds. This implies
* that all file systems except the correct one will quite correctly and
* expectedly return an error, but nobody wants to see error messages when in
* fact this is what is supposed to happen.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -