export.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,206 行 · 第 1/2 页

C
1,206
字号
	exp = exp_get_by_name(clp, mnt, dentry, reqp);	while (exp == NULL && !IS_ROOT(dentry)) {		struct dentry *parent;		parent = dget_parent(dentry);		dput(dentry);		dentry = parent;		exp = exp_get_by_name(clp, mnt, dentry, reqp);	}	dput(dentry);	return exp;}/* * Hashtable locking. Write locks are placed only by user processes * wanting to modify export information. * Write locking only done in this file.  Read locking * needed externally. */static DECLARE_RWSEM(hash_sem);voidexp_readlock(void){	down_read(&hash_sem);}static inline voidexp_writelock(void){	down_write(&hash_sem);}voidexp_readunlock(void){	up_read(&hash_sem);}static inline voidexp_writeunlock(void){	up_write(&hash_sem);}static void exp_fsid_unhash(struct svc_export *exp){	struct svc_expkey *ek;	if ((exp->ex_flags & NFSEXP_FSID) == 0)		return;	ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);	if (ek && !IS_ERR(ek)) {		ek->h.expiry_time = get_seconds()-1;		expkey_put(&ek->h, &svc_expkey_cache);	}	svc_expkey_cache.nextcheck = get_seconds();}static int exp_fsid_hash(svc_client *clp, struct svc_export *exp){	u32 fsid[2]; 	if ((exp->ex_flags & NFSEXP_FSID) == 0)		return 0;	mk_fsid_v1(fsid, exp->ex_fsid);	return exp_set_key(clp, 1, fsid, exp);}static int exp_hash(struct auth_domain *clp, struct svc_export *exp){	u32 fsid[2];	struct inode *inode = exp->ex_dentry->d_inode;	dev_t dev = inode->i_sb->s_dev;	if (old_valid_dev(dev)) {		mk_fsid_v0(fsid, dev, inode->i_ino);		return exp_set_key(clp, 0, fsid, exp);	}	mk_fsid_v3(fsid, dev, inode->i_ino);	return exp_set_key(clp, 3, fsid, exp);}static void exp_unhash(struct svc_export *exp){	struct svc_expkey *ek;	struct inode *inode = exp->ex_dentry->d_inode;	ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);	if (ek && !IS_ERR(ek)) {		ek->h.expiry_time = get_seconds()-1;		expkey_put(&ek->h, &svc_expkey_cache);	}	svc_expkey_cache.nextcheck = get_seconds();}	/* * Export a file system. */intexp_export(struct nfsctl_export *nxp){	svc_client	*clp;	struct svc_export	*exp = NULL;	struct svc_export	new;	struct svc_expkey	*fsid_key = NULL;	struct nameidata nd;	int		err;	/* 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,			(unsigned)nxp->ex_dev, (long)nxp->ex_ino,			nxp->ex_flags);	/* Try to lock the export table for update */	exp_writelock();	/* Look up client info */	if (!(clp = auth_domain_find(nxp->ex_client)))		goto out_unlock;	/* Look up the dentry */	err = path_lookup(nxp->ex_path, 0, &nd);	if (err)		goto out_unlock;	err = -EINVAL;	exp = exp_get_by_name(clp, nd.mnt, nd.dentry, NULL);	/* must make sure there won't be an ex_fsid clash */	if ((nxp->ex_flags & NFSEXP_FSID) &&	    (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) &&	    !IS_ERR(fsid_key) &&	    fsid_key->ek_export &&	    fsid_key->ek_export != exp)		goto finish;	if (exp) {		/* just a flags/id/fsid update */		exp_fsid_unhash(exp);		exp->ex_flags    = nxp->ex_flags;		exp->ex_anon_uid = nxp->ex_anon_uid;		exp->ex_anon_gid = nxp->ex_anon_gid;		exp->ex_fsid     = nxp->ex_dev;		err = exp_fsid_hash(clp, exp);		goto finish;	}	err = check_export(nd.dentry->d_inode, nxp->ex_flags);	if (err) goto finish;	err = -ENOMEM;	dprintk("nfsd: creating export entry %p for client %p\n", exp, clp);	new.h.expiry_time = NEVER;	new.h.flags = 0;	new.ex_client = clp;	new.ex_mnt = nd.mnt;	new.ex_dentry = nd.dentry;	new.ex_flags = nxp->ex_flags;	new.ex_anon_uid = nxp->ex_anon_uid;	new.ex_anon_gid = nxp->ex_anon_gid;	new.ex_fsid = nxp->ex_dev;	exp = svc_export_lookup(&new, 1);	if (exp == NULL)		goto finish;	err = 0;	if (exp_hash(clp, exp) ||	    exp_fsid_hash(clp, exp)) {		/* failed to create at least one index */		exp_do_unexport(exp);		cache_flush();		err = -ENOMEM;	}finish:	if (exp)		exp_put(exp);	if (fsid_key && !IS_ERR(fsid_key))		expkey_put(&fsid_key->h, &svc_expkey_cache);	if (clp)		auth_domain_put(clp);	path_release(&nd);out_unlock:	exp_writeunlock();out:	return err;}/* * 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){	unexp->h.expiry_time = get_seconds()-1;	svc_export_cache.nextcheck = get_seconds();	exp_unhash(unexp);	exp_fsid_unhash(unexp);}/* * unexport syscall. */intexp_unexport(struct nfsctl_export *nxp){	struct auth_domain *dom;	svc_export *exp;	struct nameidata nd;	int		err;	/* Consistency check */	if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||	    !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))		return -EINVAL;	exp_writelock();	err = -EINVAL;	dom = auth_domain_find(nxp->ex_client);	if (!dom) {		dprintk("nfsd: unexport couldn't find %s\n", nxp->ex_client);		goto out_unlock;	}	err = path_lookup(nxp->ex_path, 0, &nd);	if (err)		goto out_domain;	err = -EINVAL;	exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);	path_release(&nd);	if (!exp)		goto out_domain;	exp_do_unexport(exp);	exp_put(exp);	err = 0;out_domain:	auth_domain_put(dom);	cache_flush();out_unlock:	exp_writeunlock();	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(svc_client *clp, 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;	/* NB: we probably ought to check that it's NUL-terminated */	if (path_lookup(path, 0, &nd)) {		printk("nfsd: exp_rootfh path not found %s", path);		return err;	}	inode = nd.dentry->d_inode;	dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",		 path, nd.dentry, clp->name,		 inode->i_sb->s_id, inode->i_ino);	exp = exp_parent(clp, nd.mnt, nd.dentry, NULL);	if (!exp) {		dprintk("nfsd: exp_rootfh export not found.\n");		goto out;	}	/*	 * fh must be initialized before calling fh_compose	 */	fh_init(&fh, maxsize);	if (fh_compose(&fh, exp, nd.dentry, NULL))		err = -EINVAL;	else		err = 0;	memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));	fh_put(&fh);	exp_put(exp);out:	path_release(&nd);	return err;}/* * Called when we need the filehandle for the root of the pseudofs, * for a given NFSv4 client.   The root is defined to be the * export point with fsid==0 */intexp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,	       struct cache_req *creq){	struct svc_expkey *fsid_key;	int rv;	u32 fsidv[2];	mk_fsid_v1(fsidv, 0);	fsid_key = exp_find_key(clp, 1, fsidv, creq);	if (IS_ERR(fsid_key) && PTR_ERR(fsid_key) == -EAGAIN)		return nfserr_dropit;	if (!fsid_key || IS_ERR(fsid_key))		return nfserr_perm;	rv = fh_compose(fhp, fsid_key->ek_export, 			  fsid_key->ek_export->ex_dentry, NULL);	expkey_put(&fsid_key->h, &svc_expkey_cache);	return rv;}/* Iterator */static void *e_start(struct seq_file *m, loff_t *pos){	loff_t n = *pos;	unsigned hash, export;	struct cache_head *ch;		exp_readlock();	read_lock(&svc_export_cache.hash_lock);	if (!n--)		return (void *)1;	hash = n >> 32;	export = n & ((1LL<<32) - 1);		for (ch=export_table[hash]; ch; ch=ch->next)		if (!export--)			return ch;	n &= ~((1LL<<32) - 1);	do {		hash++;		n += 1LL<<32;	} while(hash < EXPORT_HASHMAX && export_table[hash]==NULL);	if (hash >= EXPORT_HASHMAX)		return NULL;	*pos = n+1;	return export_table[hash];}static void *e_next(struct seq_file *m, void *p, loff_t *pos){	struct cache_head *ch = p;	int hash = (*pos >> 32);	if (p == (void *)1)		hash = 0;	else if (ch->next == NULL) {		hash++;		*pos += 1LL<<32;	} else {		++*pos;		return ch->next;	}	*pos &= ~((1LL<<32) - 1);	while (hash < EXPORT_HASHMAX && export_table[hash] == NULL) {		hash++;		*pos += 1LL<<32;	}	if (hash >= EXPORT_HASHMAX)		return NULL;	++*pos;	return export_table[hash];}static void e_stop(struct seq_file *m, void *p){	read_unlock(&svc_export_cache.hash_lock);	exp_readunlock();}struct flags {	int flag;	char *name[2];} expflags[] = {	{ NFSEXP_READONLY, {"ro", "rw"}},	{ NFSEXP_INSECURE_PORT, {"insecure", ""}},	{ NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},	{ NFSEXP_ALLSQUASH, {"all_squash", ""}},	{ NFSEXP_ASYNC, {"async", "sync"}},	{ NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},	{ NFSEXP_NOHIDE, {"nohide", ""}},	{ NFSEXP_CROSSMOUNT, {"crossmnt", ""}},	{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},	{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},#ifdef MSNFS	{ NFSEXP_MSNFS, {"msnfs", ""}},#endif	{ 0, {"", ""}}};static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong){	int first = 0;	struct flags *flg;	for (flg = expflags; flg->flag; flg++) {		int state = (flg->flag & flag)?0:1;		if (*flg->name[state])			seq_printf(m, "%s%s", first++?",":"", flg->name[state]);	}	if (flag & NFSEXP_FSID)		seq_printf(m, "%sfsid=%d", first++?",":"", fsid);	if (anonu != (uid_t)-2 && anonu != (0x10000-2))		seq_printf(m, "%sanonuid=%d", first++?",":"", anonu);	if (anong != (gid_t)-2 && anong != (0x10000-2))		seq_printf(m, "%sanongid=%d", first++?",":"", anong);}static int e_show(struct seq_file *m, void *p){	struct cache_head *cp = p;	struct svc_export *exp = container_of(cp, struct svc_export, h);	svc_client *clp;	if (p == (void *)1) {		seq_puts(m, "# Version 1.1\n");		seq_puts(m, "# Path Client(Flags) # IPs\n");		return 0;	}	clp = exp->ex_client;	cache_get(&exp->h);	if (cache_check(&svc_export_cache, &exp->h, NULL))		return 0;	if (cache_put(&exp->h, &svc_export_cache)) BUG();	return svc_export_show(m, &svc_export_cache, cp);}struct seq_operations nfs_exports_op = {	.start	= e_start,	.next	= e_next,	.stop	= e_stop,	.show	= e_show,};/* * Add or modify a client. * Change requests may involve the list of host addresses. The list of * exports and possibly existing uid maps are left untouched. */intexp_addclient(struct nfsctl_client *ncp){	struct auth_domain	*dom;	int			i, err;	/* First, consistency check. */	err = -EINVAL;	if (! exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))		goto out;	if (ncp->cl_naddr > NFSCLNT_ADDRMAX)		goto out;	/* Lock the hashtable */	exp_writelock();	dom = unix_domain_find(ncp->cl_ident);	err = -ENOMEM;	if (!dom)		goto out_unlock;	/* Insert client into hashtable. */	for (i = 0; i < ncp->cl_naddr; i++)		auth_unix_add_addr(ncp->cl_addrlist[i], dom);	auth_unix_forget_old(dom);	auth_domain_put(dom);	err = 0;out_unlock:	exp_writeunlock();out:	return err;}/* * Delete a client given an identifier. */intexp_delclient(struct nfsctl_client *ncp){	int		err;	struct auth_domain *dom;	err = -EINVAL;	if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))		goto out;	/* Lock the hashtable */	exp_writelock();	dom = auth_domain_find(ncp->cl_ident);	/* just make sure that no addresses work 	 * and that it will expire soon 	 */	if (dom) {		err = auth_unix_forget_old(dom);		dom->h.expiry_time = get_seconds();		auth_domain_put(dom);	}	exp_writeunlock();out:	return err;}/* * Verify that string is non-empty and does not exceed max length. */static intexp_verify_string(char *cp, int max){	int	i;	for (i = 0; i < max; i++)		if (!cp[i])			return i;	cp[i] = 0;	printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp);	return 0;}/* * Initialize the exports module. */voidnfsd_export_init(void){	dprintk("nfsd: initializing export module.\n");	cache_register(&svc_export_cache);	cache_register(&svc_expkey_cache);}/* * Flush exports table - called when last nfsd thread is killed */voidnfsd_export_flush(void){	exp_writelock();	cache_purge(&svc_expkey_cache);	cache_purge(&svc_export_cache);	exp_writeunlock();}/* * Shutdown the exports module. */voidnfsd_export_shutdown(void){	dprintk("nfsd: shutting down export module.\n");	exp_writelock();	if (cache_unregister(&svc_expkey_cache))		printk(KERN_ERR "nfsd: failed to unregister expkey cache\n");	if (cache_unregister(&svc_export_cache))		printk(KERN_ERR "nfsd: failed to unregister export cache\n");	svcauth_unix_purge();	exp_writeunlock();	dprintk("nfsd: export shutdown complete.\n");}

⌨️ 快捷键说明

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