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

📄 export.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
#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/seq_file.h>#include <linux/syscalls.h>#include <linux/rwsem.h>#include <linux/dcache.h>#include <linux/namei.h>#include <linux/mount.h>#include <linux/hash.h>#include <linux/module.h>#include <linux/exportfs.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>#include <linux/sunrpc/msg_prot.h>#include <linux/sunrpc/gss_api.h>#define NFSDDBG_FACILITY	NFSDDBG_EXPORTtypedef struct auth_domain	svc_client;typedef struct svc_export	svc_export;static void		exp_do_unexport(svc_export *unexp);static int		exp_verify_string(char *cp, int max);/* * We have two caches. * One maps client+vfsmnt+dentry to export options - the export map * The other maps client+filehandle-fragment to export options. - the expkey map * * The export options are actually stored in the first map, and the * second map contains a reference to the entry in the first map. */#define	EXPKEY_HASHBITS		8#define	EXPKEY_HASHMAX		(1 << EXPKEY_HASHBITS)#define	EXPKEY_HASHMASK		(EXPKEY_HASHMAX -1)static struct cache_head *expkey_table[EXPKEY_HASHMAX];static void expkey_put(struct kref *ref){	struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);	if (test_bit(CACHE_VALID, &key->h.flags) &&	    !test_bit(CACHE_NEGATIVE, &key->h.flags)) {		dput(key->ek_dentry);		mntput(key->ek_mnt);	}	auth_domain_put(key->ek_client);	kfree(key);}static void expkey_request(struct cache_detail *cd,			   struct cache_head *h,			   char **bpp, int *blen){	/* client fsidtype \xfsid */	struct svc_expkey *ek = container_of(h, struct svc_expkey, h);	char type[5];	qword_add(bpp, blen, ek->ek_client->name);	snprintf(type, 5, "%d", ek->ek_fsidtype);	qword_add(bpp, blen, type);	qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype));	(*bpp)[-1] = '\n';}static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old);static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);static struct cache_detail svc_expkey_cache;static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen){	/* client fsidtype fsid [path] */	char *buf;	int len;	struct auth_domain *dom = NULL;	int err;	int fsidtype;	char *ep;	struct svc_expkey key;	struct svc_expkey *ek;	if (mesg[mlen-1] != '\n')		return -EINVAL;	mesg[mlen-1] = 0;	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);	err = -ENOMEM;	if (!buf) goto out;	err = -EINVAL;	if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)		goto out;	err = -ENOENT;	dom = auth_domain_find(buf);	if (!dom)		goto out;	dprintk("found domain %s\n", buf);	err = -EINVAL;	if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)		goto out;	fsidtype = simple_strtoul(buf, &ep, 10);	if (*ep)		goto out;	dprintk("found fsidtype %d\n", fsidtype);	if (key_len(fsidtype)==0) /* invalid type */		goto out;	if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)		goto out;	dprintk("found fsid length %d\n", len);	if (len != key_len(fsidtype))		goto out;	/* OK, we seem to have a valid key */	key.h.flags = 0;	key.h.expiry_time = get_expiry(&mesg);	if (key.h.expiry_time == 0)		goto out;	key.ek_client = dom;		key.ek_fsidtype = fsidtype;	memcpy(key.ek_fsid, buf, len);	ek = svc_expkey_lookup(&key);	err = -ENOMEM;	if (!ek)		goto out;	/* now we want a pathname, or empty meaning NEGATIVE  */	err = -EINVAL;	if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0)		goto out;	dprintk("Path seems to be <%s>\n", buf);	err = 0;	if (len == 0) {		set_bit(CACHE_NEGATIVE, &key.h.flags);		ek = svc_expkey_update(&key, ek);		if (ek)			cache_put(&ek->h, &svc_expkey_cache);		else err = -ENOMEM;	} else {		struct nameidata nd;		err = path_lookup(buf, 0, &nd);		if (err)			goto out;		dprintk("Found the path %s\n", buf);		key.ek_mnt = nd.mnt;		key.ek_dentry = nd.dentry;				ek = svc_expkey_update(&key, ek);		if (ek)			cache_put(&ek->h, &svc_expkey_cache);		else			err = -ENOMEM;		path_release(&nd);	}	cache_flush(); out:	if (dom)		auth_domain_put(dom);	kfree(buf);	return err;}static int expkey_show(struct seq_file *m,		       struct cache_detail *cd,		       struct cache_head *h){	struct svc_expkey *ek ;	int i;	if (h ==NULL) {		seq_puts(m, "#domain fsidtype fsid [path]\n");		return 0;	}	ek = container_of(h, struct svc_expkey, h);	seq_printf(m, "%s %d 0x", ek->ek_client->name,		   ek->ek_fsidtype);	for (i=0; i < key_len(ek->ek_fsidtype)/4; i++)		seq_printf(m, "%08x", ek->ek_fsid[i]);	if (test_bit(CACHE_VALID, &h->flags) && 	    !test_bit(CACHE_NEGATIVE, &h->flags)) {		seq_printf(m, " ");		seq_path(m, ek->ek_mnt, ek->ek_dentry, "\\ \t\n");	}	seq_printf(m, "\n");	return 0;}static inline int expkey_match (struct cache_head *a, struct cache_head *b){	struct svc_expkey *orig = container_of(a, struct svc_expkey, h);	struct svc_expkey *new = container_of(b, struct svc_expkey, h);	if (orig->ek_fsidtype != new->ek_fsidtype ||	    orig->ek_client != new->ek_client ||	    memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0)		return 0;	return 1;}static inline void expkey_init(struct cache_head *cnew,				   struct cache_head *citem){	struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);	struct svc_expkey *item = container_of(citem, struct svc_expkey, h);	kref_get(&item->ek_client->ref);	new->ek_client = item->ek_client;	new->ek_fsidtype = item->ek_fsidtype;	memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));}static inline void expkey_update(struct cache_head *cnew,				   struct cache_head *citem){	struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);	struct svc_expkey *item = container_of(citem, struct svc_expkey, h);	new->ek_mnt = mntget(item->ek_mnt);	new->ek_dentry = dget(item->ek_dentry);}static struct cache_head *expkey_alloc(void){	struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);	if (i)		return &i->h;	else		return NULL;}static struct cache_detail svc_expkey_cache = {	.owner		= THIS_MODULE,	.hash_size	= EXPKEY_HASHMAX,	.hash_table	= expkey_table,	.name		= "nfsd.fh",	.cache_put	= expkey_put,	.cache_request	= expkey_request,	.cache_parse	= expkey_parse,	.cache_show	= expkey_show,	.match		= expkey_match,	.init		= expkey_init,	.update       	= expkey_update,	.alloc		= expkey_alloc,};static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *item){	struct cache_head *ch;	int hash = item->ek_fsidtype;	char * cp = (char*)item->ek_fsid;	int len = key_len(item->ek_fsidtype);	hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);	hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);	hash &= EXPKEY_HASHMASK;	ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h,				 hash);	if (ch)		return container_of(ch, struct svc_expkey, h);	else		return NULL;}static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old){	struct cache_head *ch;	int hash = new->ek_fsidtype;	char * cp = (char*)new->ek_fsid;	int len = key_len(new->ek_fsidtype);	hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);	hash ^= hash_ptr(new->ek_client, EXPKEY_HASHBITS);	hash &= EXPKEY_HASHMASK;	ch = sunrpc_cache_update(&svc_expkey_cache, &new->h,				 &old->h, hash);	if (ch)		return container_of(ch, struct svc_expkey, h);	else		return NULL;}#define	EXPORT_HASHBITS		8#define	EXPORT_HASHMAX		(1<< EXPORT_HASHBITS)#define	EXPORT_HASHMASK		(EXPORT_HASHMAX -1)static struct cache_head *export_table[EXPORT_HASHMAX];static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc){	int i;	for (i = 0; i < fsloc->locations_count; i++) {		kfree(fsloc->locations[i].path);		kfree(fsloc->locations[i].hosts);	}	kfree(fsloc->locations);}static void svc_export_put(struct kref *ref){	struct svc_export *exp = container_of(ref, struct svc_export, h.ref);	dput(exp->ex_dentry);	mntput(exp->ex_mnt);	auth_domain_put(exp->ex_client);	kfree(exp->ex_path);	nfsd4_fslocs_free(&exp->ex_fslocs);	kfree(exp);}static void svc_export_request(struct cache_detail *cd,			       struct cache_head *h,			       char **bpp, int *blen){	/*  client path */	struct svc_export *exp = container_of(h, struct svc_export, h);	char *pth;	qword_add(bpp, blen, exp->ex_client->name);	pth = d_path(exp->ex_dentry, exp->ex_mnt, *bpp, *blen);	if (IS_ERR(pth)) {		/* is this correct? */		(*bpp)[0] = '\n';		return;	}	qword_add(bpp, blen, pth);	(*bpp)[-1] = '\n';}static struct svc_export *svc_export_update(struct svc_export *new,					    struct svc_export *old);static struct svc_export *svc_export_lookup(struct svc_export *);static int check_export(struct inode *inode, int flags, unsigned char *uuid){	/* We currently export only dirs and regular files.	 * This is what umountd does.	 */	if (!S_ISDIR(inode->i_mode) &&	    !S_ISREG(inode->i_mode))		return -ENOTDIR;	/* There are two requirements on a filesystem to be exportable.	 * 1:  We must be able to identify the filesystem from a number.	 *       either a device number (so FS_REQUIRES_DEV needed)	 *       or an FSID number (so NFSEXP_FSID or ->uuid is needed).	 * 2:  We must be able to find an inode from a filehandle.	 *       This means that s_export_op must be set.	 */	if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&	    !(flags & NFSEXP_FSID) &&	    uuid == NULL) {		dprintk("exp_export: export of non-dev fs without fsid\n");		return -EINVAL;	}	if (!inode->i_sb->s_export_op ||	    !inode->i_sb->s_export_op->fh_to_dentry) {		dprintk("exp_export: export of invalid fs type.\n");		return -EINVAL;	}	return 0;}#ifdef CONFIG_NFSD_V4static intfsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){	int len;	int migrated, i, err;	/* listsize */	err = get_int(mesg, &fsloc->locations_count);	if (err)		return err;	if (fsloc->locations_count > MAX_FS_LOCATIONS)		return -EINVAL;	if (fsloc->locations_count == 0)		return 0;	fsloc->locations = kzalloc(fsloc->locations_count			* sizeof(struct nfsd4_fs_location), GFP_KERNEL);	if (!fsloc->locations)		return -ENOMEM;	for (i=0; i < fsloc->locations_count; i++) {		/* colon separated host list */		err = -EINVAL;		len = qword_get(mesg, buf, PAGE_SIZE);		if (len <= 0)			goto out_free_all;		err = -ENOMEM;		fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);		if (!fsloc->locations[i].hosts)			goto out_free_all;		err = -EINVAL;		/* slash separated path component list */		len = qword_get(mesg, buf, PAGE_SIZE);		if (len <= 0)			goto out_free_all;		err = -ENOMEM;		fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);		if (!fsloc->locations[i].path)			goto out_free_all;	}	/* migrated */	err = get_int(mesg, &migrated);	if (err)		goto out_free_all;	err = -EINVAL;	if (migrated < 0 || migrated > 1)		goto out_free_all;	fsloc->migrated = migrated;	return 0;out_free_all:	nfsd4_fslocs_free(fsloc);	return err;}static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp){	int listsize, err;	struct exp_flavor_info *f;	err = get_int(mesg, &listsize);	if (err)		return err;	if (listsize < 0 || listsize > MAX_SECINFO_LIST)		return -EINVAL;	for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {		err = get_int(mesg, &f->pseudoflavor);		if (err)			return err;		/*		 * Just a quick sanity check; we could also try to check		 * whether this pseudoflavor is supported, but at worst		 * an unsupported pseudoflavor on the export would just		 * be a pseudoflavor that won't match the flavor of any		 * authenticated request.  The administrator will		 * probably discover the problem when someone fails to		 * authenticate.		 */		if (f->pseudoflavor < 0)			return -EINVAL;		err = get_int(mesg, &f->flags);		if (err)			return err;		/* Only some flags are allowed to differ between flavors: */		if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))			return -EINVAL;	}	exp->ex_nflavors = listsize;	return 0;}#else /* CONFIG_NFSD_V4 */static inline intfsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}static inline intsecinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }#endifstatic int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen){	/* client path expiry [flags anonuid anongid fsid] */	char *buf;	int len;	int err;	struct auth_domain *dom = NULL;	struct nameidata nd;	struct svc_export exp, *expp;	int an_int;	nd.dentry = NULL;	exp.ex_path = NULL;	/* fs locations */	exp.ex_fslocs.locations = NULL;	exp.ex_fslocs.locations_count = 0;	exp.ex_fslocs.migrated = 0;	exp.ex_uuid = NULL;	/* secinfo */	exp.ex_nflavors = 0;	if (mesg[mlen-1] != '\n')		return -EINVAL;	mesg[mlen-1] = 0;	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);	err = -ENOMEM;	if (!buf) goto out;	/* client */	len = qword_get(&mesg, buf, PAGE_SIZE);	err = -EINVAL;	if (len <= 0) goto out;	err = -ENOENT;	dom = auth_domain_find(buf);	if (!dom)		goto out;	/* path */	err = -EINVAL;	if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)		goto out;	err = path_lookup(buf, 0, &nd);	if (err) goto out_no_path;	exp.h.flags = 0;	exp.ex_client = dom;	exp.ex_mnt = nd.mnt;	exp.ex_dentry = nd.dentry;	exp.ex_path = kstrdup(buf, GFP_KERNEL);	err = -ENOMEM;	if (!exp.ex_path)		goto out;	/* expiry */	err = -EINVAL;	exp.h.expiry_time = get_expiry(&mesg);	if (exp.h.expiry_time == 0)		goto out;

⌨️ 快捷键说明

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