namei.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 482 行 · 第 1/2 页

C
482
字号
	ctx = NULL;	/* Check if a conversion error occurred. */	if ((signed)nls_name.len < 0) {		err = (signed)nls_name.len;		goto err_out;	}	nls_name.hash = full_name_hash(nls_name.name, nls_name.len);	/*	 * Note: No need for dent->d_lock lock as i_sem is held on the	 * parent inode.	 */	/* Does a dentry matching the nls_name exist already? */	real_dent = d_lookup(dent->d_parent, &nls_name);	/* If not, create it now. */	if (!real_dent) {		real_dent = d_alloc(dent->d_parent, &nls_name);		kfree(nls_name.name);		if (!real_dent) {			err = -ENOMEM;			goto err_out;		}		new_dent = d_splice_alias(dent_inode, real_dent);		if (new_dent)			dput(real_dent);		else			new_dent = real_dent;		return new_dent;	}	kfree(nls_name.name);	/* Matching dentry exists, check if it is negative. */	if (real_dent->d_inode) {		BUG_ON(real_dent->d_inode != dent_inode);		/*		 * Already have the inode and the dentry attached, decrement		 * the reference count to balance the ntfs_iget() we did		 * earlier on.  We found the dentry using d_lookup() so it		 * cannot be disconnected and thus we do not need to worry		 * about any NFS/disconnectedness issues here.		 */		iput(dent_inode);		return real_dent;	}	/*	 * Negative dentry: instantiate it unless the inode is a directory and	 * has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED),	 * in which case d_move() that in place of the found dentry.	 */	if (!S_ISDIR(dent_inode->i_mode)) {		/* Not a directory; everything is easy. */		d_instantiate(real_dent, dent_inode);		return real_dent;	}	spin_lock(&dcache_lock);	if (list_empty(&dent_inode->i_dentry)) {		/*		 * Directory without a 'disconnected' dentry; we need to do		 * d_instantiate() by hand because it takes dcache_lock which		 * we already hold.		 */		list_add(&real_dent->d_alias, &dent_inode->i_dentry);		real_dent->d_inode = dent_inode;		spin_unlock(&dcache_lock);		security_d_instantiate(real_dent, dent_inode);		return real_dent;	}	/*	 * Directory with a 'disconnected' dentry; get a reference to the	 * 'disconnected' dentry.	 */	new_dent = list_entry(dent_inode->i_dentry.next, struct dentry,			d_alias);	dget_locked(new_dent);	spin_unlock(&dcache_lock);	/* Do security vodoo. */	security_d_instantiate(real_dent, dent_inode);	/* Move new_dent in place of real_dent. */	d_move(new_dent, real_dent);	/* Balance the ntfs_iget() we did above. */	iput(dent_inode);	/* Throw away real_dent. */	dput(real_dent);	/* Use new_dent as the actual dentry. */	return new_dent;eio_err_out:	ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");	err = -EIO;err_out:	if (ctx)		ntfs_attr_put_search_ctx(ctx);	if (m)		unmap_mft_record(ni);	iput(dent_inode);	return ERR_PTR(err);   }}/** * Inode operations for directories. */struct inode_operations ntfs_dir_inode_ops = {	.lookup	= ntfs_lookup,	/* VFS: Lookup directory. */};/** * ntfs_get_parent - find the dentry of the parent of a given directory dentry * @child_dent:		dentry of the directory whose parent directory to find * * Find the dentry for the parent directory of the directory specified by the * dentry @child_dent.  This function is called from * fs/exportfs/expfs.c::find_exported_dentry() which in turn is called from the * default ->decode_fh() which is export_decode_fh() in the same file. * * The code is based on the ext3 ->get_parent() implementation found in * fs/ext3/namei.c::ext3_get_parent(). * * Note: ntfs_get_parent() is called with @child_dent->d_inode->i_sem down. * * Return the dentry of the parent directory on success or the error code on * error (IS_ERR() is true). */struct dentry *ntfs_get_parent(struct dentry *child_dent){	struct inode *vi = child_dent->d_inode;	ntfs_inode *ni = NTFS_I(vi);	MFT_RECORD *mrec;	ntfs_attr_search_ctx *ctx;	ATTR_RECORD *attr;	FILE_NAME_ATTR *fn;	struct inode *parent_vi;	struct dentry *parent_dent;	unsigned long parent_ino;	int err;	ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);	/* Get the mft record of the inode belonging to the child dentry. */	mrec = map_mft_record(ni);	if (IS_ERR(mrec))		return (struct dentry *)mrec;	/* Find the first file name attribute in the mft record. */	ctx = ntfs_attr_get_search_ctx(ni, mrec);	if (unlikely(!ctx)) {		unmap_mft_record(ni);		return ERR_PTR(-ENOMEM);	}try_next:	err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL,			0, ctx);	if (unlikely(err)) {		ntfs_attr_put_search_ctx(ctx);		unmap_mft_record(ni);		if (err == -ENOENT)			ntfs_error(vi->i_sb, "Inode 0x%lx does not have a "					"file name attribute.  Run chkdsk.",					vi->i_ino);		return ERR_PTR(err);	}	attr = ctx->attr;	if (unlikely(attr->non_resident))		goto try_next;	fn = (FILE_NAME_ATTR *)((u8 *)attr +			le16_to_cpu(attr->data.resident.value_offset));	if (unlikely((u8 *)fn + le32_to_cpu(attr->data.resident.value_length) >			(u8*)attr + le32_to_cpu(attr->length)))		goto try_next;	/* Get the inode number of the parent directory. */	parent_ino = MREF_LE(fn->parent_directory);	/* Release the search context and the mft record of the child. */	ntfs_attr_put_search_ctx(ctx);	unmap_mft_record(ni);	/* Get the inode of the parent directory. */	parent_vi = ntfs_iget(vi->i_sb, parent_ino);	if (IS_ERR(parent_vi) || unlikely(is_bad_inode(parent_vi))) {		if (!IS_ERR(parent_vi))			iput(parent_vi);		ntfs_error(vi->i_sb, "Failed to get parent directory inode "				"0x%lx of child inode 0x%lx.", parent_ino,				vi->i_ino);		return ERR_PTR(-EACCES);	}	/* Finally get a dentry for the parent directory and return it. */	parent_dent = d_alloc_anon(parent_vi);	if (unlikely(!parent_dent)) {		iput(parent_vi);		return ERR_PTR(-ENOMEM);	}	ntfs_debug("Done for inode 0x%lx.", vi->i_ino);	return parent_dent;}/** * ntfs_get_dentry - find a dentry for the inode from a file handle sub-fragment * @sb:		super block identifying the mounted ntfs volume * @fh:		the file handle sub-fragment * * Find a dentry for the inode given a file handle sub-fragment.  This function * is called from fs/exportfs/expfs.c::find_exported_dentry() which in turn is * called from the default ->decode_fh() which is export_decode_fh() in the * same file.  The code is closely based on the default ->get_dentry() helper * fs/exportfs/expfs.c::get_object(). * * The @fh contains two 32-bit unsigned values, the first one is the inode * number and the second one is the inode generation. * * Return the dentry on success or the error code on error (IS_ERR() is true). */struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh){	struct inode *vi;	struct dentry *dent;	unsigned long ino = ((u32 *)fh)[0];	u32 gen = ((u32 *)fh)[1];	ntfs_debug("Entering for inode 0x%lx, generation 0x%x.", ino, gen);	vi = ntfs_iget(sb, ino);	if (IS_ERR(vi)) {		ntfs_error(sb, "Failed to get inode 0x%lx.", ino);		return (struct dentry *)vi;	}	if (unlikely(is_bad_inode(vi) || vi->i_generation != gen)) {		/* We didn't find the right inode. */		ntfs_error(sb, "Inode 0x%lx, bad count: %d %d or version 0x%x "				"0x%x.", vi->i_ino, vi->i_nlink,				atomic_read(&vi->i_count), vi->i_generation,				gen);		iput(vi);		return ERR_PTR(-ESTALE);	}	/* Now find a dentry.  If possible, get a well-connected one. */	dent = d_alloc_anon(vi);	if (unlikely(!dent)) {		iput(vi);		return ERR_PTR(-ENOMEM);	}	ntfs_debug("Done for inode 0x%lx, generation 0x%x.", ino, gen);	return dent;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?