📄 inode.c
字号:
/** * inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project. * * Copyright (c) 2001-2007 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program/include file is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the main directory of the Linux-NTFS * distribution in the file COPYING); if not, write to the Free Software * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/buffer_head.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/mount.h>#include <linux/mutex.h>#include <linux/pagemap.h>#include <linux/quotaops.h>#include <linux/slab.h>#include "aops.h"#include "attrib.h"#include "bitmap.h"#include "dir.h"#include "debug.h"#include "inode.h"#include "lcnalloc.h"#include "malloc.h"#include "mft.h"#include "time.h"#include "ntfs.h"/** * ntfs_test_inode - compare two (possibly fake) inodes for equality * @vi: vfs inode which to test * @na: ntfs attribute which is being tested with * * Compare the ntfs attribute embedded in the ntfs specific part of the vfs * inode @vi for equality with the ntfs attribute @na. * * If searching for the normal file/directory inode, set @na->type to AT_UNUSED. * @na->name and @na->name_len are then ignored. * * Return 1 if the attributes match and 0 if not. * * NOTE: This function runs with the inode_lock spin lock held so it is not * allowed to sleep. */int ntfs_test_inode(struct inode *vi, ntfs_attr *na){ ntfs_inode *ni; if (vi->i_ino != na->mft_no) return 0; ni = NTFS_I(vi); /* If !NInoAttr(ni), @vi is a normal file or directory inode. */ if (likely(!NInoAttr(ni))) { /* If not looking for a normal inode this is a mismatch. */ if (unlikely(na->type != AT_UNUSED)) return 0; } else { /* A fake inode describing an attribute. */ if (ni->type != na->type) return 0; if (ni->name_len != na->name_len) return 0; if (na->name_len && memcmp(ni->name, na->name, na->name_len * sizeof(ntfschar))) return 0; } /* Match! */ return 1;}/** * ntfs_init_locked_inode - initialize an inode * @vi: vfs inode to initialize * @na: ntfs attribute which to initialize @vi to * * Initialize the vfs inode @vi with the values from the ntfs attribute @na in * order to enable ntfs_test_inode() to do its work. * * If initializing the normal file/directory inode, set @na->type to AT_UNUSED. * In that case, @na->name and @na->name_len should be set to NULL and 0, * respectively. Although that is not strictly necessary as * ntfs_read_locked_inode() will fill them in later. * * Return 0 on success and -errno on error. * * NOTE: This function runs with the inode_lock spin lock held so it is not * allowed to sleep. (Hence the GFP_ATOMIC allocation.) */static int ntfs_init_locked_inode(struct inode *vi, ntfs_attr *na){ ntfs_inode *ni = NTFS_I(vi); vi->i_ino = na->mft_no; ni->type = na->type; if (na->type == AT_INDEX_ALLOCATION) NInoSetMstProtected(ni); ni->name = na->name; ni->name_len = na->name_len; /* If initializing a normal inode, we are done. */ if (likely(na->type == AT_UNUSED)) { BUG_ON(na->name); BUG_ON(na->name_len); return 0; } /* It is a fake inode. */ NInoSetAttr(ni); /* * We have I30 global constant as an optimization as it is the name * in >99.9% of named attributes! The other <0.1% incur a GFP_ATOMIC * allocation but that is ok. And most attributes are unnamed anyway, * thus the fraction of named attributes with name != I30 is actually * absolutely tiny. */ if (na->name_len && na->name != I30) { unsigned int i; BUG_ON(!na->name); i = na->name_len * sizeof(ntfschar); ni->name = kmalloc(i + sizeof(ntfschar), GFP_ATOMIC); if (!ni->name) return -ENOMEM; memcpy(ni->name, na->name, i); ni->name[na->name_len] = 0; } return 0;}typedef int (*set_t)(struct inode *, void *);static int ntfs_read_locked_inode(struct inode *vi);static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi);static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi);/** * ntfs_iget - obtain a struct inode corresponding to a specific normal inode * @sb: super block of mounted volume * @mft_no: mft record number / inode number to obtain * * Obtain the struct inode corresponding to a specific normal inode (i.e. a * file or directory). * * If the inode is in the cache, it is just returned with an increased * reference count. Otherwise, a new struct inode is allocated and initialized, * and finally ntfs_read_locked_inode() is called to read in the inode and * fill in the remainder of the inode structure. * * Return the struct inode on success. Check the return value with IS_ERR() and * if true, the function failed and the error code is obtained from PTR_ERR(). */struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no){ struct inode *vi; int err; ntfs_attr na; na.mft_no = mft_no; na.type = AT_UNUSED; na.name = NULL; na.name_len = 0; vi = iget5_locked(sb, mft_no, (test_t)ntfs_test_inode, (set_t)ntfs_init_locked_inode, &na); if (unlikely(!vi)) return ERR_PTR(-ENOMEM); err = 0; /* If this is a freshly allocated inode, need to read it now. */ if (vi->i_state & I_NEW) { err = ntfs_read_locked_inode(vi); unlock_new_inode(vi); } /* * There is no point in keeping bad inodes around if the failure was * due to ENOMEM. We want to be able to retry again later. */ if (unlikely(err == -ENOMEM)) { iput(vi); vi = ERR_PTR(err); } return vi;}/** * ntfs_attr_iget - obtain a struct inode corresponding to an attribute * @base_vi: vfs base inode containing the attribute * @type: attribute type * @name: Unicode name of the attribute (NULL if unnamed) * @name_len: length of @name in Unicode characters (0 if unnamed) * * Obtain the (fake) struct inode corresponding to the attribute specified by * @type, @name, and @name_len, which is present in the base mft record * specified by the vfs inode @base_vi. * * If the attribute inode is in the cache, it is just returned with an * increased reference count. Otherwise, a new struct inode is allocated and * initialized, and finally ntfs_read_locked_attr_inode() is called to read the * attribute and fill in the inode structure. * * Note, for index allocation attributes, you need to use ntfs_index_iget() * instead of ntfs_attr_iget() as working with indices is a lot more complex. * * Return the struct inode of the attribute inode on success. Check the return * value with IS_ERR() and if true, the function failed and the error code is * obtained from PTR_ERR(). */struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPE type, ntfschar *name, u32 name_len){ struct inode *vi; int err; ntfs_attr na; /* Make sure no one calls ntfs_attr_iget() for indices. */ BUG_ON(type == AT_INDEX_ALLOCATION); na.mft_no = base_vi->i_ino; na.type = type; na.name = name; na.name_len = name_len; vi = iget5_locked(base_vi->i_sb, na.mft_no, (test_t)ntfs_test_inode, (set_t)ntfs_init_locked_inode, &na); if (unlikely(!vi)) return ERR_PTR(-ENOMEM); err = 0; /* If this is a freshly allocated inode, need to read it now. */ if (vi->i_state & I_NEW) { err = ntfs_read_locked_attr_inode(base_vi, vi); unlock_new_inode(vi); } /* * There is no point in keeping bad attribute inodes around. This also * simplifies things in that we never need to check for bad attribute * inodes elsewhere. */ if (unlikely(err)) { iput(vi); vi = ERR_PTR(err); } return vi;}/** * ntfs_index_iget - obtain a struct inode corresponding to an index * @base_vi: vfs base inode containing the index related attributes * @name: Unicode name of the index * @name_len: length of @name in Unicode characters * * Obtain the (fake) struct inode corresponding to the index specified by @name * and @name_len, which is present in the base mft record specified by the vfs * inode @base_vi. * * If the index inode is in the cache, it is just returned with an increased * reference count. Otherwise, a new struct inode is allocated and * initialized, and finally ntfs_read_locked_index_inode() is called to read * the index related attributes and fill in the inode structure. * * Return the struct inode of the index inode on success. Check the return * value with IS_ERR() and if true, the function failed and the error code is * obtained from PTR_ERR(). */struct inode *ntfs_index_iget(struct inode *base_vi, ntfschar *name, u32 name_len){ struct inode *vi; int err; ntfs_attr na; na.mft_no = base_vi->i_ino; na.type = AT_INDEX_ALLOCATION; na.name = name; na.name_len = name_len; vi = iget5_locked(base_vi->i_sb, na.mft_no, (test_t)ntfs_test_inode, (set_t)ntfs_init_locked_inode, &na); if (unlikely(!vi)) return ERR_PTR(-ENOMEM); err = 0; /* If this is a freshly allocated inode, need to read it now. */ if (vi->i_state & I_NEW) { err = ntfs_read_locked_index_inode(base_vi, vi); unlock_new_inode(vi); } /* * There is no point in keeping bad index inodes around. This also * simplifies things in that we never need to check for bad index * inodes elsewhere. */ if (unlikely(err)) { iput(vi); vi = ERR_PTR(err); } return vi;}struct inode *ntfs_alloc_big_inode(struct super_block *sb){ ntfs_inode *ni; ntfs_debug("Entering."); ni = kmem_cache_alloc(ntfs_big_inode_cache, GFP_NOFS); if (likely(ni != NULL)) { ni->state = 0; return VFS_I(ni); } ntfs_error(sb, "Allocation of NTFS big inode structure failed."); return NULL;}void ntfs_destroy_big_inode(struct inode *inode){ ntfs_inode *ni = NTFS_I(inode); ntfs_debug("Entering."); BUG_ON(ni->page); if (!atomic_dec_and_test(&ni->count)) BUG(); kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode));}static inline ntfs_inode *ntfs_alloc_extent_inode(void){ ntfs_inode *ni; ntfs_debug("Entering."); ni = kmem_cache_alloc(ntfs_inode_cache, GFP_NOFS); if (likely(ni != NULL)) { ni->state = 0; return ni; } ntfs_error(NULL, "Allocation of NTFS inode structure failed."); return NULL;}static void ntfs_destroy_extent_inode(ntfs_inode *ni){ ntfs_debug("Entering."); BUG_ON(ni->page); if (!atomic_dec_and_test(&ni->count)) BUG(); kmem_cache_free(ntfs_inode_cache, ni);}/* * The attribute runlist lock has separate locking rules from the * normal runlist lock, so split the two lock-classes: */static struct lock_class_key attr_list_rl_lock_class;/** * __ntfs_init_inode - initialize ntfs specific part of an inode * @sb: super block of mounted volume * @ni: freshly allocated ntfs inode which to initialize * * Initialize an ntfs inode to defaults. * * NOTE: ni->mft_no, ni->state, ni->type, ni->name, and ni->name_len are left * untouched. Make sure to initialize them elsewhere. * * Return zero on success and -ENOMEM on error. */void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni){ ntfs_debug("Entering."); rwlock_init(&ni->size_lock); ni->initialized_size = ni->allocated_size = 0; ni->seq_no = 0; atomic_set(&ni->count, 1); ni->vol = NTFS_SB(sb); ntfs_init_runlist(&ni->runlist); mutex_init(&ni->mrec_lock); ni->page = NULL; ni->page_ofs = 0; ni->attr_list_size = 0; ni->attr_list = NULL; ntfs_init_runlist(&ni->attr_list_rl); lockdep_set_class(&ni->attr_list_rl.lock, &attr_list_rl_lock_class); ni->itype.index.block_size = 0; ni->itype.index.vcn_size = 0; ni->itype.index.collation_rule = 0; ni->itype.index.block_size_bits = 0; ni->itype.index.vcn_size_bits = 0; mutex_init(&ni->extent_lock); ni->nr_extents = 0; ni->ext.base_ntfs_ino = NULL;}/* * Extent inodes get MFT-mapped in a nested way, while the base inode
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -