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

📄 export.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
#define MSNFS	/* HACK HACK *//* * linux/fs/nfsd/export.c * * NFS exporting and validation. * * We maintain a list of clients, each of which has a list of * exports. To export an fs to a given client, you first have * to create the client entry with NFSCTL_ADDCLIENT, which * creates a client control block and adds it to the hash * table. Then, you call NFSCTL_EXPORT for each fs. * * * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de> */#include <linux/unistd.h>#include <linux/slab.h>#include <linux/stat.h>#include <linux/in.h>#include <linux/sunrpc/svc.h>#include <linux/nfsd/nfsd.h>#include <linux/nfsd/nfsfh.h>#include <linux/nfsd/syscall.h>#include <linux/lockd/bind.h>#define NFSDDBG_FACILITY	NFSDDBG_EXPORT#define NFSD_PARANOIA 1typedef struct svc_client	svc_client;typedef struct svc_export	svc_export;static svc_export *	exp_find(svc_client *clp, kdev_t dev);static svc_export *	exp_parent(svc_client *clp, kdev_t dev,					struct dentry *dentry);static svc_export *	exp_child(svc_client *clp, kdev_t dev,					struct dentry *dentry);static void		exp_unexport_all(svc_client *clp);static void		exp_do_unexport(svc_export *unexp);static svc_client *	exp_getclientbyname(char *name);static void		exp_freeclient(svc_client *clp);static void		exp_unhashclient(svc_client *clp);static int		exp_verify_string(char *cp, int max);#define CLIENT_HASHBITS		6#define CLIENT_HASHMAX		(1 << CLIENT_HASHBITS)#define CLIENT_HASHMASK		(CLIENT_HASHMAX - 1)#define CLIENT_HASH(a) \		((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)/* XXX: is this adequate for 32bit kdev_t ? */#define EXPORT_HASH(dev)	((dev) & (NFSCLNT_EXPMAX - 1))struct svc_clnthash {	struct svc_clnthash *	h_next;	struct in_addr		h_addr;	struct svc_client *	h_client;};static struct svc_clnthash *	clnt_hash[CLIENT_HASHMAX];static svc_client *		clients;static int			initialized;static int			hash_lock;static int			want_lock;static int			hash_count;static DECLARE_WAIT_QUEUE_HEAD(	hash_wait );/* * Find a client's export for a device. */static inline svc_export *exp_find(svc_client *clp, kdev_t dev){	svc_export *	exp;	exp = clp->cl_export[EXPORT_HASH(dev)];	while (exp && exp->ex_dev != dev)		exp = exp->ex_next;	return exp;}/* * Find the client's export entry matching xdev/xino. */svc_export *exp_get(svc_client *clp, kdev_t dev, ino_t ino){	svc_export *	exp;	if (!clp)		return NULL;	exp = clp->cl_export[EXPORT_HASH(dev)];	if (exp)		do {			if (exp->ex_ino == ino && exp->ex_dev == dev)				goto out;		} while (NULL != (exp = exp->ex_next));	exp = NULL;out:	return exp;}/* * Find the export entry for a given dentry.  <gam3@acm.org> */static svc_export *exp_parent(svc_client *clp, kdev_t dev, struct dentry *dentry){	svc_export      *exp;	if (clp == NULL)		return NULL;	for (exp = clp->cl_export[EXPORT_HASH(dev)]; exp; exp = exp->ex_next)		if (is_subdir(dentry, exp->ex_dentry))			break;	return exp;}/* * Find the child export entry for a given fs. This function is used * only by the export syscall to keep the export tree consistent. * <gam3@acm.org> */static svc_export *exp_child(svc_client *clp, kdev_t dev, struct dentry *dentry){	svc_export      *exp;	if (clp == NULL)		return NULL;	for (exp = clp->cl_export[EXPORT_HASH(dev)]; exp; exp = exp->ex_next) {		struct dentry	*ndentry = exp->ex_dentry;		if (ndentry && is_subdir(ndentry->d_parent, dentry))			break;	}	return exp;}/* * Export a file system. */intexp_export(struct nfsctl_export *nxp){	svc_client	*clp;	svc_export	*exp, *parent;	svc_export	**head;	struct nameidata nd;	struct inode	*inode = NULL;	int		i, err;	kdev_t		dev;	ino_t		ino;	/* Consistency check */	err = -EINVAL;	if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||	    !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))		goto out;	dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",			nxp->ex_client, nxp->ex_path,			nxp->ex_dev, (long) nxp->ex_ino, nxp->ex_flags);	dev = to_kdev_t(nxp->ex_dev);	ino = nxp->ex_ino;	/* Try to lock the export table for update */	if ((err = exp_writelock()) < 0)		goto out;	/* Look up client info */	err = -EINVAL;	if (!(clp = exp_getclientbyname(nxp->ex_client)))		goto out_unlock;	/*	 * If there's already an export for this file, assume this	 * is just a flag update.	 */	if ((exp = exp_get(clp, dev, ino)) != NULL) {		exp->ex_flags    = nxp->ex_flags;		exp->ex_anon_uid = nxp->ex_anon_uid;		exp->ex_anon_gid = nxp->ex_anon_gid;		err = 0;		goto out_unlock;	}	/* Look up the dentry */	err = 0;	if (path_init(nxp->ex_path, LOOKUP_POSITIVE, &nd))		err = path_walk(nxp->ex_path, &nd);	if (err)		goto out_unlock;	inode = nd.dentry->d_inode;	err = -EINVAL;	if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {		printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",			inode->i_dev, dev); 		/* I'm just being paranoid... */		goto finish;	}	/* We currently export only dirs and regular files.	 * This is what umountd does.	 */	err = -ENOTDIR;	if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode))		goto finish;	err = -EINVAL;	if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) ||	    (inode->i_sb->s_op->read_inode == NULL	     && inode->i_sb->s_op->fh_to_dentry == NULL)) {		dprintk("exp_export: export of invalid fs type.\n");		goto finish;	}	if ((parent = exp_child(clp, dev, nd.dentry)) != NULL) {		dprintk("exp_export: export not valid (Rule 3).\n");		goto finish;	}	/* Is this is a sub-export, must be a proper subset of FS */	if ((parent = exp_parent(clp, dev, nd.dentry)) != NULL) {		dprintk("exp_export: sub-export not valid (Rule 2).\n");		goto finish;	}	err = -ENOMEM;	if (!(exp = kmalloc(sizeof(*exp), GFP_USER)))		goto finish;	dprintk("nfsd: created export entry %p for client %p\n", exp, clp);	strcpy(exp->ex_path, nxp->ex_path);	exp->ex_client = clp;	exp->ex_parent = parent;	exp->ex_dentry = nd.dentry;	exp->ex_mnt = nd.mnt;	exp->ex_flags = nxp->ex_flags;	exp->ex_dev = dev;	exp->ex_ino = ino;	exp->ex_anon_uid = nxp->ex_anon_uid;	exp->ex_anon_gid = nxp->ex_anon_gid;	/* Update parent pointers of all exports */	if (parent) {		for (i = 0; i < NFSCLNT_EXPMAX; i++) {			svc_export *temp = clp->cl_export[i];			while (temp) {				if (temp->ex_parent == parent)					temp->ex_parent = exp;				temp = temp->ex_next;			}		}	}	head = clp->cl_export + EXPORT_HASH(dev);	exp->ex_next = *head;	*head = exp;	err = 0;	/* Unlock hashtable */out_unlock:	exp_unlock();out:	return err;	/* Release the dentry */finish:	path_release(&nd);	goto out_unlock;}/* * Unexport a file system. The export entry has already * been removed from the client's list of exported fs's. */static voidexp_do_unexport(svc_export *unexp){	svc_export	*exp;	svc_client	*clp;	struct dentry	*dentry;	struct vfsmount *mnt;	struct inode	*inode;	int		i;	/* Update parent pointers. */	clp = unexp->ex_client;	for (i = 0; i < NFSCLNT_EXPMAX; i++) {		for (exp = clp->cl_export[i]; exp; exp = exp->ex_next)			if (exp->ex_parent == unexp)				exp->ex_parent = unexp->ex_parent;	}	dentry = unexp->ex_dentry;	mnt = unexp->ex_mnt;	inode = dentry->d_inode;	if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino)		printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");	dput(dentry);	mntput(mnt);	kfree(unexp);}/* * Revoke all exports for a given client. * This may look very awkward, but we have to do it this way in order * to avoid race conditions (aka mind the parent pointer). */static voidexp_unexport_all(svc_client *clp){	svc_export	*exp;	int		i;	dprintk("unexporting all fs's for clnt %p\n", clp);	for (i = 0; i < NFSCLNT_EXPMAX; i++) {		exp = clp->cl_export[i];		clp->cl_export[i] = NULL;		while (exp) {			svc_export *next = exp->ex_next;			exp_do_unexport(exp);			exp = next;		}	}}/* * unexport syscall. */intexp_unexport(struct nfsctl_export *nxp){	svc_client	*clp;	svc_export	**expp, *exp = NULL;	int		err;	/* Consistency check */	if (!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))		return -EINVAL;	if ((err = exp_writelock()) < 0)		goto out;	err = -EINVAL;	clp = exp_getclientbyname(nxp->ex_client);	if (clp) {		expp = clp->cl_export + EXPORT_HASH(nxp->ex_dev);		while ((exp = *expp) != NULL) {			if (exp->ex_dev == nxp->ex_dev) {				if (exp->ex_ino == nxp->ex_ino) {					*expp = exp->ex_next;					exp_do_unexport(exp);					err = 0;					break;				}			}			expp = &(exp->ex_next);		}	}	exp_unlock();out:	return err;}/* * Obtain the root fh on behalf of a client. * This could be done in user space, but I feel that it adds some safety * since its harder to fool a kernel module than a user space program. */intexp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,	   char *path, struct knfsd_fh *f, int maxsize){	struct svc_export	*exp;	struct nameidata	nd;	struct inode		*inode;	struct svc_fh		fh;	int			err;	err = -EPERM;	if (path) {		if (path_init(path, LOOKUP_POSITIVE, &nd) &&		    path_walk(path, &nd)) {			printk("nfsd: exp_rootfh path not found %s", path);			return err;		}		dev = nd.dentry->d_inode->i_dev;		ino = nd.dentry->d_inode->i_ino;			dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n",		         path, nd.dentry, clp->cl_ident, dev, (long) ino);		exp = exp_parent(clp, dev, nd.dentry);	} else {		dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",		         clp->cl_ident, dev, (long) ino);		if ((exp = exp_get(clp, dev, ino))) {			nd.mnt = mntget(exp->ex_mnt);			nd.dentry = dget(exp->ex_dentry);		}	}	if (!exp) {		dprintk("nfsd: exp_rootfh export not found.\n");		goto out;	}	inode = nd.dentry->d_inode;	if (!inode) {		printk("exp_rootfh: Aieee, NULL d_inode\n");		goto out;	}	if (inode->i_dev != dev || inode->i_ino != ino) {		printk("exp_rootfh: Aieee, ino/dev mismatch\n");		printk("exp_rootfh: arg[dev(%x):ino(%ld)]"		       " inode[dev(%x):ino(%ld)]\n",		       dev, (long) ino, inode->i_dev, (long) inode->i_ino);	}	/*	 * fh must be initialized before calling fh_compose	 */	fh_init(&fh, maxsize);	if (fh_compose(&fh, exp, dget(nd.dentry), NULL))		err = -EINVAL;	else		err = 0;	memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));	fh_put(&fh);out:	if (path)		path_release(&nd);	return err;}/* * Hashtable locking. Write locks are placed only by user processes * wanting to modify export information. */voidexp_readlock(void){	while (hash_lock || want_lock)		sleep_on(&hash_wait);	hash_count++;}intexp_writelock(void){	/* fast track */	if (!hash_count && !hash_lock) {	lock_it:		hash_lock = 1;		return 0;	}

⌨️ 快捷键说明

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