inode.c
来自「一个类似windows」· C语言 代码 · 共 2,026 行 · 第 1/5 页
C
2,026 行
* Verify the number of mft records does not exceed
* 2^32 - 1.
*/
if (ll >= (1ULL << 32)) {
ntfs_error(sb, "$MFT is too big! Aborting.");
goto put_err_out;
}
vol->nr_mft_records = ll;
/*
* We have got the first extent of the run_list for
* $MFT which means it is now relatively safe to call
* the normal ntfs_read_inode() function. Thus, take
* us out of the calling chain. Also we need to do this
* now because we need ntfs_read_inode() in place to
* get at subsequent extents.
*/
sb->s_op = &ntfs_sops;
/*
* Complete reading the inode, this will actually
* re-read the mft record for $MFT, this time entering
* it into the page cache with which we complete the
* kick start of the volume. It should be safe to do
* this now as the first extent of $MFT/$DATA is
* already known and we would hope that we don't need
* further extents in order to find the other
* attributes belonging to $MFT. Only time will tell if
* this is really the case. If not we will have to play
* magic at this point, possibly duplicating a lot of
* ntfs_read_inode() at this point. We will need to
* ensure we do enough of its work to be able to call
* ntfs_read_inode() on extents of $MFT/$DATA. But lets
* hope this never happens...
*/
ntfs_read_locked_inode(vi);
if (is_bad_inode(vi)) {
ntfs_error(sb, "ntfs_read_inode() of $MFT "
"failed. BUG or corrupt $MFT. "
"Run chkdsk and if no errors "
"are found, please report you "
"saw this message to "
"linux-ntfs-dev@lists.sf.net");
put_attr_search_ctx(ctx);
/* Revert to the safe super operations. */
sb->s_op = &ntfs_mount_sops;
goto out_now;
}
/*
* Re-initialize some specifics about $MFT's inode as
* ntfs_read_inode() will have set up the default ones.
*/
/* Set uid and gid to root. */
vi->i_uid = vi->i_gid = 0;
/* Regular file. No access for anyone. */
vi->i_mode = S_IFREG;
/* No VFS initiated operations allowed for $MFT. */
vi->i_op = &ntfs_empty_inode_ops;
vi->i_fop = &ntfs_empty_file_ops;
/* Put back our special address space operations. */
vi->i_mapping->a_ops = &ntfs_mft_aops;
}
/* Get the lowest vcn for the next extent. */
highest_vcn = sle64_to_cpu(attr->data.non_resident.highest_vcn);
next_vcn = highest_vcn + 1;
/* Only one extent or error, which we catch below. */
if (next_vcn <= 0)
break;
/* Avoid endless loops due to corruption. */
if (next_vcn < sle64_to_cpu(
attr->data.non_resident.lowest_vcn)) {
ntfs_error(sb, "$MFT has corrupt attribute list "
"attribute. Run chkdsk.");
goto put_err_out;
}
}
if (!attr) {
ntfs_error(sb, "$MFT/$DATA attribute not found. $MFT is "
"corrupt. Run chkdsk.");
goto put_err_out;
}
if (highest_vcn && highest_vcn != last_vcn - 1) {
ntfs_error(sb, "Failed to load the complete run list "
"for $MFT/$DATA. Driver bug or "
"corrupt $MFT. Run chkdsk.");
ntfs_debug("highest_vcn = 0x%Lx, last_vcn - 1 = 0x%Lx",
(long long)highest_vcn,
(long long)last_vcn - 1);
goto put_err_out;
}
put_attr_search_ctx(ctx);
ntfs_debug("Done.");
out_now:
ntfs_free(m);
return;
em_put_err_out:
ntfs_error(sb, "Couldn't find first extent of $DATA attribute in "
"attribute list. $MFT is corrupt. Run chkdsk.");
put_err_out:
put_attr_search_ctx(ctx);
err_out:
/* Make sure we revert to the safe super operations. */
sb->s_op = &ntfs_mount_sops;
ntfs_error(sb, "Failed. Marking inode as bad.");
make_bad_inode(vi);
goto out_now;
}
/**
* ntfs_dirty_inode - mark the inode's metadata dirty
* @vi: inode to mark dirty
*
* This is called from fs/inode.c::__mark_inode_dirty(), when the inode itself
* is being marked dirty. An example is when update_atime() is invoked.
*
* We mark the inode dirty by setting both the page in which the mft record
* resides and the buffer heads in that page which correspond to the mft record
* dirty. This ensures that the changes will eventually be propagated to disk
* when the inode is set dirty.
*
* FIXME: Can we do that with the buffer heads? I am not too sure. Because if we
* do that we need to make sure that the kernel will not write out those buffer
* heads or we are screwed as it will write corrupt data to disk. The only way
* a mft record can be written correctly is by mst protecting it, writting it
* synchronously and fast mst deprotecting it. During this period, obviously,
* the mft record must be marked as not uptodate, be locked for writing or
* whatever, so that nobody attempts anything stupid.
*
* FIXME: Do we need to check that the fs is not mounted read only? And what
* about the inode? Anything else?
*
* FIXME: As we are only a read only driver it is safe to just return here for
* the moment.
*/
void ntfs_dirty_inode(struct inode *vi)
{
ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
NInoSetDirty(NTFS_I(vi));
return;
}
/**
* ntfs_commit_inode - write out a dirty inode
* @ni: inode to write out
*
*/
int ntfs_commit_inode(ntfs_inode *ni)
{
ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
NInoClearDirty(ni);
return 0;
}
/**
* ntfs_put_inode - handler for when the inode reference count is decremented
* @vi: vfs inode
*
* The VFS calls ntfs_put_inode() every time the inode reference count (i_count)
* is about to be decremented (but before the decrement itself.
*
* If the inode @vi is a directory with a single reference, we need to put the
* attribute inode for the directory index bitmap, if it is present, otherwise
* the directory inode would remain pinned for ever (or rather until umount()
* time.
*/
void ntfs_put_inode(struct inode *vi)
{
if (S_ISDIR(vi->i_mode) && (atomic_read(&vi->i_count) == 2)) {
ntfs_inode *ni;
ni = NTFS_I(vi);
if (NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino) {
iput(ni->itype.index.bmp_ino);
ni->itype.index.bmp_ino = NULL;
}
}
return;
}
void __ntfs_clear_inode(ntfs_inode *ni)
{
int err;
ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
if (NInoDirty(ni)) {
err = ntfs_commit_inode(ni);
if (err) {
ntfs_error(ni->vol->sb, "Failed to commit dirty "
"inode synchronously.");
// FIXME: Do something!!!
}
}
/* Synchronize with ntfs_commit_inode(). */
down(&ni->mrec_lock);
up(&ni->mrec_lock);
if (NInoDirty(ni)) {
ntfs_error(ni->vol->sb, "Failed to commit dirty inode "
"asynchronously.");
// FIXME: Do something!!!
}
/* No need to lock at this stage as no one else has a reference. */
if (ni->nr_extents > 0) {
int i;
// FIXME: Handle dirty case for each extent inode!
for (i = 0; i < ni->nr_extents; i++)
ntfs_clear_extent_inode(ni->ext.extent_ntfs_inos[i]);
kfree(ni->ext.extent_ntfs_inos);
}
/* Free all alocated memory. */
down_write(&ni->run_list.lock);
if (ni->run_list.rl) {
ntfs_free(ni->run_list.rl);
ni->run_list.rl = NULL;
}
up_write(&ni->run_list.lock);
if (ni->attr_list) {
ntfs_free(ni->attr_list);
ni->attr_list = NULL;
}
down_write(&ni->attr_list_rl.lock);
if (ni->attr_list_rl.rl) {
ntfs_free(ni->attr_list_rl.rl);
ni->attr_list_rl.rl = NULL;
}
up_write(&ni->attr_list_rl.lock);
if (ni->name_len && ni->name != I30) {
/* Catch bugs... */
BUG_ON(!ni->name);
kfree(ni->name);
}
}
void ntfs_clear_extent_inode(ntfs_inode *ni)
{
__ntfs_clear_inode(ni);
/* Bye, bye... */
ntfs_destroy_extent_inode(ni);
}
/**
* ntfs_clear_big_inode - clean up the ntfs specific part of an inode
* @vi: vfs inode pending annihilation
*
* When the VFS is going to remove an inode from memory, ntfs_clear_big_inode()
* is called, which deallocates all memory belonging to the NTFS specific part
* of the inode and returns.
*
* If the MFT record is dirty, we commit it before doing anything else.
*/
void ntfs_clear_big_inode(struct inode *vi)
{
ntfs_inode *ni = NTFS_I(vi);
__ntfs_clear_inode(ni);
if (NInoAttr(ni)) {
/* Release the base inode if we are holding it. */
if (ni->nr_extents == -1) {
iput(VFS_I(ni->ext.base_ntfs_ino));
ni->nr_extents = 0;
ni->ext.base_ntfs_ino = NULL;
}
}
return;
}
/**
* ntfs_show_options - show mount options in /proc/mounts
* @sf: seq_file in which to write our mount options
* @mnt: vfs mount whose mount options to display
*
* Called by the VFS once for each mounted ntfs volume when someone reads
* /proc/mounts in order to display the NTFS specific mount options of each
* mount. The mount options of the vfs mount @mnt are written to the seq file
* @sf and success is returned.
*/
int ntfs_show_options(struct seq_file *sf, struct vfsmount *mnt)
{
ntfs_volume *vol = NTFS_SB(mnt->mnt_sb);
int i;
seq_printf(sf, ",uid=%i", vol->uid);
seq_printf(sf, ",gid=%i", vol->gid);
if (vol->fmask == vol->dmask)
seq_printf(sf, ",umask=0%o", vol->fmask);
else {
seq_printf(sf, ",fmask=0%o", vol->fmask);
seq_printf(sf, ",dmask=0%o", vol->dmask);
}
seq_printf(sf, ",nls=%s", vol->nls_map->charset);
if (NVolCaseSensitive(vol))
seq_printf(sf, ",case_sensitive");
if (NVolShowSystemFiles(vol))
seq_printf(sf, ",show_sys_files");
for (i = 0; on_errors_arr[i].val; i++) {
if (on_errors_arr[i].val & vol->on_errors)
seq_printf(sf, ",errors=%s", on_errors_arr[i].str);
}
seq_printf(sf, ",mft_zone_multiplier=%i", vol->mft_zone_multiplier);
return 0;
}
#ifdef NTFS_RW
/**
* ntfs_truncate - called when the i_size of an ntfs inode is changed
* @vi: inode for which the i_size was changed
*
* We don't support i_size changes yet.
*
* Called with ->i_sem held.
*/
void ntfs_truncate(struct inode *vi)
{
// TODO: Implement...
ntfs_warning(vi->i_sb, "Eeek: i_size may have changed! If you see "
"this right after a message from "
"ntfs_{prepare,commit}_{,nonresident_}write() then "
"just ignore it. Otherwise it is bad news.");
// TODO: reset i_size now!
return;
}
/**
* ntfs_setattr - called from notify_change() when an attribute is being changed
* @dentry: dentry whose attributes to change
* @attr: structure describing the attributes and the changes
*
* We have to trap VFS attempts to truncate the file described by @dentry as
* soon as possible, because we do not implement changes in i_size yet. So we
* abort all i_size changes here.
*
* Called with ->i_sem held.
*
* Basically this is a copy of generic notify_change() and inode_setattr()
* functionality, except we intercept and abort changes in i_size.
*/
int ntfs_setattr(struct dentry *dentry, struct iattr *attr)
{
struct inode *vi;
int err;
unsigned int ia_valid = attr->ia_valid;
vi = dentry->d_inode;
err = inode_change_ok(vi, attr);
if (err)
return err;
if ((ia_valid & ATTR_UID && attr->ia_uid != vi->i_uid) ||
(ia_valid & ATTR_GID && attr->ia_gid != vi->i_gid)) {
err = DQUOT_TRANSFER(vi, attr) ? -EDQUOT : 0;
if (err)
return err;
}
lock_kernel();
if (ia_valid & ATTR_SIZE) {
ntfs_error(vi->i_sb, "Changes in i_size are not supported "
"yet. Sorry.");
// TODO: Implement...
// err = vmtruncate(vi, attr->ia_size);
err = -EOPNOTSUPP;
if (err)
goto trunc_err;
}
if (ia_valid & ATTR_UID)
vi->i_uid = attr->ia_uid;
if (ia_valid & ATTR_GID)
vi->i_gid = attr->ia_gid;
if (ia_valid & ATTR_ATIME)
vi->i_atime = attr->ia_atime;
if (ia_valid & ATTR_MTIME)
vi->i_mtime = attr->ia_mtime;
if (ia_valid & ATTR_CTIME)
vi->i_ctime = attr->ia_ctime;
if (ia_valid & ATTR_MODE) {
vi->i_mode = attr->ia_mode;
if (!in_group_p(vi->i_gid) &&
!capable(CAP_FSETID))
vi->i_mode &= ~S_ISGID;
}
mark_inode_dirty(vi);
trunc_err:
unlock_kernel();
return err;
}
#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?