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

📄 vfs_inode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/9p/vfs_inode.c * * This file contains vfs inode ops for the 9P2000 protocol. * *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License version 2 *  as published by the Free Software Foundation. * *  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: *  Free Software Foundation *  51 Franklin Street, Fifth Floor *  Boston, MA  02111-1301  USA * */#include <linux/module.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/pagemap.h>#include <linux/stat.h>#include <linux/string.h>#include <linux/inet.h>#include <linux/namei.h>#include <linux/idr.h>#include <linux/sched.h>#include <net/9p/9p.h>#include <net/9p/client.h>#include "v9fs.h"#include "v9fs_vfs.h"#include "fid.h"static const struct inode_operations v9fs_dir_inode_operations;static const struct inode_operations v9fs_dir_inode_operations_ext;static const struct inode_operations v9fs_file_inode_operations;static const struct inode_operations v9fs_symlink_inode_operations;/** * unixmode2p9mode - convert unix mode bits to plan 9 * @v9ses: v9fs session information * @mode: mode to convert * */static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode){	int res;	res = mode & 0777;	if (S_ISDIR(mode))		res |= P9_DMDIR;	if (v9fs_extended(v9ses)) {		if (S_ISLNK(mode))			res |= P9_DMSYMLINK;		if (v9ses->nodev == 0) {			if (S_ISSOCK(mode))				res |= P9_DMSOCKET;			if (S_ISFIFO(mode))				res |= P9_DMNAMEDPIPE;			if (S_ISBLK(mode))				res |= P9_DMDEVICE;			if (S_ISCHR(mode))				res |= P9_DMDEVICE;		}		if ((mode & S_ISUID) == S_ISUID)			res |= P9_DMSETUID;		if ((mode & S_ISGID) == S_ISGID)			res |= P9_DMSETGID;		if ((mode & P9_DMLINK))			res |= P9_DMLINK;	}	return res;}/** * p9mode2unixmode- convert plan9 mode bits to unix mode bits * @v9ses: v9fs session information * @mode: mode to convert * */static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode){	int res;	res = mode & 0777;	if ((mode & P9_DMDIR) == P9_DMDIR)		res |= S_IFDIR;	else if ((mode & P9_DMSYMLINK) && (v9fs_extended(v9ses)))		res |= S_IFLNK;	else if ((mode & P9_DMSOCKET) && (v9fs_extended(v9ses))		 && (v9ses->nodev == 0))		res |= S_IFSOCK;	else if ((mode & P9_DMNAMEDPIPE) && (v9fs_extended(v9ses))		 && (v9ses->nodev == 0))		res |= S_IFIFO;	else if ((mode & P9_DMDEVICE) && (v9fs_extended(v9ses))		 && (v9ses->nodev == 0))		res |= S_IFBLK;	else		res |= S_IFREG;	if (v9fs_extended(v9ses)) {		if ((mode & P9_DMSETUID) == P9_DMSETUID)			res |= S_ISUID;		if ((mode & P9_DMSETGID) == P9_DMSETGID)			res |= S_ISGID;	}	return res;}int v9fs_uflags2omode(int uflags){	int ret;	ret = 0;	switch (uflags&3) {	default:	case O_RDONLY:		ret = P9_OREAD;		break;	case O_WRONLY:		ret = P9_OWRITE;		break;	case O_RDWR:		ret = P9_ORDWR;		break;	}	if (uflags & O_EXCL)		ret |= P9_OEXCL;	if (uflags & O_TRUNC)		ret |= P9_OTRUNC;	if (uflags & O_APPEND)		ret |= P9_OAPPEND;	return ret;}/** * v9fs_blank_wstat - helper function to setup a 9P stat structure * @v9ses: 9P session info (for determining extended mode) * @wstat: structure to initialize * */static voidv9fs_blank_wstat(struct p9_wstat *wstat){	wstat->type = ~0;	wstat->dev = ~0;	wstat->qid.type = ~0;	wstat->qid.version = ~0;	*((long long *)&wstat->qid.path) = ~0;	wstat->mode = ~0;	wstat->atime = ~0;	wstat->mtime = ~0;	wstat->length = ~0;	wstat->name = NULL;	wstat->uid = NULL;	wstat->gid = NULL;	wstat->muid = NULL;	wstat->n_uid = ~0;	wstat->n_gid = ~0;	wstat->n_muid = ~0;	wstat->extension = NULL;}/** * v9fs_get_inode - helper function to setup an inode * @sb: superblock * @mode: mode to setup inode with * */struct inode *v9fs_get_inode(struct super_block *sb, int mode){	struct inode *inode;	struct v9fs_session_info *v9ses = sb->s_fs_info;	P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);	inode = new_inode(sb);	if (inode) {		inode->i_mode = mode;		inode->i_uid = current->fsuid;		inode->i_gid = current->fsgid;		inode->i_blocks = 0;		inode->i_rdev = 0;		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;		inode->i_mapping->a_ops = &v9fs_addr_operations;		switch (mode & S_IFMT) {		case S_IFIFO:		case S_IFBLK:		case S_IFCHR:		case S_IFSOCK:			if (!v9fs_extended(v9ses)) {				P9_DPRINTK(P9_DEBUG_ERROR,				      "special files without extended mode\n");				return ERR_PTR(-EINVAL);			}			init_special_inode(inode, inode->i_mode,					   inode->i_rdev);			break;		case S_IFREG:			inode->i_op = &v9fs_file_inode_operations;			inode->i_fop = &v9fs_file_operations;			break;		case S_IFLNK:			if (!v9fs_extended(v9ses)) {				P9_DPRINTK(P9_DEBUG_ERROR,					"extended modes used w/o 9P2000.u\n");				return ERR_PTR(-EINVAL);			}			inode->i_op = &v9fs_symlink_inode_operations;			break;		case S_IFDIR:			inc_nlink(inode);			if (v9fs_extended(v9ses))				inode->i_op = &v9fs_dir_inode_operations_ext;			else				inode->i_op = &v9fs_dir_inode_operations;			inode->i_fop = &v9fs_dir_operations;			break;		default:			P9_DPRINTK(P9_DEBUG_ERROR,				"BAD mode 0x%x S_IFMT 0x%x\n",				mode, mode & S_IFMT);			return ERR_PTR(-EINVAL);		}	} else {		P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");		return ERR_PTR(-ENOMEM);	}	return inode;}/*static struct v9fs_fid*v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry){	int err;	int nfid;	struct v9fs_fid *ret;	struct v9fs_fcall *fcall;	nfid = v9fs_get_idpool(&v9ses->fidpool);	if (nfid < 0) {		eprintk(KERN_WARNING, "no free fids available\n");		return ERR_PTR(-ENOSPC);	}	err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name,		&fcall);	if (err < 0) {		if (fcall && fcall->id == RWALK)			goto clunk_fid;		PRINT_FCALL_ERROR("walk error", fcall);		v9fs_put_idpool(nfid, &v9ses->fidpool);		goto error;	}	kfree(fcall);	fcall = NULL;	ret = v9fs_fid_create(v9ses, nfid);	if (!ret) {		err = -ENOMEM;		goto clunk_fid;	}	err = v9fs_fid_insert(ret, dentry);	if (err < 0) {		v9fs_fid_destroy(ret);		goto clunk_fid;	}	return ret;clunk_fid:	v9fs_t_clunk(v9ses, nfid);error:	kfree(fcall);	return ERR_PTR(err);}*/static struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,	struct super_block *sb){	int err, umode;	struct inode *ret;	struct p9_stat *st;	ret = NULL;	st = p9_client_stat(fid);	if (IS_ERR(st)) {		err = PTR_ERR(st);		st = NULL;		goto error;	}	umode = p9mode2unixmode(v9ses, st->mode);	ret = v9fs_get_inode(sb, umode);	if (IS_ERR(ret)) {		err = PTR_ERR(ret);		ret = NULL;		goto error;	}	v9fs_stat2inode(st, ret, sb);	ret->i_ino = v9fs_qid2ino(&st->qid);	kfree(st);	return ret;error:	kfree(st);	if (ret)		iput(ret);	return ERR_PTR(err);}/** * v9fs_remove - helper function to remove files and directories * @dir: directory inode that is being deleted * @file:  dentry that is being deleted * @rmdir: removing a directory * */static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir){	struct inode *file_inode;	struct v9fs_session_info *v9ses;	struct p9_fid *v9fid;	P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,		rmdir);	file_inode = file->d_inode;	v9ses = v9fs_inode2v9ses(file_inode);	v9fid = v9fs_fid_clone(file);	if (IS_ERR(v9fid))		return PTR_ERR(v9fid);	return p9_client_remove(v9fid);}static intv9fs_open_created(struct inode *inode, struct file *file){	return 0;}/** * v9fs_create - Create a file * @dentry:  dentry that is being created * @perm: create permissions * @mode: open mode * */static struct p9_fid *v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,		struct dentry *dentry, char *extension, u32 perm, u8 mode){	int err;	char *name;	struct p9_fid *dfid, *ofid, *fid;	struct inode *inode;	err = 0;	ofid = NULL;	fid = NULL;	name = (char *) dentry->d_name.name;	dfid = v9fs_fid_clone(dentry->d_parent);	if (IS_ERR(dfid)) {		err = PTR_ERR(dfid);		dfid = NULL;		goto error;	}	/* clone a fid to use for creation */	ofid = p9_client_walk(dfid, 0, NULL, 1);	if (IS_ERR(ofid)) {		err = PTR_ERR(ofid);		ofid = NULL;		goto error;	}	err = p9_client_fcreate(ofid, name, perm, mode, extension);	if (err < 0)		goto error;	/* now walk from the parent so we can get unopened fid */	fid = p9_client_walk(dfid, 1, &name, 0);	if (IS_ERR(fid)) {		err = PTR_ERR(fid);		fid = NULL;		goto error;	} else		dfid = NULL;	/* instantiate inode and assign the unopened fid to the dentry */	inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);	if (IS_ERR(inode)) {		err = PTR_ERR(inode);		goto error;	}	if (v9ses->cache)		dentry->d_op = &v9fs_cached_dentry_operations;	else		dentry->d_op = &v9fs_dentry_operations;	d_instantiate(dentry, inode);	v9fs_fid_add(dentry, fid);	return ofid;error:	if (dfid)		p9_client_clunk(dfid);	if (ofid)		p9_client_clunk(ofid);	if (fid)		p9_client_clunk(fid);	return ERR_PTR(err);}/** * v9fs_vfs_create - VFS hook to create files * @inode: directory inode that is being created * @dentry:  dentry that is being deleted * @mode: create permissions * @nd: path information * */static intv9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,		struct nameidata *nd){	int err;	u32 perm;	int flags;	struct v9fs_session_info *v9ses;	struct p9_fid *fid;	struct file *filp;	err = 0;	fid = NULL;	v9ses = v9fs_inode2v9ses(dir);	perm = unixmode2p9mode(v9ses, mode);	if (nd && nd->flags & LOOKUP_OPEN)		flags = nd->intent.open.flags - 1;	else		flags = O_RDWR;	fid = v9fs_create(v9ses, dir, dentry, NULL, perm,						v9fs_uflags2omode(flags));	if (IS_ERR(fid)) {		err = PTR_ERR(fid);		fid = NULL;		goto error;	}	/* if we are opening a file, assign the open fid to the file */	if (nd && nd->flags & LOOKUP_OPEN) {		filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);		if (IS_ERR(filp)) {			err = PTR_ERR(filp);			goto error;		}		filp->private_data = fid;	} else		p9_client_clunk(fid);	return 0;error:	if (fid)		p9_client_clunk(fid);	return err;}/** * v9fs_vfs_mkdir - VFS mkdir hook to create a directory * @inode:  inode that is being unlinked * @dentry: dentry that is being unlinked * @mode: mode for new directory * */static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode){	int err;	u32 perm;	struct v9fs_session_info *v9ses;	struct p9_fid *fid;	P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);	err = 0;	v9ses = v9fs_inode2v9ses(dir);	perm = unixmode2p9mode(v9ses, mode | S_IFDIR);	fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD);	if (IS_ERR(fid)) {		err = PTR_ERR(fid);		fid = NULL;	}	if (fid)		p9_client_clunk(fid);	return err;}/** * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode * @dir:  inode that is being walked from * @dentry: dentry that is being walked to? * @nameidata: path data * */static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,				      struct nameidata *nameidata){	struct super_block *sb;	struct v9fs_session_info *v9ses;	struct p9_fid *dfid, *fid;	struct inode *inode;	char *name;	int result = 0;	P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",		dir, dentry->d_name.name, dentry, nameidata);	sb = dir->i_sb;	v9ses = v9fs_inode2v9ses(dir);	dfid = v9fs_fid_lookup(dentry->d_parent);	if (IS_ERR(dfid))		return ERR_PTR(PTR_ERR(dfid));	name = (char *) dentry->d_name.name;	fid = p9_client_walk(dfid, 1, &name, 1);	if (IS_ERR(fid)) {		result = PTR_ERR(fid);		if (result == -ENOENT) {			d_add(dentry, NULL);			return NULL;		}		return ERR_PTR(result);	}	inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);	if (IS_ERR(inode)) {		result = PTR_ERR(inode);

⌨️ 快捷键说明

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