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

📄 dir.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	}	/* Open the file on the server */	lock_kernel();	res = nfs4_atomic_open(dir, dentry, nd);	unlock_kernel();	if (IS_ERR(res)) {		error = PTR_ERR(res);		switch (error) {			/* Make a negative dentry */			case -ENOENT:				res = NULL;				goto out;			/* This turned out not to be a regular file */			case -EISDIR:			case -ENOTDIR:				goto no_open;			case -ELOOP:				if (!(nd->intent.open.flags & O_NOFOLLOW))					goto no_open;			/* case -EINVAL: */			default:				goto out;		}	} else if (res != NULL)		dentry = res;out:	return res;no_open:	return nfs_lookup(dir, dentry, nd);}static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd){	struct dentry *parent = NULL;	struct inode *inode = dentry->d_inode;	struct inode *dir;	int openflags, ret = 0;	parent = dget_parent(dentry);	dir = parent->d_inode;	if (!is_atomic_open(dir, nd))		goto no_open;	/* We can't create new files in nfs_open_revalidate(), so we	 * optimize away revalidation of negative dentries.	 */	if (inode == NULL) {		if (!nfs_neg_need_reval(dir, dentry, nd))			ret = 1;		goto out;	}	/* NFS only supports OPEN on regular files */	if (!S_ISREG(inode->i_mode))		goto no_open;	openflags = nd->intent.open.flags;	/* We cannot do exclusive creation on a positive dentry */	if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))		goto no_open;	/* We can't create new files, or truncate existing ones here */	openflags &= ~(O_CREAT|O_TRUNC);	/*	 * Note: we're not holding inode->i_mutex and so may be racing with	 * operations that change the directory. We therefore save the	 * change attribute *before* we do the RPC call.	 */	lock_kernel();	ret = nfs4_open_revalidate(dir, dentry, openflags, nd);	unlock_kernel();out:	dput(parent);	if (!ret)		d_drop(dentry);	return ret;no_open:	dput(parent);	if (inode != NULL && nfs_have_delegation(inode, FMODE_READ))		return 1;	return nfs_lookup_revalidate(dentry, nd);}#endif /* CONFIG_NFSV4 */static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc){	struct dentry *parent = desc->file->f_path.dentry;	struct inode *dir = parent->d_inode;	struct nfs_entry *entry = desc->entry;	struct dentry *dentry, *alias;	struct qstr name = {		.name = entry->name,		.len = entry->len,	};	struct inode *inode;	unsigned long verf = nfs_save_change_attribute(dir);	switch (name.len) {		case 2:			if (name.name[0] == '.' && name.name[1] == '.')				return dget_parent(parent);			break;		case 1:			if (name.name[0] == '.')				return dget(parent);	}	spin_lock(&dir->i_lock);	if (NFS_I(dir)->cache_validity & NFS_INO_INVALID_DATA) {		spin_unlock(&dir->i_lock);		return NULL;	}	spin_unlock(&dir->i_lock);	name.hash = full_name_hash(name.name, name.len);	dentry = d_lookup(parent, &name);	if (dentry != NULL) {		/* Is this a positive dentry that matches the readdir info? */		if (dentry->d_inode != NULL &&				(NFS_FILEID(dentry->d_inode) == entry->ino ||				d_mountpoint(dentry))) {			if (!desc->plus || entry->fh->size == 0)				return dentry;			if (nfs_compare_fh(NFS_FH(dentry->d_inode),						entry->fh) == 0)				goto out_renew;		}		/* No, so d_drop to allow one to be created */		d_drop(dentry);		dput(dentry);	}	if (!desc->plus || !(entry->fattr->valid & NFS_ATTR_FATTR))		return NULL;	if (name.len > NFS_SERVER(dir)->namelen)		return NULL;	/* Note: caller is already holding the dir->i_mutex! */	dentry = d_alloc(parent, &name);	if (dentry == NULL)		return NULL;	dentry->d_op = NFS_PROTO(dir)->dentry_ops;	inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr);	if (IS_ERR(inode)) {		dput(dentry);		return NULL;	}	alias = d_materialise_unique(dentry, inode);	if (alias != NULL) {		dput(dentry);		if (IS_ERR(alias))			return NULL;		dentry = alias;	}out_renew:	nfs_set_verifier(dentry, verf);	return dentry;}/* * Code common to create, mkdir, and mknod. */int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,				struct nfs_fattr *fattr){	struct dentry *parent = dget_parent(dentry);	struct inode *dir = parent->d_inode;	struct inode *inode;	int error = -EACCES;	d_drop(dentry);	/* We may have been initialized further down */	if (dentry->d_inode)		goto out;	if (fhandle->size == 0) {		error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);		if (error)			goto out_error;	}	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));	if (!(fattr->valid & NFS_ATTR_FATTR)) {		struct nfs_server *server = NFS_SB(dentry->d_sb);		error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr);		if (error < 0)			goto out_error;	}	inode = nfs_fhget(dentry->d_sb, fhandle, fattr);	error = PTR_ERR(inode);	if (IS_ERR(inode))		goto out_error;	d_add(dentry, inode);out:	dput(parent);	return 0;out_error:	nfs_mark_for_revalidate(dir);	dput(parent);	return error;}/* * Following a failed create operation, we drop the dentry rather * than retain a negative dentry. This avoids a problem in the event * that the operation succeeded on the server, but an error in the * reply path made it appear to have failed. */static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,		struct nameidata *nd){	struct iattr attr;	int error;	int open_flags = 0;	dfprintk(VFS, "NFS: create(%s/%ld), %s\n",			dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);	attr.ia_mode = mode;	attr.ia_valid = ATTR_MODE;	if ((nd->flags & LOOKUP_CREATE) != 0)		open_flags = nd->intent.open.flags;	lock_kernel();	error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd);	if (error != 0)		goto out_err;	unlock_kernel();	return 0;out_err:	unlock_kernel();	d_drop(dentry);	return error;}/* * See comments for nfs_proc_create regarding failed operations. */static intnfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev){	struct iattr attr;	int status;	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();	status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);	if (status != 0)		goto out_err;	unlock_kernel();	return 0;out_err:	unlock_kernel();	d_drop(dentry);	return status;}/* * See comments for nfs_proc_create regarding failed operations. */static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode){	struct iattr attr;	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();	error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);	if (error != 0)		goto out_err;	unlock_kernel();	return 0;out_err:	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();	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);	/* Ensure the VFS deletes this inode */	if (error == 0 && dentry->d_inode != NULL)		clear_nlink(dentry->d_inode);	unlock_kernel();	return error;}static int nfs_sillyrename(struct inode *dir, struct dentry *dentry){	static unsigned int sillycounter;	const int      fileidsize  = sizeof(NFS_FILEID(dentry->d_inode))*2;	const int      countersize = sizeof(sillycounter)*2;	const int      slen        = sizeof(".nfs")+fileidsize+countersize-1;	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));	nfs_inc_stats(dir, NFSIOS_SILLYRENAME);	/*	 * 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",		fileidsize, fileidsize,		(unsigned long long)NFS_FILEID(dentry->d_inode));	/* Return delegation in anticipation of the rename */	nfs_inode_return_delegation(dentry->d_inode);	sdentry = NULL;	do {		char *suffix = silly + slen - countersize;		dput(sdentry);		sillycounter++;		sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);		dfprintk(VFS, "NFS: 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);	if (dentry->d_inode) {		error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,				dir, &qsilly);		nfs_mark_for_revalidate(dentry->d_inode);	} else		error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,				dir, &qsilly);	if (!error) {		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));		d_move(dentry, sdentry);		error = nfs_async_unlink(dir, 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;	}	if (inode != NULL) {		nfs_inode_return_delegation(inode);		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);		/* The VFS may want to delete this inode */		if (error == 0)			drop_nlink(inode);		nfs_mark_for_revalidate(inode);	} else		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);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);		/* Start asynchronous writeout of the inode */		write_inode_now(dentry->d_inode, 0);		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_set_verifier(dentry, nfs_save_change_attribute(dir));	} else if (need_rehash)		d_rehash(dentry);	unlock_kernel();	return error;}/* * To create a symbolic link, most file systems instantiate a new inode, * add a page to it containing the path, then write it out to the disk * using prepare_write/commit_write. * * Unfortunately the NFS client can't create the in-core inode first * because it needs a file handle to create an in-core inode (see * fs/nfs/inode.c:nfs_fhget).  We only have a file handle *after* the * symlink request has completed on the server. * * So instead we allocate a raw page, copy the symname into it, then do * the SYMLINK request with the page as the buffer.  If it succeeds, we * now have a new file handle and can instantiate an in-core NFS inode * and move the raw page into its mapping. */static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname){	struct pagevec lru_pvec;	struct page *page;	char *kaddr;	struct iattr attr;	unsigned int pathlen = strlen(symname);	int error;	dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id,		dir->i_ino, dentry->d_name.name, symname);	if (pathlen > PAGE_SIZE)		return -ENAMETOOLONG;	attr.ia_mode = S_IFLNK | S_IRWXUGO;	attr.ia_valid = ATTR_MODE;	lock_kernel();	page = alloc_page(GFP_HIGHUSER);	if (!page) {		unlock_kernel();

⌨️ 快捷键说明

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