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

📄 export.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
 */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 (IS_ERR(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 (IS_ERR(exp)) {		err = PTR_ERR(exp);		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;}static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type,				   u32 *fsidv, struct cache_req *reqp){	struct svc_export *exp;	struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);	if (IS_ERR(ek))		return ERR_PTR(PTR_ERR(ek));	exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);	cache_put(&ek->h, &svc_expkey_cache);	if (IS_ERR(exp))		return ERR_PTR(PTR_ERR(exp));	return exp;}__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp){	struct exp_flavor_info *f;	struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;	/* legacy gss-only clients are always OK: */	if (exp->ex_client == rqstp->rq_gssclient)		return 0;	/* ip-address based client; check sec= export option: */	for (f = exp->ex_flavors; f < end; f++) {		if (f->pseudoflavor == rqstp->rq_flavor)			return 0;	}	/* defaults in absence of sec= options: */	if (exp->ex_nflavors == 0) {		if (rqstp->rq_flavor == RPC_AUTH_NULL ||		    rqstp->rq_flavor == RPC_AUTH_UNIX)			return 0;	}	return nfserr_wrongsec;}/* * Uses rq_client and rq_gssclient to find an export; uses rq_client (an * auth_unix client) if it's available and has secinfo information; * otherwise, will try to use rq_gssclient. * * Called from functions that handle requests; functions that do work on * behalf of mountd are passed a single client name to use, and should * use exp_get_by_name() or exp_find(). */struct svc_export *rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt,		struct dentry *dentry){	struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);	if (rqstp->rq_client == NULL)		goto gss;	/* First try the auth_unix client: */	exp = exp_get_by_name(rqstp->rq_client, mnt, dentry,						&rqstp->rq_chandle);	if (PTR_ERR(exp) == -ENOENT)		goto gss;	if (IS_ERR(exp))		return exp;	/* If it has secinfo, assume there are no gss/... clients */	if (exp->ex_nflavors > 0)		return exp;gss:	/* Otherwise, try falling back on gss client */	if (rqstp->rq_gssclient == NULL)		return exp;	gssexp = exp_get_by_name(rqstp->rq_gssclient, mnt, dentry,						&rqstp->rq_chandle);	if (PTR_ERR(gssexp) == -ENOENT)		return exp;	if (!IS_ERR(exp))		exp_put(exp);	return gssexp;}struct svc_export *rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv){	struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);	if (rqstp->rq_client == NULL)		goto gss;	/* First try the auth_unix client: */	exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle);	if (PTR_ERR(exp) == -ENOENT)		goto gss;	if (IS_ERR(exp))		return exp;	/* If it has secinfo, assume there are no gss/... clients */	if (exp->ex_nflavors > 0)		return exp;gss:	/* Otherwise, try falling back on gss client */	if (rqstp->rq_gssclient == NULL)		return exp;	gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv,						&rqstp->rq_chandle);	if (PTR_ERR(gssexp) == -ENOENT)		return exp;	if (!IS_ERR(exp))		exp_put(exp);	return gssexp;}struct svc_export *rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt,		struct dentry *dentry){	struct svc_export *exp;	dget(dentry);	exp = rqst_exp_get_by_name(rqstp, mnt, dentry);	while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {		struct dentry *parent;		parent = dget_parent(dentry);		dput(dentry);		dentry = parent;		exp = rqst_exp_get_by_name(rqstp, mnt, dentry);	}	dput(dentry);	return exp;}/* * 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 */__be32exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp){	struct svc_export *exp;	__be32 rv;	u32 fsidv[2];	mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);	exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);	if (PTR_ERR(exp) == -ENOENT)		return nfserr_perm;	if (IS_ERR(exp))		return nfserrno(PTR_ERR(exp));	rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);	if (rv)		goto out;	rv = check_nfsd_access(exp, rqstp);out:	exp_put(exp);	return rv;}/* Iterator */static void *e_start(struct seq_file *m, loff_t *pos)	__acquires(svc_export_cache.hash_lock){	loff_t n = *pos;	unsigned hash, export;	struct cache_head *ch;		exp_readlock();	read_lock(&svc_export_cache.hash_lock);	if (!n--)		return SEQ_START_TOKEN;	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 == SEQ_START_TOKEN)		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)	__releases(svc_export_cache.hash_lock){	read_unlock(&svc_export_cache.hash_lock);	exp_readunlock();}static 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 show_expflags(struct seq_file *m, int flags, int mask){	struct flags *flg;	int state, first = 0;	for (flg = expflags; flg->flag; flg++) {		if (flg->flag & ~mask)			continue;		state = (flg->flag & flags) ? 0 : 1;		if (*flg->name[state])			seq_printf(m, "%s%s", first++?",":"", flg->name[state]);	}}static void show_secinfo_flags(struct seq_file *m, int flags){	seq_printf(m, ",");	show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);}static void show_secinfo(struct seq_file *m, struct svc_export *exp){	struct exp_flavor_info *f;	struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;	int lastflags = 0, first = 0;	if (exp->ex_nflavors == 0)		return;	for (f = exp->ex_flavors; f < end; f++) {		if (first || f->flags != lastflags) {			if (!first)				show_secinfo_flags(m, lastflags);			seq_printf(m, ",sec=%d", f->pseudoflavor);			lastflags = f->flags;		} else {			seq_printf(m, ":%d", f->pseudoflavor);		}	}	show_secinfo_flags(m, lastflags);}static void exp_flags(struct seq_file *m, int flag, int fsid,		uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc){	show_expflags(m, flag, NFSEXP_ALLFLAGS);	if (flag & NFSEXP_FSID)		seq_printf(m, ",fsid=%d", fsid);	if (anonu != (uid_t)-2 && anonu != (0x10000-2))		seq_printf(m, ",anonuid=%u", anonu);	if (anong != (gid_t)-2 && anong != (0x10000-2))		seq_printf(m, ",anongid=%u", anong);	if (fsloc && fsloc->locations_count > 0) {		char *loctype = (fsloc->migrated) ? "refer" : "replicas";		int i;		seq_printf(m, ",%s=", loctype);		seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");		seq_putc(m, '@');		seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");		for (i = 1; i < fsloc->locations_count; i++) {			seq_putc(m, ';');			seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");			seq_putc(m, '@');			seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");		}	}}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);	if (p == SEQ_START_TOKEN) {		seq_puts(m, "# Version 1.1\n");		seq_puts(m, "# Path Client(Flags) # IPs\n");		return 0;	}	cache_get(&exp->h);	if (cache_check(&svc_export_cache, &exp->h, NULL))		return 0;	cache_put(&exp->h, &svc_export_cache);	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);		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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -