⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 namei.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *   Copyright (C) International Business Machines Corp., 2000-2004 *   Portions Copyright (C) Christoph Hellwig, 2001-2002 * *   This program 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 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;  if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/fs.h>#include <linux/ctype.h>#include <linux/quotaops.h>#include <linux/exportfs.h>#include "jfs_incore.h"#include "jfs_superblock.h"#include "jfs_inode.h"#include "jfs_dinode.h"#include "jfs_dmap.h"#include "jfs_unicode.h"#include "jfs_metapage.h"#include "jfs_xattr.h"#include "jfs_acl.h"#include "jfs_debug.h"/* * forward references */struct dentry_operations jfs_ci_dentry_operations;static s64 commitZeroLink(tid_t, struct inode *);/* * NAME:	free_ea_wmap(inode) * * FUNCTION:	free uncommitted extended attributes from working map * */static inline void free_ea_wmap(struct inode *inode){	dxd_t *ea = &JFS_IP(inode)->ea;	if (ea->flag & DXD_EXTENT) {		/* free EA pages from cache */		invalidate_dxd_metapages(inode, *ea);		dbFree(inode, addressDXD(ea), lengthDXD(ea));	}	ea->flag = 0;}/* * NAME:	jfs_create(dip, dentry, mode) * * FUNCTION:	create a regular file in the parent directory <dip> *		with name = <from dentry> and mode = <mode> * * PARAMETER:	dip	- parent directory vnode *		dentry	- dentry of new file *		mode	- create mode (rwxrwxrwx). *		nd- nd struct * * RETURN:	Errors from subroutines * */static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,		struct nameidata *nd){	int rc = 0;	tid_t tid;		/* transaction id */	struct inode *ip = NULL;	/* child directory inode */	ino_t ino;	struct component_name dname;	/* child directory name */	struct btstack btstack;	struct inode *iplist[2];	struct tblock *tblk;	jfs_info("jfs_create: dip:0x%p name:%s", dip, dentry->d_name.name);	/*	 * search parent directory for entry/freespace	 * (dtSearch() returns parent directory page pinned)	 */	if ((rc = get_UCSname(&dname, dentry)))		goto out1;	/*	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we	 * block there while holding dtree page, so we allocate the inode &	 * begin the transaction before we search the directory.	 */	ip = ialloc(dip, mode);	if (IS_ERR(ip)) {		rc = PTR_ERR(ip);		goto out2;	}	tid = txBegin(dip->i_sb, 0);	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);	rc = jfs_init_acl(tid, ip, dip);	if (rc)		goto out3;	rc = jfs_init_security(tid, ip, dip);	if (rc) {		txAbort(tid, 0);		goto out3;	}	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {		jfs_err("jfs_create: dtSearch returned %d", rc);		txAbort(tid, 0);		goto out3;	}	tblk = tid_to_tblock(tid);	tblk->xflag |= COMMIT_CREATE;	tblk->ino = ip->i_ino;	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;	iplist[0] = dip;	iplist[1] = ip;	/*	 * initialize the child XAD tree root in-line in inode	 */	xtInitRoot(tid, ip);	/*	 * create entry in parent directory for child directory	 * (dtInsert() releases parent directory page)	 */	ino = ip->i_ino;	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {		if (rc == -EIO) {			jfs_err("jfs_create: dtInsert returned -EIO");			txAbort(tid, 1);	/* Marks Filesystem dirty */		} else			txAbort(tid, 0);	/* Filesystem full */		goto out3;	}	ip->i_op = &jfs_file_inode_operations;	ip->i_fop = &jfs_file_operations;	ip->i_mapping->a_ops = &jfs_aops;	insert_inode_hash(ip);	mark_inode_dirty(ip);	dip->i_ctime = dip->i_mtime = CURRENT_TIME;	mark_inode_dirty(dip);	rc = txCommit(tid, 2, &iplist[0], 0);      out3:	txEnd(tid);	mutex_unlock(&JFS_IP(ip)->commit_mutex);	mutex_unlock(&JFS_IP(dip)->commit_mutex);	if (rc) {		free_ea_wmap(ip);		ip->i_nlink = 0;		iput(ip);	} else		d_instantiate(dentry, ip);      out2:	free_UCSname(&dname);      out1:	jfs_info("jfs_create: rc:%d", rc);	return rc;}/* * NAME:	jfs_mkdir(dip, dentry, mode) * * FUNCTION:	create a child directory in the parent directory <dip> *		with name = <from dentry> and mode = <mode> * * PARAMETER:	dip	- parent directory vnode *		dentry	- dentry of child directory *		mode	- create mode (rwxrwxrwx). * * RETURN:	Errors from subroutines * * note: * EACCESS: user needs search+write permission on the parent directory */static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode){	int rc = 0;	tid_t tid;		/* transaction id */	struct inode *ip = NULL;	/* child directory inode */	ino_t ino;	struct component_name dname;	/* child directory name */	struct btstack btstack;	struct inode *iplist[2];	struct tblock *tblk;	jfs_info("jfs_mkdir: dip:0x%p name:%s", dip, dentry->d_name.name);	/* link count overflow on parent directory ? */	if (dip->i_nlink == JFS_LINK_MAX) {		rc = -EMLINK;		goto out1;	}	/*	 * search parent directory for entry/freespace	 * (dtSearch() returns parent directory page pinned)	 */	if ((rc = get_UCSname(&dname, dentry)))		goto out1;	/*	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we	 * block there while holding dtree page, so we allocate the inode &	 * begin the transaction before we search the directory.	 */	ip = ialloc(dip, S_IFDIR | mode);	if (IS_ERR(ip)) {		rc = PTR_ERR(ip);		goto out2;	}	tid = txBegin(dip->i_sb, 0);	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);	rc = jfs_init_acl(tid, ip, dip);	if (rc)		goto out3;	rc = jfs_init_security(tid, ip, dip);	if (rc) {		txAbort(tid, 0);		goto out3;	}	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {		jfs_err("jfs_mkdir: dtSearch returned %d", rc);		txAbort(tid, 0);		goto out3;	}	tblk = tid_to_tblock(tid);	tblk->xflag |= COMMIT_CREATE;	tblk->ino = ip->i_ino;	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;	iplist[0] = dip;	iplist[1] = ip;	/*	 * initialize the child directory in-line in inode	 */	dtInitRoot(tid, ip, dip->i_ino);	/*	 * create entry in parent directory for child directory	 * (dtInsert() releases parent directory page)	 */	ino = ip->i_ino;	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {		if (rc == -EIO) {			jfs_err("jfs_mkdir: dtInsert returned -EIO");			txAbort(tid, 1);	/* Marks Filesystem dirty */		} else			txAbort(tid, 0);	/* Filesystem full */		goto out3;	}	ip->i_nlink = 2;	/* for '.' */	ip->i_op = &jfs_dir_inode_operations;	ip->i_fop = &jfs_dir_operations;	insert_inode_hash(ip);	mark_inode_dirty(ip);	/* update parent directory inode */	inc_nlink(dip);		/* for '..' from child directory */	dip->i_ctime = dip->i_mtime = CURRENT_TIME;	mark_inode_dirty(dip);	rc = txCommit(tid, 2, &iplist[0], 0);      out3:	txEnd(tid);	mutex_unlock(&JFS_IP(ip)->commit_mutex);	mutex_unlock(&JFS_IP(dip)->commit_mutex);	if (rc) {		free_ea_wmap(ip);		ip->i_nlink = 0;		iput(ip);	} else		d_instantiate(dentry, ip);      out2:	free_UCSname(&dname);      out1:	jfs_info("jfs_mkdir: rc:%d", rc);	return rc;}/* * NAME:	jfs_rmdir(dip, dentry) * * FUNCTION:	remove a link to child directory * * PARAMETER:	dip	- parent inode *		dentry	- child directory dentry * * RETURN:	-EINVAL	- if name is . or .. *		-EINVAL - if . or .. exist but are invalid. *		errors from subroutines * * note: * if other threads have the directory open when the last link * is removed, the "." and ".." entries, if present, are removed before * rmdir() returns and no new entries may be created in the directory, * but the directory is not removed until the last reference to * the directory is released (cf.unlink() of regular file). */static int jfs_rmdir(struct inode *dip, struct dentry *dentry){	int rc;	tid_t tid;		/* transaction id */	struct inode *ip = dentry->d_inode;	ino_t ino;	struct component_name dname;	struct inode *iplist[2];	struct tblock *tblk;	jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);	/* Init inode for quota operations. */	DQUOT_INIT(ip);	/* directory must be empty to be removed */	if (!dtEmpty(ip)) {		rc = -ENOTEMPTY;		goto out;	}	if ((rc = get_UCSname(&dname, dentry))) {		goto out;	}	tid = txBegin(dip->i_sb, 0);	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);	iplist[0] = dip;	iplist[1] = ip;	tblk = tid_to_tblock(tid);	tblk->xflag |= COMMIT_DELETE;	tblk->u.ip = ip;	/*	 * delete the entry of target directory from parent directory	 */	ino = ip->i_ino;	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {		jfs_err("jfs_rmdir: dtDelete returned %d", rc);		if (rc == -EIO)			txAbort(tid, 1);		txEnd(tid);		mutex_unlock(&JFS_IP(ip)->commit_mutex);		mutex_unlock(&JFS_IP(dip)->commit_mutex);		goto out2;	}	/* update parent directory's link count corresponding	 * to ".." entry of the target directory deleted	 */	dip->i_ctime = dip->i_mtime = CURRENT_TIME;	inode_dec_link_count(dip);	/*	 * OS/2 could have created EA and/or ACL	 */	/* free EA from both persistent and working map */	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {		/* free EA pages */		txEA(tid, ip, &JFS_IP(ip)->ea, NULL);	}	JFS_IP(ip)->ea.flag = 0;	/* free ACL from both persistent and working map */	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {		/* free ACL pages */		txEA(tid, ip, &JFS_IP(ip)->acl, NULL);	}	JFS_IP(ip)->acl.flag = 0;	/* mark the target directory as deleted */	clear_nlink(ip);	mark_inode_dirty(ip);	rc = txCommit(tid, 2, &iplist[0], 0);	txEnd(tid);	mutex_unlock(&JFS_IP(ip)->commit_mutex);	mutex_unlock(&JFS_IP(dip)->commit_mutex);	/*	 * Truncating the directory index table is not guaranteed.  It	 * may need to be done iteratively	 */	if (test_cflag(COMMIT_Stale, dip)) {		if (dip->i_size > 1)			jfs_truncate_nolock(dip, 0);		clear_cflag(COMMIT_Stale, dip);	}      out2:	free_UCSname(&dname);      out:	jfs_info("jfs_rmdir: rc:%d", rc);	return rc;}/* * NAME:	jfs_unlink(dip, dentry) * * FUNCTION:	remove a link to object <vp> named by <name> *		from parent directory <dvp> * * PARAMETER:	dip	- inode of parent directory *		dentry	- dentry of object to be removed * * RETURN:	errors from subroutines * * note: * temporary file: if one or more processes have the file open * when the last link is removed, the link will be removed before * unlink() returns, but the removal of the file contents will be * postponed until all references to the files are closed. * * JFS does NOT support unlink() on directories. * */static int jfs_unlink(struct inode *dip, struct dentry *dentry){	int rc;	tid_t tid;		/* transaction id */	struct inode *ip = dentry->d_inode;	ino_t ino;	struct component_name dname;	/* object name */	struct inode *iplist[2];	struct tblock *tblk;	s64 new_size = 0;	int commit_flag;	jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);	/* Init inode for quota operations. */	DQUOT_INIT(ip);	if ((rc = get_UCSname(&dname, dentry)))		goto out;	IWRITE_LOCK(ip, RDWRLOCK_NORMAL);	tid = txBegin(dip->i_sb, 0);	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);	iplist[0] = dip;	iplist[1] = ip;	/*	 * delete the entry of target file from parent directory	 */	ino = ip->i_ino;	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {		jfs_err("jfs_unlink: dtDelete returned %d", rc);		if (rc == -EIO)			txAbort(tid, 1);	/* Marks FS Dirty */		txEnd(tid);		mutex_unlock(&JFS_IP(ip)->commit_mutex);		mutex_unlock(&JFS_IP(dip)->commit_mutex);		IWRITE_UNLOCK(ip);		goto out1;	}	ASSERT(ip->i_nlink);	ip->i_ctime = dip->i_ctime = dip->i_mtime = CURRENT_TIME;	mark_inode_dirty(dip);	/* update target's inode */	inode_dec_link_count(ip);	/*	 *	commit zero link count object	 */	if (ip->i_nlink == 0) {		assert(!test_cflag(COMMIT_Nolink, ip));		/* free block resources */		if ((new_size = commitZeroLink(tid, ip)) < 0) {			txAbort(tid, 1);	/* Marks FS Dirty */			txEnd(tid);			mutex_unlock(&JFS_IP(ip)->commit_mutex);			mutex_unlock(&JFS_IP(dip)->commit_mutex);			IWRITE_UNLOCK(ip);			rc = new_size;			goto out1;		}		tblk = tid_to_tblock(tid);		tblk->xflag |= COMMIT_DELETE;		tblk->u.ip = ip;

⌨️ 快捷键说明

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