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

📄 dir.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	struct iattr attr;	struct nfs_fattr fattr;	struct nfs_fh fhandle;	int error;	dfprintk(VFS, "NFS: mknod(%s/%ld, %s\n", dir->i_sb->s_id,		dir->i_ino, dentry->d_name.name);	if (!new_valid_dev(rdev))		return -EINVAL;	attr.ia_mode = mode;	attr.ia_valid = ATTR_MODE;	lock_kernel();	nfs_begin_data_update(dir);	error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev,					&fhandle, &fattr);	nfs_end_data_update(dir);	if (!error)		error = nfs_instantiate(dentry, &fhandle, &fattr);	else		d_drop(dentry);	unlock_kernel();	return error;}/* * See comments for nfs_proc_create regarding failed operations. */static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode){	struct iattr attr;	struct nfs_fattr fattr;	struct nfs_fh fhandle;	int error;	dfprintk(VFS, "NFS: mkdir(%s/%ld, %s\n", dir->i_sb->s_id,		dir->i_ino, dentry->d_name.name);	attr.ia_valid = ATTR_MODE;	attr.ia_mode = mode | S_IFDIR;	lock_kernel();#if 0	/*	 * Always drop the dentry, we can't always depend on	 * the fattr returned by the server (AIX seems to be	 * broken). We're better off doing another lookup than	 * depending on potentially bogus information.	 */	d_drop(dentry);#endif	nfs_begin_data_update(dir);	error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle,					&fattr);	nfs_end_data_update(dir);	if (!error)		error = nfs_instantiate(dentry, &fhandle, &fattr);	else		d_drop(dentry);	unlock_kernel();	return error;}static int nfs_rmdir(struct inode *dir, struct dentry *dentry){	int error;	dfprintk(VFS, "NFS: rmdir(%s/%ld, %s\n", dir->i_sb->s_id,		dir->i_ino, dentry->d_name.name);	lock_kernel();	nfs_begin_data_update(dir);	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);	/* Ensure the VFS deletes this inode */	if (error == 0 && dentry->d_inode != NULL)		dentry->d_inode->i_nlink = 0;	nfs_end_data_update(dir);	unlock_kernel();	return error;}static int nfs_sillyrename(struct inode *dir, struct dentry *dentry){	static unsigned int sillycounter;	const int      i_inosize  = sizeof(dir->i_ino)*2;	const int      countersize = sizeof(sillycounter)*2;	const int      slen       = strlen(".nfs") + i_inosize + countersize;	char           silly[slen+1];	struct qstr    qsilly;	struct dentry *sdentry;	int            error = -EIO;	dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",		dentry->d_parent->d_name.name, dentry->d_name.name, 		atomic_read(&dentry->d_count));#ifdef NFS_PARANOIAif (!dentry->d_inode)printk("NFS: silly-renaming %s/%s, negative dentry??\n",dentry->d_parent->d_name.name, dentry->d_name.name);#endif	/*	 * We don't allow a dentry to be silly-renamed twice.	 */	error = -EBUSY;	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)		goto out;	sprintf(silly, ".nfs%*.*lx",		i_inosize, i_inosize, dentry->d_inode->i_ino);	sdentry = NULL;	do {		char *suffix = silly + slen - countersize;		dput(sdentry);		sillycounter++;		sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);		dfprintk(VFS, "trying to rename %s to %s\n",			 dentry->d_name.name, silly);				sdentry = lookup_one_len(silly, dentry->d_parent, slen);		/*		 * N.B. Better to return EBUSY here ... it could be		 * dangerous to delete the file while it's in use.		 */		if (IS_ERR(sdentry))			goto out;	} while(sdentry->d_inode != NULL); /* need negative lookup */	qsilly.name = silly;	qsilly.len  = strlen(silly);	nfs_begin_data_update(dir);	if (dentry->d_inode) {		nfs_begin_data_update(dentry->d_inode);		error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,				dir, &qsilly);		nfs_end_data_update(dentry->d_inode);	} else		error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,				dir, &qsilly);	nfs_end_data_update(dir);	if (!error) {		nfs_renew_times(dentry);		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));		d_move(dentry, sdentry);		error = nfs_async_unlink(dentry); 		/* If we return 0 we don't unlink */	}	dput(sdentry);out:	return error;}/* * Remove a file after making sure there are no pending writes, * and after checking that the file has only one user.  * * We invalidate the attribute cache and free the inode prior to the operation * to avoid possible races if the server reuses the inode. */static int nfs_safe_remove(struct dentry *dentry){	struct inode *dir = dentry->d_parent->d_inode;	struct inode *inode = dentry->d_inode;	int error = -EBUSY;			dfprintk(VFS, "NFS: safe_remove(%s/%s)\n",		dentry->d_parent->d_name.name, dentry->d_name.name);	/* If the dentry was sillyrenamed, we simply call d_delete() */	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {		error = 0;		goto out;	}	nfs_begin_data_update(dir);	if (inode != NULL) {		nfs_begin_data_update(inode);		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);		/* The VFS may want to delete this inode */		if (error == 0)			inode->i_nlink--;		nfs_end_data_update(inode);	} else		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);	nfs_end_data_update(dir);out:	return error;}/*  We do silly rename. In case sillyrename() returns -EBUSY, the inode *  belongs to an active ".nfs..." file and we return -EBUSY. * *  If sillyrename() returns 0, we do nothing, otherwise we unlink. */static int nfs_unlink(struct inode *dir, struct dentry *dentry){	int error;	int need_rehash = 0;	dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id,		dir->i_ino, dentry->d_name.name);	lock_kernel();	spin_lock(&dcache_lock);	spin_lock(&dentry->d_lock);	if (atomic_read(&dentry->d_count) > 1) {		spin_unlock(&dentry->d_lock);		spin_unlock(&dcache_lock);		error = nfs_sillyrename(dir, dentry);		unlock_kernel();		return error;	}	if (!d_unhashed(dentry)) {		__d_drop(dentry);		need_rehash = 1;	}	spin_unlock(&dentry->d_lock);	spin_unlock(&dcache_lock);	error = nfs_safe_remove(dentry);	if (!error) {		nfs_renew_times(dentry);		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));	} else if (need_rehash)		d_rehash(dentry);	unlock_kernel();	return error;}static intnfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname){	struct iattr attr;	struct nfs_fattr sym_attr;	struct nfs_fh sym_fh;	struct qstr qsymname;	int error;	dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id,		dir->i_ino, dentry->d_name.name, symname);#ifdef NFS_PARANOIAif (dentry->d_inode)printk("nfs_proc_symlink: %s/%s not negative!\n",dentry->d_parent->d_name.name, dentry->d_name.name);#endif	/*	 * Fill in the sattr for the call. 	 * Note: SunOS 4.1.2 crashes if the mode isn't initialized!	 */	attr.ia_valid = ATTR_MODE;	attr.ia_mode = S_IFLNK | S_IRWXUGO;	qsymname.name = symname;	qsymname.len  = strlen(symname);	lock_kernel();	nfs_begin_data_update(dir);	error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,					  &attr, &sym_fh, &sym_attr);	nfs_end_data_update(dir);	if (!error) {		error = nfs_instantiate(dentry, &sym_fh, &sym_attr);	} else {		if (error == -EEXIST)			printk("nfs_proc_symlink: %s/%s already exists??\n",			       dentry->d_parent->d_name.name, dentry->d_name.name);		d_drop(dentry);	}	unlock_kernel();	return error;}static int nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry){	struct inode *inode = old_dentry->d_inode;	int error;	dfprintk(VFS, "NFS: link(%s/%s -> %s/%s)\n",		old_dentry->d_parent->d_name.name, old_dentry->d_name.name,		dentry->d_parent->d_name.name, dentry->d_name.name);	/*	 * Drop the dentry in advance to force a new lookup.	 * Since nfs_proc_link doesn't return a file handle,	 * we can't use the existing dentry.	 */	lock_kernel();	d_drop(dentry);	nfs_begin_data_update(dir);	nfs_begin_data_update(inode);	error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);	nfs_end_data_update(inode);	nfs_end_data_update(dir);	unlock_kernel();	return error;}/* * RENAME * FIXME: Some nfsds, like the Linux user space nfsd, may generate a * different file handle for the same inode after a rename (e.g. when * moving to a different directory). A fail-safe method to do so would * be to look up old_dir/old_name, create a link to new_dir/new_name and * rename the old file using the sillyrename stuff. This way, the original * file in old_dir will go away when the last process iput()s the inode. * * FIXED. *  * It actually works quite well. One needs to have the possibility for * at least one ".nfs..." file in each directory the file ever gets * moved or linked to which happens automagically with the new * implementation that only depends on the dcache stuff instead of * using the inode layer * * Unfortunately, things are a little more complicated than indicated * above. For a cross-directory move, we want to make sure we can get * rid of the old inode after the operation.  This means there must be * no pending writes (if it's a file), and the use count must be 1. * If these conditions are met, we can drop the dentries before doing * the rename. */static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,		      struct inode *new_dir, struct dentry *new_dentry){	struct inode *old_inode = old_dentry->d_inode;	struct inode *new_inode = new_dentry->d_inode;	struct dentry *dentry = NULL, *rehash = NULL;	int error = -EBUSY;	/*	 * To prevent any new references to the target during the rename,	 * we unhash the dentry and free the inode in advance.	 */	lock_kernel();	if (!d_unhashed(new_dentry)) {		d_drop(new_dentry);		rehash = new_dentry;	}	dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n",		 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,		 new_dentry->d_parent->d_name.name, new_dentry->d_name.name,		 atomic_read(&new_dentry->d_count));	/*	 * First check whether the target is busy ... we can't	 * safely do _any_ rename if the target is in use.	 *	 * For files, make a copy of the dentry and then do a 	 * silly-rename. If the silly-rename succeeds, the	 * copied dentry is hashed and becomes the new target.	 */	if (!new_inode)		goto go_ahead;	if (S_ISDIR(new_inode->i_mode))		goto out;	else if (atomic_read(&new_dentry->d_count) > 1) {		int err;		/* copy the target dentry's name */		dentry = d_alloc(new_dentry->d_parent,				 &new_dentry->d_name);		if (!dentry)			goto out;		/* silly-rename the existing target ... */		err = nfs_sillyrename(new_dir, new_dentry);		if (!err) {			new_dentry = rehash = dentry;			new_inode = NULL;			/* instantiate the replacement target */			d_instantiate(new_dentry, NULL);		}		/* dentry still busy? */		if (atomic_read(&new_dentry->d_count) > 1) {#ifdef NFS_PARANOIA			printk("nfs_rename: target %s/%s busy, d_count=%d\n",			       new_dentry->d_parent->d_name.name,			       new_dentry->d_name.name,			       atomic_read(&new_dentry->d_count));#endif			goto out;		}	}go_ahead:	/*	 * ... prune child dentries and writebacks if needed.	 */	if (atomic_read(&old_dentry->d_count) > 1) {		nfs_wb_all(old_inode);		shrink_dcache_parent(old_dentry);	}	if (new_inode)		d_delete(new_dentry);	nfs_begin_data_update(old_dir);	nfs_begin_data_update(new_dir);	nfs_begin_data_update(old_inode);	error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,					   new_dir, &new_dentry->d_name);	nfs_end_data_update(old_inode);	nfs_end_data_update(new_dir);	nfs_end_data_update(old_dir);out:	if (rehash)		d_rehash(rehash);	if (!error) {		if (!S_ISDIR(old_inode->i_mode))			d_move(old_dentry, new_dentry);		nfs_renew_times(new_dentry);		nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir));	}	/* new dentry created? */	if (dentry)		dput(dentry);	unlock_kernel();	return error;}int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res){	struct nfs_access_entry *cache = &NFS_I(inode)->cache_access;	if (cache->cred != cred			|| time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))			|| (NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR))		return -ENOENT;	memcpy(res, cache, sizeof(*res));	return 0;}void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set){	struct nfs_access_entry *cache = &NFS_I(inode)->cache_access;	if (cache->cred != set->cred) {		if (cache->cred)			put_rpccred(cache->cred);		cache->cred = get_rpccred(set->cred);	}	cache->jiffies = set->jiffies;	cache->mask = set->mask;}static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask){	struct nfs_access_entry cache;	int status;	status = nfs_access_get_cached(inode, cred, &cache);	if (status == 0)		goto out;	/* Be clever: ask server to check for all possible rights */	cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ;	cache.cred = cred;	cache.jiffies = jiffies;	status = NFS_PROTO(inode)->access(inode, &cache);	if (status != 0)		return status;	nfs_access_add_cache(inode, &cache);out:	if ((cache.mask & mask) == mask)		return 0;	return -EACCES;}int nfs_permission(struct inode *inode, int mask, struct nameidata *nd){	struct rpc_cred *cred;	int mode = inode->i_mode;	int res;	if (mask == 0)		return 0;	if (mask & MAY_WRITE) {		/*		 *		 * Nobody gets write access to a read-only fs.		 *		 */		if (IS_RDONLY(inode) &&		    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))			return -EROFS;		/*		 *		 * Nobody gets write access to an immutable file.		 *		 */		if (IS_IMMUTABLE(inode))			return -EACCES;	}	/* Are we checking permissions on anything other than lookup/execute? */	if ((mask & MAY_EXEC) == 0) {		/* We only need to check permissions on file open() and access() */		if (!nd || !(nd->flags & (LOOKUP_OPEN|LOOKUP_ACCESS)))			return 0;		/* NFSv4 has atomic_open... */		if (NFS_PROTO(inode)->version > 3 && (nd->flags & LOOKUP_OPEN))			return 0;	}	lock_kernel();	if (!NFS_PROTO(inode)->access)		goto out_notsup;	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);	res = nfs_do_access(inode, cred, mask);	put_rpccred(cred);	unlock_kernel();	return res;out_notsup:	nfs_revalidate_inode(NFS_SERVER(inode), inode);	res = vfs_permission(inode, mask);	unlock_kernel();	return res;}/* * Local variables: *  version-control: t *  kept-new-versions: 5 * End: */

⌨️ 快捷键说明

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