Blame view

fs/nfsd/export.c 31.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
   * 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>
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
13
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/namei.h>
f35279d3f   Bruce Allan   [PATCH] sunrpc: c...
15
  #include <linux/module.h>
a56942551   Christoph Hellwig   knfsd: exportfs: ...
16
  #include <linux/exportfs.h>
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
17
  #include <linux/sunrpc/svc_xprt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18

9a74af213   Boaz Harrosh   nfsd: Move privat...
19
  #include "nfsd.h"
1557aca79   J. Bruce Fields   nfsd: move most o...
20
  #include "nfsfh.h"
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
21
  #include "netns.h"
9cf514ccf   Christoph Hellwig   nfsd: implement p...
22
  #include "pnfs.h"
9a74af213   Boaz Harrosh   nfsd: Move privat...
23

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #define NFSDDBG_FACILITY	NFSDDBG_EXPORT
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
30
31
32
33
34
35
36
37
  /*
   * 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)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38

74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
39
  static void expkey_put(struct kref *ref)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  {
baab935ff   NeilBrown   [PATCH] knfsd: Co...
41
42
43
  	struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
  
  	if (test_bit(CACHE_VALID, &key->h.flags) &&
e83aece3a   Jan Blunck   Use struct path i...
44
45
  	    !test_bit(CACHE_NEGATIVE, &key->h.flags))
  		path_put(&key->ek_path);
baab935ff   NeilBrown   [PATCH] knfsd: Co...
46
47
  	auth_domain_put(key->ek_client);
  	kfree(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  }
  
  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] = '
  ';
  }
c89172e36   Stanislav Kinsbursky   nfsd: pass pointe...
65
66
67
  static struct svc_expkey *svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
  					    struct svc_expkey *old);
  static struct svc_expkey *svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *);
74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
68

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
  static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
  {
f0db79d54   Kinglong Mee   NFSD: Add missing...
71
  	/* client fsidtype fsid expiry [path] */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
77
78
  	char *buf;
  	int len;
  	struct auth_domain *dom = NULL;
  	int err;
  	int fsidtype;
  	char *ep;
  	struct svc_expkey key;
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
79
  	struct svc_expkey *ek = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80

3476964db   Dan Carpenter   nfsd: remove some...
81
82
  	if (mesg[mlen - 1] != '
  ')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
  		return -EINVAL;
  	mesg[mlen-1] = 0;
  
  	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  	err = -ENOMEM;
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
88
89
  	if (!buf)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  
  	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
  ", 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
  ", fsidtype);
4bdff8c09   Frank Filz   [PATCH] knfsd: fi...
110
  	if (key_len(fsidtype)==0) /* invalid type */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  		goto out;
  	if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
  		goto out;
  	dprintk("found fsid length %d
  ", 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);
c89172e36   Stanislav Kinsbursky   nfsd: pass pointe...
128
  	ek = svc_expkey_lookup(cd, &key);
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
129
130
131
  	err = -ENOMEM;
  	if (!ek)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  	/* now we want a pathname, or empty meaning NEGATIVE  */
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
133
  	err = -EINVAL;
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
134
135
  	len = qword_get(&mesg, buf, PAGE_SIZE);
  	if (len < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
140
  		goto out;
  	dprintk("Path seems to be <%s>
  ", buf);
  	err = 0;
  	if (len == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  		set_bit(CACHE_NEGATIVE, &key.h.flags);
c89172e36   Stanislav Kinsbursky   nfsd: pass pointe...
142
  		ek = svc_expkey_update(cd, &key, ek);
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
143
144
  		if (!ek)
  			err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  	} else {
a63bb9966   Al Viro   [PATCH] switch nf...
146
  		err = kern_path(buf, 0, &key.ek_path);
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
147
  		if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
  			goto out;
  
  		dprintk("Found the path %s
  ", buf);
e83aece3a   Jan Blunck   Use struct path i...
152

c89172e36   Stanislav Kinsbursky   nfsd: pass pointe...
153
  		ek = svc_expkey_update(cd, &key, ek);
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
154
  		if (!ek)
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
155
  			err = -ENOMEM;
a63bb9966   Al Viro   [PATCH] switch nf...
156
  		path_put(&key.ek_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
  	}
  	cache_flush();
   out:
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
160
  	if (ek)
d4bb527e9   Stanislav Kinsbursky   nfsd: use passed ...
161
  		cache_put(&ek->h, cd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
  	if (dom)
  		auth_domain_put(dom);
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
164
  	kfree(buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
168
169
170
171
172
  	return err;
  }
  
  static int expkey_show(struct seq_file *m,
  		       struct cache_detail *cd,
  		       struct cache_head *h)
  {
  	struct svc_expkey *ek ;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
173
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
179
180
  
  	if (h ==NULL) {
  		seq_puts(m, "#domain fsidtype fsid [path]
  ");
  		return 0;
  	}
  	ek = container_of(h, struct svc_expkey, h);
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
181
182
183
184
  	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]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
  	if (test_bit(CACHE_VALID, &h->flags) && 
  	    !test_bit(CACHE_NEGATIVE, &h->flags)) {
  		seq_printf(m, " ");
c32c2f63a   Jan Blunck   d_path: Make seq_...
188
189
  		seq_path(m, &ek->ek_path, "\\ \t
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
194
  	}
  	seq_printf(m, "
  ");
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195

8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
196
  static inline int expkey_match (struct cache_head *a, struct cache_head *b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
  {
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
198
199
200
201
202
203
  	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)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
  		return 0;
  	return 1;
  }
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
207
208
  static inline void expkey_init(struct cache_head *cnew,
  				   struct cache_head *citem)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
  {
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
210
211
  	struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
  	struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
efc36aa56   NeilBrown   [PATCH] knfsd: Ch...
212
  	kref_get(&item->ek_client->ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
  	new->ek_client = item->ek_client;
  	new->ek_fsidtype = item->ek_fsidtype;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
215
216
  
  	memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  }
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
218
219
  static inline void expkey_update(struct cache_head *cnew,
  				   struct cache_head *citem)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
  {
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
221
222
  	struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
  	struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
e83aece3a   Jan Blunck   Use struct path i...
223
224
  	new->ek_path = item->ek_path;
  	path_get(&item->ek_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  }
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
226
227
228
229
230
231
232
233
  static struct cache_head *expkey_alloc(void)
  {
  	struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
  	if (i)
  		return &i->h;
  	else
  		return NULL;
  }
e5f06f720   Stanislav Kinsbursky   nfsd: make expkey...
234
  static struct cache_detail svc_expkey_cache_template = {
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
235
236
  	.owner		= THIS_MODULE,
  	.hash_size	= EXPKEY_HASHMAX,
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
237
238
  	.name		= "nfsd.fh",
  	.cache_put	= expkey_put,
73fb847a4   Stanislav Kinsbursky   SUNRPC: introduce...
239
  	.cache_request	= expkey_request,
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
240
241
242
243
244
245
246
  	.cache_parse	= expkey_parse,
  	.cache_show	= expkey_show,
  	.match		= expkey_match,
  	.init		= expkey_init,
  	.update       	= expkey_update,
  	.alloc		= expkey_alloc,
  };
61f8603d9   NeilBrown   nfsd: factor out ...
247
248
  static int
  svc_expkey_hash(struct svc_expkey *item)
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
249
  {
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
250
251
252
253
254
255
256
  	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;
61f8603d9   NeilBrown   nfsd: factor out ...
257
258
259
260
  	return hash;
  }
  
  static struct svc_expkey *
c89172e36   Stanislav Kinsbursky   nfsd: pass pointe...
261
  svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *item)
61f8603d9   NeilBrown   nfsd: factor out ...
262
263
264
  {
  	struct cache_head *ch;
  	int hash = svc_expkey_hash(item);
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
265

c89172e36   Stanislav Kinsbursky   nfsd: pass pointe...
266
  	ch = sunrpc_cache_lookup(cd, &item->h, hash);
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
267
268
269
270
271
272
273
  	if (ch)
  		return container_of(ch, struct svc_expkey, h);
  	else
  		return NULL;
  }
  
  static struct svc_expkey *
c89172e36   Stanislav Kinsbursky   nfsd: pass pointe...
274
275
  svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
  		  struct svc_expkey *old)
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
276
277
  {
  	struct cache_head *ch;
61f8603d9   NeilBrown   nfsd: factor out ...
278
  	int hash = svc_expkey_hash(new);
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
279

c89172e36   Stanislav Kinsbursky   nfsd: pass pointe...
280
  	ch = sunrpc_cache_update(cd, &new->h, &old->h, hash);
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
281
282
283
284
285
  	if (ch)
  		return container_of(ch, struct svc_expkey, h);
  	else
  		return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
  
  #define	EXPORT_HASHBITS		8
  #define	EXPORT_HASHMAX		(1<< EXPORT_HASHBITS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289

933469190   Manoj Naik   [PATCH] knfsd: nf...
290
291
  static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
  {
a1f05514b   Kinglong Mee   NFS4: Avoid NULL ...
292
  	struct nfsd4_fs_location *locations = fsloc->locations;
933469190   Manoj Naik   [PATCH] knfsd: nf...
293
  	int i;
a1f05514b   Kinglong Mee   NFS4: Avoid NULL ...
294
295
  	if (!locations)
  		return;
933469190   Manoj Naik   [PATCH] knfsd: nf...
296
  	for (i = 0; i < fsloc->locations_count; i++) {
a1f05514b   Kinglong Mee   NFS4: Avoid NULL ...
297
298
  		kfree(locations[i].path);
  		kfree(locations[i].hosts);
933469190   Manoj Naik   [PATCH] knfsd: nf...
299
  	}
a1f05514b   Kinglong Mee   NFS4: Avoid NULL ...
300
301
302
  
  	kfree(locations);
  	fsloc->locations = NULL;
933469190   Manoj Naik   [PATCH] knfsd: nf...
303
  }
baab935ff   NeilBrown   [PATCH] knfsd: Co...
304
  static void svc_export_put(struct kref *ref)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
  {
baab935ff   NeilBrown   [PATCH] knfsd: Co...
306
  	struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
547754916   Jan Blunck   Use struct path i...
307
  	path_put(&exp->ex_path);
baab935ff   NeilBrown   [PATCH] knfsd: Co...
308
  	auth_domain_put(exp->ex_client);
933469190   Manoj Naik   [PATCH] knfsd: nf...
309
  	nfsd4_fslocs_free(&exp->ex_fslocs);
885c91f74   majianpeng   nfsd: Fix memleak...
310
  	kfree(exp->ex_uuid);
baab935ff   NeilBrown   [PATCH] knfsd: Co...
311
  	kfree(exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
315
316
317
318
319
320
321
322
  }
  
  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);
cf28b4863   Jan Blunck   d_path: Make d_pa...
323
  	pth = d_path(&exp->ex_path, *bpp, *blen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
327
328
329
330
331
332
333
  	if (IS_ERR(pth)) {
  		/* is this correct? */
  		(*bpp)[0] = '
  ';
  		return;
  	}
  	qword_add(bpp, blen, pth);
  	(*bpp)[-1] = '
  ';
  }
74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
334
335
  static struct svc_export *svc_export_update(struct svc_export *new,
  					    struct svc_export *old);
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
336
  static struct svc_export *svc_export_lookup(struct svc_export *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337

774b14782   J. Bruce Fields   nfsd: make V4ROOT...
338
  static int check_export(struct inode *inode, int *flags, unsigned char *uuid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  {
f2ca7153c   J. Bruce Fields   nfsd: allow expor...
340
341
342
  	/*
  	 * We currently export only dirs, regular files, and (for v4
  	 * pseudoroot) symlinks.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
  	 */
  	if (!S_ISDIR(inode->i_mode) &&
f2ca7153c   J. Bruce Fields   nfsd: allow expor...
345
  	    !S_ISLNK(inode->i_mode) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
  	    !S_ISREG(inode->i_mode))
  		return -ENOTDIR;
774b14782   J. Bruce Fields   nfsd: make V4ROOT...
348
349
350
351
352
353
  	/*
  	 * Mountd should never pass down a writeable V4ROOT export, but,
  	 * just to make sure:
  	 */
  	if (*flags & NFSEXP_V4ROOT)
  		*flags |= NFSEXP_READONLY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
356
  	/* 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)
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
357
  	 *       or an FSID number (so NFSEXP_FSID or ->uuid is needed).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
361
  	 * 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) &&
774b14782   J. Bruce Fields   nfsd: make V4ROOT...
362
  	    !(*flags & NFSEXP_FSID) &&
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
363
  	    uuid == NULL) {
3e3b48009   Greg Banks   [PATCH] knfsd: ad...
364
365
  		dprintk("exp_export: export of non-dev fs without fsid
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
  		return -EINVAL;
  	}
cfaea787c   Christoph Hellwig   exportfs: remove ...
368
369
370
  
  	if (!inode->i_sb->s_export_op ||
  	    !inode->i_sb->s_export_op->fh_to_dentry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
  		dprintk("exp_export: export of invalid fs type.
  ");
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
  	return 0;
  
  }
933469190   Manoj Naik   [PATCH] knfsd: nf...
378
379
380
381
382
383
384
  #ifdef CONFIG_NFSD_V4
  
  static int
  fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
  {
  	int len;
  	int migrated, i, err;
be69da805   Kinglong Mee   NFSD: Error out w...
385
386
387
  	/* more than one fsloc */
  	if (fsloc->locations)
  		return -EINVAL;
933469190   Manoj Naik   [PATCH] knfsd: nf...
388
  	/* listsize */
a007c4c3e   J. Bruce Fields   nfsd: add get_uin...
389
  	err = get_uint(mesg, &fsloc->locations_count);
933469190   Manoj Naik   [PATCH] knfsd: nf...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  	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;
  }
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
434
435
  static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
  {
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
436
  	struct exp_flavor_info *f;
1f53146da   Kinglong Mee   NFSD: Using type ...
437
438
  	u32 listsize;
  	int err;
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
439

be69da805   Kinglong Mee   NFSD: Error out w...
440
441
442
  	/* more than one secinfo */
  	if (exp->ex_nflavors)
  		return -EINVAL;
1f53146da   Kinglong Mee   NFSD: Using type ...
443
  	err = get_uint(mesg, &listsize);
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
444
445
  	if (err)
  		return err;
1f53146da   Kinglong Mee   NFSD: Using type ...
446
  	if (listsize > MAX_SECINFO_LIST)
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
447
448
449
  		return -EINVAL;
  
  	for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
a007c4c3e   J. Bruce Fields   nfsd: add get_uin...
450
  		err = get_uint(mesg, &f->pseudoflavor);
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
451
452
453
  		if (err)
  			return err;
  		/*
80492e7d4   Roel Kluin   rpcgss: remove re...
454
455
456
457
  		 * XXX: It would be nice to also check whether this
  		 * pseudoflavor is supported, so we can discover the
  		 * problem at export time instead of when a client fails
  		 * to authenticate.
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
458
  		 */
a007c4c3e   J. Bruce Fields   nfsd: add get_uin...
459
  		err = get_uint(mesg, &f->flags);
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
460
461
462
463
464
465
466
467
468
  		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;
  }
933469190   Manoj Naik   [PATCH] knfsd: nf...
469
  #else /* CONFIG_NFSD_V4 */
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
470
471
472
473
  static inline int
  fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}
  static inline int
  secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
933469190   Manoj Naik   [PATCH] knfsd: nf...
474
  #endif
0d63790c3   Kinglong Mee   NFSD: Helper func...
475
476
477
478
  static inline int
  uuid_parse(char **mesg, char *buf, unsigned char **puuid)
  {
  	int len;
be69da805   Kinglong Mee   NFSD: Error out w...
479
480
481
  	/* more than one uuid */
  	if (*puuid)
  		return -EINVAL;
0d63790c3   Kinglong Mee   NFSD: Helper func...
482
483
  	/* expect a 16 byte uuid encoded as \xXXXX... */
  	len = qword_get(mesg, buf, PAGE_SIZE);
94eb36892   Kinglong Mee   NFSD: Adds macro ...
484
  	if (len != EX_UUID_LEN)
0d63790c3   Kinglong Mee   NFSD: Helper func...
485
  		return -EINVAL;
94eb36892   Kinglong Mee   NFSD: Adds macro ...
486
  	*puuid = kmemdup(buf, EX_UUID_LEN, GFP_KERNEL);
0d63790c3   Kinglong Mee   NFSD: Helper func...
487
488
489
490
491
  	if (*puuid == NULL)
  		return -ENOMEM;
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
494
495
496
497
498
  static 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;
c1a2a4756   Al Viro   [PATCH] sanitize ...
499
  	struct svc_export exp = {}, *expp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  	int an_int;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
504
505
506
  	if (mesg[mlen-1] != '
  ')
  		return -EINVAL;
  	mesg[mlen-1] = 0;
  
  	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
c1a2a4756   Al Viro   [PATCH] sanitize ...
507
508
  	if (!buf)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
  
  	/* client */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  	err = -EINVAL;
c1a2a4756   Al Viro   [PATCH] sanitize ...
512
513
514
  	len = qword_get(&mesg, buf, PAGE_SIZE);
  	if (len <= 0)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
520
521
522
  
  	err = -ENOENT;
  	dom = auth_domain_find(buf);
  	if (!dom)
  		goto out;
  
  	/* path */
  	err = -EINVAL;
c1a2a4756   Al Viro   [PATCH] sanitize ...
523
524
525
526
527
528
  	if ((len = qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
  		goto out1;
  
  	err = kern_path(buf, 0, &exp.ex_path);
  	if (err)
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  	exp.ex_client = dom;
db3a35326   Stanislav Kinsbursky   nfsd: add link to...
531
  	exp.cd = cd;
9cf514ccf   Christoph Hellwig   nfsd: implement p...
532
  	exp.ex_devid_map = NULL;
c1a2a4756   Al Viro   [PATCH] sanitize ...
533

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
537
  	/* expiry */
  	err = -EINVAL;
  	exp.h.expiry_time = get_expiry(&mesg);
  	if (exp.h.expiry_time == 0)
c1a2a4756   Al Viro   [PATCH] sanitize ...
538
  		goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
  
  	/* flags */
  	err = get_int(&mesg, &an_int);
4a4b88317   J. Bruce Fields   knfsd: eliminate ...
542
543
  	if (err == -ENOENT) {
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  		set_bit(CACHE_NEGATIVE, &exp.h.flags);
4a4b88317   J. Bruce Fields   knfsd: eliminate ...
545
  	} else {
c1a2a4756   Al Viro   [PATCH] sanitize ...
546
547
  		if (err || an_int < 0)
  			goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
550
551
  		exp.ex_flags= an_int;
  	
  		/* anon uid */
  		err = get_int(&mesg, &an_int);
c1a2a4756   Al Viro   [PATCH] sanitize ...
552
553
  		if (err)
  			goto out3;
4c1e1b34d   Eric W. Biederman   nfsd: Store ex_an...
554
  		exp.ex_anon_uid= make_kuid(&init_user_ns, an_int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
  
  		/* anon gid */
  		err = get_int(&mesg, &an_int);
c1a2a4756   Al Viro   [PATCH] sanitize ...
558
559
  		if (err)
  			goto out3;
4c1e1b34d   Eric W. Biederman   nfsd: Store ex_an...
560
  		exp.ex_anon_gid= make_kgid(&init_user_ns, an_int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
562
563
  
  		/* fsid */
  		err = get_int(&mesg, &an_int);
c1a2a4756   Al Viro   [PATCH] sanitize ...
564
565
  		if (err)
  			goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  		exp.ex_fsid = an_int;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
567
568
569
  		while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
  			if (strcmp(buf, "fsloc") == 0)
  				err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
0d63790c3   Kinglong Mee   NFSD: Helper func...
570
571
572
  			else if (strcmp(buf, "uuid") == 0)
  				err = uuid_parse(&mesg, buf, &exp.ex_uuid);
  			else if (strcmp(buf, "secinfo") == 0)
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
573
574
  				err = secinfo_parse(&mesg, buf, &exp);
  			else
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
575
576
577
578
579
580
  				/* quietly ignore unknown words and anything
  				 * following. Newer user-space can try to set
  				 * new values, then see what the result was.
  				 */
  				break;
  			if (err)
c1a2a4756   Al Viro   [PATCH] sanitize ...
581
  				goto out4;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
582
  		}
933469190   Manoj Naik   [PATCH] knfsd: nf...
583

2b0143b5c   David Howells   VFS: normal files...
584
  		err = check_export(d_inode(exp.ex_path.dentry), &exp.ex_flags,
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
585
  				   exp.ex_uuid);
c1a2a4756   Al Viro   [PATCH] sanitize ...
586
587
  		if (err)
  			goto out4;
427d6c664   J. Bruce Fields   nfsd: return bett...
588
  		/*
6f6cc3205   J. Bruce Fields   nfsd: -EINVAL on ...
589
590
591
592
593
594
595
  		 * No point caching this if it would immediately expire.
  		 * Also, this protects exportfs's dummy export from the
  		 * anon_uid/anon_gid checks:
  		 */
  		if (exp.h.expiry_time < seconds_since_boot())
  			goto out4;
  		/*
427d6c664   J. Bruce Fields   nfsd: return bett...
596
597
598
599
600
601
  		 * For some reason exportfs has been passing down an
  		 * invalid (-1) uid & gid on the "dummy" export which it
  		 * uses to test export support.  To make sure exportfs
  		 * sees errors from check_export we therefore need to
  		 * delay these checks till after check_export:
  		 */
6f6cc3205   J. Bruce Fields   nfsd: -EINVAL on ...
602
  		err = -EINVAL;
427d6c664   J. Bruce Fields   nfsd: return bett...
603
604
605
606
  		if (!uid_valid(exp.ex_anon_uid))
  			goto out4;
  		if (!gid_valid(exp.ex_anon_gid))
  			goto out4;
6f6cc3205   J. Bruce Fields   nfsd: -EINVAL on ...
607
  		err = 0;
9cf514ccf   Christoph Hellwig   nfsd: implement p...
608
609
  
  		nfsd4_setup_layout_type(&exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
  	}
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
611
  	expp = svc_export_lookup(&exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
  	if (expp)
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
613
614
615
  		expp = svc_export_update(&exp, expp);
  	else
  		err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
  	cache_flush();
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
617
618
619
620
  	if (expp == NULL)
  		err = -ENOMEM;
  	else
  		exp_put(expp);
c1a2a4756   Al Viro   [PATCH] sanitize ...
621
  out4:
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
622
623
  	nfsd4_fslocs_free(&exp.ex_fslocs);
  	kfree(exp.ex_uuid);
c1a2a4756   Al Viro   [PATCH] sanitize ...
624
  out3:
c1a2a4756   Al Viro   [PATCH] sanitize ...
625
626
627
628
  	path_put(&exp.ex_path);
  out1:
  	auth_domain_put(dom);
  out:
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
629
  	kfree(buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
  	return err;
  }
933469190   Manoj Naik   [PATCH] knfsd: nf...
632
  static void exp_flags(struct seq_file *m, int flag, int fsid,
4c1e1b34d   Eric W. Biederman   nfsd: Store ex_an...
633
  		kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fslocs);
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
634
  static void show_secinfo(struct seq_file *m, struct svc_export *exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
637
638
639
640
641
642
643
644
645
646
647
  
  static int svc_export_show(struct seq_file *m,
  			   struct cache_detail *cd,
  			   struct cache_head *h)
  {
  	struct svc_export *exp ;
  
  	if (h ==NULL) {
  		seq_puts(m, "#path domain(flags)
  ");
  		return 0;
  	}
  	exp = container_of(h, struct svc_export, h);
c32c2f63a   Jan Blunck   d_path: Make seq_...
648
649
  	seq_path(m, &exp->ex_path, " \t
  \\");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
653
654
  	seq_putc(m, '\t');
  	seq_escape(m, exp->ex_client->name, " \t
  \\");
  	seq_putc(m, '(');
  	if (test_bit(CACHE_VALID, &h->flags) && 
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
655
  	    !test_bit(CACHE_NEGATIVE, &h->flags)) {
933469190   Manoj Naik   [PATCH] knfsd: nf...
656
657
  		exp_flags(m, exp->ex_flags, exp->ex_fsid,
  			  exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
658
659
660
  		if (exp->ex_uuid) {
  			int i;
  			seq_puts(m, ",uuid=");
94eb36892   Kinglong Mee   NFSD: Adds macro ...
661
  			for (i = 0; i < EX_UUID_LEN; i++) {
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
662
663
664
665
666
  				if ((i&3) == 0 && i)
  					seq_putc(m, ':');
  				seq_printf(m, "%02x", exp->ex_uuid[i]);
  			}
  		}
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
667
  		show_secinfo(m, exp);
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
668
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
  	seq_puts(m, ")
  ");
  	return 0;
  }
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
673
  static int svc_export_match(struct cache_head *a, struct cache_head *b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
  {
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
675
676
677
  	struct svc_export *orig = container_of(a, struct svc_export, h);
  	struct svc_export *new = container_of(b, struct svc_export, h);
  	return orig->ex_client == new->ex_client &&
b77a4b2ed   Kinglong Mee   NFSD: Using path_...
678
  		path_equal(&orig->ex_path, &new->ex_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
  }
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
680
681
  
  static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
  {
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
683
684
  	struct svc_export *new = container_of(cnew, struct svc_export, h);
  	struct svc_export *item = container_of(citem, struct svc_export, h);
efc36aa56   NeilBrown   [PATCH] knfsd: Ch...
685
  	kref_get(&item->ex_client->ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
  	new->ex_client = item->ex_client;
0da22a919   Kinglong Mee   NFSD: Using path_...
687
688
  	new->ex_path = item->ex_path;
  	path_get(&item->ex_path);
933469190   Manoj Naik   [PATCH] knfsd: nf...
689
690
691
  	new->ex_fslocs.locations = NULL;
  	new->ex_fslocs.locations_count = 0;
  	new->ex_fslocs.migrated = 0;
8a4c39268   Jeff Layton   nfsd: allow nfsd ...
692
  	new->ex_layout_types = 0;
2eeb9b2ab   Jeff Layton   nfsd: initialize ...
693
  	new->ex_uuid = NULL;
db3a35326   Stanislav Kinsbursky   nfsd: add link to...
694
  	new->cd = item->cd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  }
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
696
  static void export_update(struct cache_head *cnew, struct cache_head *citem)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  {
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
698
699
  	struct svc_export *new = container_of(cnew, struct svc_export, h);
  	struct svc_export *item = container_of(citem, struct svc_export, h);
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
700
  	int i;
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
701

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
705
  	new->ex_flags = item->ex_flags;
  	new->ex_anon_uid = item->ex_anon_uid;
  	new->ex_anon_gid = item->ex_anon_gid;
  	new->ex_fsid = item->ex_fsid;
9cf514ccf   Christoph Hellwig   nfsd: implement p...
706
707
  	new->ex_devid_map = item->ex_devid_map;
  	item->ex_devid_map = NULL;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
708
709
  	new->ex_uuid = item->ex_uuid;
  	item->ex_uuid = NULL;
933469190   Manoj Naik   [PATCH] knfsd: nf...
710
711
712
713
714
715
  	new->ex_fslocs.locations = item->ex_fslocs.locations;
  	item->ex_fslocs.locations = NULL;
  	new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
  	item->ex_fslocs.locations_count = 0;
  	new->ex_fslocs.migrated = item->ex_fslocs.migrated;
  	item->ex_fslocs.migrated = 0;
8a4c39268   Jeff Layton   nfsd: allow nfsd ...
716
  	new->ex_layout_types = item->ex_layout_types;
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
717
718
719
720
  	new->ex_nflavors = item->ex_nflavors;
  	for (i = 0; i < MAX_SECINFO_LIST; i++) {
  		new->ex_flavors[i] = item->ex_flavors[i];
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
  }
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
722
723
724
725
726
727
728
729
  static struct cache_head *svc_export_alloc(void)
  {
  	struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
  	if (i)
  		return &i->h;
  	else
  		return NULL;
  }
2355c5964   J. Bruce Fields   nfsd4: fix missin...
730
  static struct cache_detail svc_export_cache_template = {
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
731
732
  	.owner		= THIS_MODULE,
  	.hash_size	= EXPORT_HASHMAX,
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
733
734
  	.name		= "nfsd.export",
  	.cache_put	= svc_export_put,
73fb847a4   Stanislav Kinsbursky   SUNRPC: introduce...
735
  	.cache_request	= svc_export_request,
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
736
737
738
739
740
741
742
  	.cache_parse	= svc_export_parse,
  	.cache_show	= svc_export_show,
  	.match		= svc_export_match,
  	.init		= svc_export_init,
  	.update		= export_update,
  	.alloc		= svc_export_alloc,
  };
61f8603d9   NeilBrown   nfsd: factor out ...
743
744
  static int
  svc_export_hash(struct svc_export *exp)
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
745
  {
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
746
  	int hash;
61f8603d9   NeilBrown   nfsd: factor out ...
747

4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
748
  	hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
547754916   Jan Blunck   Use struct path i...
749
750
  	hash ^= hash_ptr(exp->ex_path.dentry, EXPORT_HASHBITS);
  	hash ^= hash_ptr(exp->ex_path.mnt, EXPORT_HASHBITS);
61f8603d9   NeilBrown   nfsd: factor out ...
751
752
753
754
755
756
757
758
  	return hash;
  }
  
  static struct svc_export *
  svc_export_lookup(struct svc_export *exp)
  {
  	struct cache_head *ch;
  	int hash = svc_export_hash(exp);
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
759

db3a35326   Stanislav Kinsbursky   nfsd: add link to...
760
  	ch = sunrpc_cache_lookup(exp->cd, &exp->h, hash);
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
761
762
763
764
765
  	if (ch)
  		return container_of(ch, struct svc_export, h);
  	else
  		return NULL;
  }
74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
766
  static struct svc_export *
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
767
768
769
  svc_export_update(struct svc_export *new, struct svc_export *old)
  {
  	struct cache_head *ch;
61f8603d9   NeilBrown   nfsd: factor out ...
770
  	int hash = svc_export_hash(old);
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
771

db3a35326   Stanislav Kinsbursky   nfsd: add link to...
772
  	ch = sunrpc_cache_update(old->cd, &new->h, &old->h, hash);
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
773
774
775
776
777
  	if (ch)
  		return container_of(ch, struct svc_export, h);
  	else
  		return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778

74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
779
  static struct svc_expkey *
e6d615f74   Kinglong Mee   NFSD: Remove type...
780
  exp_find_key(struct cache_detail *cd, struct auth_domain *clp, int fsid_type,
c89172e36   Stanislav Kinsbursky   nfsd: pass pointe...
781
  	     u32 *fsidv, struct cache_req *reqp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
783
784
785
786
  {
  	struct svc_expkey key, *ek;
  	int err;
  	
  	if (!clp)
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
787
  		return ERR_PTR(-ENOENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
789
790
791
  
  	key.ek_client = clp;
  	key.ek_fsidtype = fsid_type;
  	memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
c89172e36   Stanislav Kinsbursky   nfsd: pass pointe...
792
  	ek = svc_expkey_lookup(cd, &key);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
793
794
  	if (ek == NULL)
  		return ERR_PTR(-ENOMEM);
c89172e36   Stanislav Kinsbursky   nfsd: pass pointe...
795
  	err = cache_check(cd, &ek->h, reqp);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
796
797
  	if (err)
  		return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
  	return ek;
  }
e6d615f74   Kinglong Mee   NFSD: Remove type...
800
801
802
  static struct svc_export *
  exp_get_by_name(struct cache_detail *cd, struct auth_domain *clp,
  		const struct path *path, struct cache_req *reqp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
  {
  	struct svc_export *exp, key;
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
805
  	int err;
e83aece3a   Jan Blunck   Use struct path i...
806

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  	if (!clp)
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
808
  		return ERR_PTR(-ENOENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
  
  	key.ex_client = clp;
55430e2ec   Al Viro   nfsd struct path ...
811
  	key.ex_path = *path;
2a75cfa64   Stanislav Kinsbursky   nfsd: pass pointe...
812
  	key.cd = cd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813

4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
814
  	exp = svc_export_lookup(&key);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
815
816
  	if (exp == NULL)
  		return ERR_PTR(-ENOMEM);
2a75cfa64   Stanislav Kinsbursky   nfsd: pass pointe...
817
  	err = cache_check(cd, &exp->h, reqp);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
818
819
  	if (err)
  		return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
822
823
824
825
  	return exp;
  }
  
  /*
   * Find the export entry for a given dentry.
   */
e6d615f74   Kinglong Mee   NFSD: Remove type...
826
827
  static struct svc_export *
  exp_parent(struct cache_detail *cd, struct auth_domain *clp, struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  {
5bf3bd2b5   Al Viro   switch exp_parent...
829
  	struct dentry *saved = dget(path->dentry);
e6d615f74   Kinglong Mee   NFSD: Remove type...
830
  	struct svc_export *exp = exp_get_by_name(cd, clp, path, NULL);
5bf3bd2b5   Al Viro   switch exp_parent...
831
832
833
834
835
  
  	while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
  		struct dentry *parent = dget_parent(path->dentry);
  		dput(path->dentry);
  		path->dentry = parent;
2a75cfa64   Stanislav Kinsbursky   nfsd: pass pointe...
836
  		exp = exp_get_by_name(cd, clp, path, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
  	}
5bf3bd2b5   Al Viro   switch exp_parent...
838
839
  	dput(path->dentry);
  	path->dentry = saved;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
841
  	return exp;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
845
846
847
848
849
  
  /*
   * 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.
   */
  int
e6d615f74   Kinglong Mee   NFSD: Remove type...
850
  exp_rootfh(struct net *net, struct auth_domain *clp, char *name,
2a75cfa64   Stanislav Kinsbursky   nfsd: pass pointe...
851
  	   struct knfsd_fh *f, int maxsize)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
  {
  	struct svc_export	*exp;
a63bb9966   Al Viro   [PATCH] switch nf...
854
  	struct path		path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
856
857
  	struct inode		*inode;
  	struct svc_fh		fh;
  	int			err;
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
858
859
  	struct nfsd_net		*nn = net_generic(net, nfsd_net_id);
  	struct cache_detail	*cd = nn->svc_export_cache;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
862
  
  	err = -EPERM;
  	/* NB: we probably ought to check that it's NUL-terminated */
a63bb9966   Al Viro   [PATCH] switch nf...
863
864
  	if (kern_path(name, 0, &path)) {
  		printk("nfsd: exp_rootfh path not found %s", name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
  		return err;
  	}
2b0143b5c   David Howells   VFS: normal files...
867
  	inode = d_inode(path.dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
869
870
  
  	dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)
  ",
a63bb9966   Al Viro   [PATCH] switch nf...
871
  		 name, path.dentry, clp->name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
  		 inode->i_sb->s_id, inode->i_ino);
2a75cfa64   Stanislav Kinsbursky   nfsd: pass pointe...
873
  	exp = exp_parent(cd, clp, &path);
4b41bd85d   J.Bruce Fields   [PATCH] knfsd: nf...
874
875
876
877
  	if (IS_ERR(exp)) {
  		err = PTR_ERR(exp);
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
879
880
881
882
  
  	/*
  	 * fh must be initialized before calling fh_compose
  	 */
  	fh_init(&fh, maxsize);
a63bb9966   Al Viro   [PATCH] switch nf...
883
  	if (fh_compose(&fh, exp, path.dentry, NULL))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
885
886
887
888
889
890
  		err = -EINVAL;
  	else
  		err = 0;
  	memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
  	fh_put(&fh);
  	exp_put(exp);
  out:
a63bb9966   Al Viro   [PATCH] switch nf...
891
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
893
  	return err;
  }
2a75cfa64   Stanislav Kinsbursky   nfsd: pass pointe...
894
895
  static struct svc_export *exp_find(struct cache_detail *cd,
  				   struct auth_domain *clp, int fsid_type,
cce76f9b9   Adrian Bunk   fs/nfsd/export.c:...
896
  				   u32 *fsidv, struct cache_req *reqp)
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
897
898
  {
  	struct svc_export *exp;
e5f06f720   Stanislav Kinsbursky   nfsd: make expkey...
899
900
  	struct nfsd_net *nn = net_generic(cd->net, nfsd_net_id);
  	struct svc_expkey *ek = exp_find_key(nn->svc_expkey_cache, clp, fsid_type, fsidv, reqp);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
901
  	if (IS_ERR(ek))
e231c2ee6   David Howells   Convert ERR_PTR(P...
902
  		return ERR_CAST(ek);
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
903

2a75cfa64   Stanislav Kinsbursky   nfsd: pass pointe...
904
  	exp = exp_get_by_name(cd, clp, &ek->ek_path, reqp);
e5f06f720   Stanislav Kinsbursky   nfsd: make expkey...
905
  	cache_put(&ek->h, nn->svc_expkey_cache);
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
906

2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
907
  	if (IS_ERR(exp))
e231c2ee6   David Howells   Convert ERR_PTR(P...
908
  		return ERR_CAST(exp);
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
909
910
  	return exp;
  }
32c1eb0cd   Andy Adamson   knfsd: nfsd4: ret...
911
912
913
914
915
916
917
918
919
920
  __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++) {
d5497fc69   J. Bruce Fields   nfsd4: move rq_fl...
921
  		if (f->pseudoflavor == rqstp->rq_cred.cr_flavor)
32c1eb0cd   Andy Adamson   knfsd: nfsd4: ret...
922
923
924
925
  			return 0;
  	}
  	/* defaults in absence of sec= options: */
  	if (exp->ex_nflavors == 0) {
d5497fc69   J. Bruce Fields   nfsd4: move rq_fl...
926
927
  		if (rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
  		    rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)
32c1eb0cd   Andy Adamson   knfsd: nfsd4: ret...
928
929
  			return 0;
  	}
ed9416439   Andrew Elble   nfsd: implement m...
930
931
932
933
934
935
936
937
938
  
  	/* If the compound op contains a spo_must_allowed op,
  	 * it will be sent with integrity/protection which
  	 * will have to be expressly allowed on mounts that
  	 * don't support it
  	 */
  
  	if (nfsd4_spo_must_allow(rqstp))
  		return 0;
32c1eb0cd   Andy Adamson   knfsd: nfsd4: ret...
939
940
  	return nfserr_wrongsec;
  }
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
941
  /*
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
942
943
944
945
   * 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.
   *
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
946
947
948
949
950
   * 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 *
91c9fa8f7   Al Viro   switch rqst_exp_g...
951
  rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
952
  {
9a25b96c1   J. Bruce Fields   nfsd: return erro...
953
  	struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
9695c7057   Stanislav Kinsbursky   SUNRPC: service r...
954
  	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
955
  	struct cache_detail *cd = nn->svc_export_cache;
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
956
957
958
  
  	if (rqstp->rq_client == NULL)
  		goto gss;
3ab4d8b12   J. Bruce Fields   knfsd: nfsd: set ...
959

2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
960
  	/* First try the auth_unix client: */
2a75cfa64   Stanislav Kinsbursky   nfsd: pass pointe...
961
  	exp = exp_get_by_name(cd, rqstp->rq_client, path, &rqstp->rq_chandle);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
962
963
964
965
966
967
968
969
970
971
972
  	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;
2a75cfa64   Stanislav Kinsbursky   nfsd: pass pointe...
973
  	gssexp = exp_get_by_name(cd, rqstp->rq_gssclient, path, &rqstp->rq_chandle);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
974
975
  	if (PTR_ERR(gssexp) == -ENOENT)
  		return exp;
9a25b96c1   J. Bruce Fields   nfsd: return erro...
976
  	if (!IS_ERR(exp))
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
977
978
  		exp_put(exp);
  	return gssexp;
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
979
980
981
982
983
  }
  
  struct svc_export *
  rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
  {
9a25b96c1   J. Bruce Fields   nfsd: return erro...
984
  	struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
9695c7057   Stanislav Kinsbursky   SUNRPC: service r...
985
  	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
986
  	struct cache_detail *cd = nn->svc_export_cache;
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
987
988
989
  
  	if (rqstp->rq_client == NULL)
  		goto gss;
3ab4d8b12   J. Bruce Fields   knfsd: nfsd: set ...
990

2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
991
  	/* First try the auth_unix client: */
2a75cfa64   Stanislav Kinsbursky   nfsd: pass pointe...
992
993
  	exp = exp_find(cd, rqstp->rq_client, fsid_type,
  		       fsidv, &rqstp->rq_chandle);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
994
995
996
997
998
999
1000
1001
1002
1003
1004
  	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;
2a75cfa64   Stanislav Kinsbursky   nfsd: pass pointe...
1005
  	gssexp = exp_find(cd, rqstp->rq_gssclient, fsid_type, fsidv,
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1006
1007
1008
  						&rqstp->rq_chandle);
  	if (PTR_ERR(gssexp) == -ENOENT)
  		return exp;
9a25b96c1   J. Bruce Fields   nfsd: return erro...
1009
  	if (!IS_ERR(exp))
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1010
1011
  		exp_put(exp);
  	return gssexp;
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
1012
1013
1014
  }
  
  struct svc_export *
e64c390ca   Al Viro   switch rqst_exp_p...
1015
  rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
1016
  {
e64c390ca   Al Viro   switch rqst_exp_p...
1017
1018
  	struct dentry *saved = dget(path->dentry);
  	struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1019

e64c390ca   Al Viro   switch rqst_exp_p...
1020
1021
1022
1023
1024
  	while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
  		struct dentry *parent = dget_parent(path->dentry);
  		dput(path->dentry);
  		path->dentry = parent;
  		exp = rqst_exp_get_by_name(rqstp, path);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1025
  	}
e64c390ca   Al Viro   switch rqst_exp_p...
1026
1027
  	dput(path->dentry);
  	path->dentry = saved;
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1028
  	return exp;
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
1029
  }
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
1030

ed748aacb   Trond Myklebust   NFSD: Cleanup for...
1031
  struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp)
f39bde24b   J. Bruce Fields   nfsd4: fix error ...
1032
  {
f39bde24b   J. Bruce Fields   nfsd4: fix error ...
1033
1034
1035
  	u32 fsidv[2];
  
  	mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
260c64d23   J. Bruce Fields   Revert "nfsd4: fi...
1036
  	return rqst_exp_find(rqstp, FSID_NUM, fsidv);
f39bde24b   J. Bruce Fields   nfsd4: fix error ...
1037
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
1040
1041
1042
  /*
   * 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
   */
c7afef1f9   Al Viro   [PATCH] nfsd: mis...
1043
  __be32
df547efb0   J. Bruce Fields   knfsd: nfsd4: sim...
1044
  exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
  {
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
1046
  	struct svc_export *exp;
c7afef1f9   Al Viro   [PATCH] nfsd: mis...
1047
  	__be32 rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048

ed748aacb   Trond Myklebust   NFSD: Cleanup for...
1049
  	exp = rqst_find_fsidzero_export(rqstp);
6899320c2   J.Bruce Fields   [PATCH] knfsd: nf...
1050
1051
  	if (IS_ERR(exp))
  		return nfserrno(PTR_ERR(exp));
547754916   Jan Blunck   Use struct path i...
1052
  	rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
d0ebd9c0e   J.Bruce Fields   [PATCH] knfsd: nf...
1053
  	exp_put(exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
1055
  	return rv;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
  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"}},
18c01ab30   Rajesh Ghanekar   nfsd: allow turni...
1066
  	{ NFSEXP_NOREADDIRPLUS, {"nordirplus", ""}},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
1069
1070
  	{ NFSEXP_NOHIDE, {"nohide", ""}},
  	{ NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
  	{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
  	{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
eb4c86c6a   Steve Dickson   nfsd: introduce e...
1071
  	{ NFSEXP_V4ROOT, {"v4root", ""}},
9b3075c59   Christoph Hellwig   nfsd: add NFSEXP_...
1072
  	{ NFSEXP_PNFS, {"pnfs", ""}},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
1074
  	{ 0, {"", ""}}
  };
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1075
  static void show_expflags(struct seq_file *m, int flags, int mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
  	struct flags *flg;
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1078
  	int state, first = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
1080
  
  	for (flg = expflags; flg->flag; flg++) {
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1081
1082
1083
  		if (flg->flag & ~mask)
  			continue;
  		state = (flg->flag & flags) ? 0 : 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
1085
1086
  		if (*flg->name[state])
  			seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
  	}
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1087
  }
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
1088
1089
1090
1091
1092
  static void show_secinfo_flags(struct seq_file *m, int flags)
  {
  	seq_printf(m, ",");
  	show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
  }
74ec1e126   J. Bruce Fields   nfsd: fix /proc/n...
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
  static bool secinfo_flags_equal(int f, int g)
  {
  	f &= NFSEXP_SECINFO_FLAGS;
  	g &= NFSEXP_SECINFO_FLAGS;
  	return f == g;
  }
  
  static int show_secinfo_run(struct seq_file *m, struct exp_flavor_info **fp, struct exp_flavor_info *end)
  {
  	int flags;
  
  	flags = (*fp)->flags;
  	seq_printf(m, ",sec=%d", (*fp)->pseudoflavor);
  	(*fp)++;
  	while (*fp != end && secinfo_flags_equal(flags, (*fp)->flags)) {
  		seq_printf(m, ":%d", (*fp)->pseudoflavor);
  		(*fp)++;
  	}
  	return flags;
  }
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
1113
1114
1115
1116
  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;
74ec1e126   J. Bruce Fields   nfsd: fix /proc/n...
1117
  	int flags;
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
1118
1119
1120
  
  	if (exp->ex_nflavors == 0)
  		return;
74ec1e126   J. Bruce Fields   nfsd: fix /proc/n...
1121
1122
1123
1124
1125
1126
1127
  	f = exp->ex_flavors;
  	flags = show_secinfo_run(m, &f, end);
  	if (!secinfo_flags_equal(flags, exp->ex_flags))
  		show_secinfo_flags(m, flags);
  	while (f != end) {
  		flags = show_secinfo_run(m, &f, end);
  		show_secinfo_flags(m, flags);
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
1128
  	}
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
1129
  }
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1130
  static void exp_flags(struct seq_file *m, int flag, int fsid,
4c1e1b34d   Eric W. Biederman   nfsd: Store ex_an...
1131
  		kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fsloc)
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1132
1133
  {
  	show_expflags(m, flag, NFSEXP_ALLFLAGS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
  	if (flag & NFSEXP_FSID)
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1135
  		seq_printf(m, ",fsid=%d", fsid);
4c1e1b34d   Eric W. Biederman   nfsd: Store ex_an...
1136
1137
1138
1139
1140
1141
  	if (!uid_eq(anonu, make_kuid(&init_user_ns, (uid_t)-2)) &&
  	    !uid_eq(anonu, make_kuid(&init_user_ns, 0x10000-2)))
  		seq_printf(m, ",anonuid=%u", from_kuid(&init_user_ns, anonu));
  	if (!gid_eq(anong, make_kgid(&init_user_ns, (gid_t)-2)) &&
  	    !gid_eq(anong, make_kgid(&init_user_ns, 0x10000-2)))
  		seq_printf(m, ",anongid=%u", from_kgid(&init_user_ns, anong));
933469190   Manoj Naik   [PATCH] knfsd: nf...
1142
1143
1144
  	if (fsloc && fsloc->locations_count > 0) {
  		char *loctype = (fsloc->migrated) ? "refer" : "replicas";
  		int i;
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1145
  		seq_printf(m, ",%s=", loctype);
933469190   Manoj Naik   [PATCH] knfsd: nf...
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
  		seq_escape(m, fsloc->locations[0].path, ",;@ \t
  \\");
  		seq_putc(m, '@');
  		seq_escape(m, fsloc->locations[0].hosts, ",;@ \t
  \\");
  		for (i = 1; i < fsloc->locations_count; i++) {
  			seq_putc(m, ';');
  			seq_escape(m, fsloc->locations[i].path, ",;@ \t
  \\");
  			seq_putc(m, '@');
  			seq_escape(m, fsloc->locations[i].hosts, ",;@ \t
  \\");
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
1161
1162
1163
1164
1165
  }
  
  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);
f2c7ea10f   Stanislav Kinsbursky   nfsd: pass svc_ex...
1166
  	struct cache_detail *cd = m->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167

bc6f02e51   Greg Banks   [PATCH] knfsd: Us...
1168
  	if (p == SEQ_START_TOKEN) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
1170
1171
1172
1173
1174
  		seq_puts(m, "# Version 1.1
  ");
  		seq_puts(m, "# Path Client(Flags) # IPs
  ");
  		return 0;
  	}
bf18f163e   Kinglong Mee   NFSD: Using exp_g...
1175
  	exp_get(exp);
f2c7ea10f   Stanislav Kinsbursky   nfsd: pass svc_ex...
1176
  	if (cache_check(cd, &exp->h, NULL))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1177
  		return 0;
a09581f29   Stanislav Kinsbursky   nfsd: use exp_put...
1178
  	exp_put(exp);
f2c7ea10f   Stanislav Kinsbursky   nfsd: pass svc_ex...
1179
  	return svc_export_show(m, cd, cp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
  }
88e9d34c7   James Morris   seq_file: constif...
1181
  const struct seq_operations nfs_exports_op = {
c8c081b70   Kinglong Mee   sunrpc/nfsd: Remo...
1182
1183
1184
  	.start	= cache_seq_start,
  	.next	= cache_seq_next,
  	.stop	= cache_seq_stop,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
1186
  	.show	= e_show,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
1189
  /*
   * Initialize the exports module.
   */
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1190
  int
b89109bef   Stanislav Kinsbursky   nfsd: pass networ...
1191
  nfsd_export_init(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
  {
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1193
  	int rv;
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1194
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
b89109bef   Stanislav Kinsbursky   nfsd: pass networ...
1195
1196
  	dprintk("nfsd: initializing export module (net: %p).
  ", net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197

b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1198
1199
1200
1201
  	nn->svc_export_cache = cache_create_net(&svc_export_cache_template, net);
  	if (IS_ERR(nn->svc_export_cache))
  		return PTR_ERR(nn->svc_export_cache);
  	rv = cache_register_net(nn->svc_export_cache, net);
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1202
  	if (rv)
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1203
  		goto destroy_export_cache;
e5f06f720   Stanislav Kinsbursky   nfsd: make expkey...
1204
1205
1206
  	nn->svc_expkey_cache = cache_create_net(&svc_expkey_cache_template, net);
  	if (IS_ERR(nn->svc_expkey_cache)) {
  		rv = PTR_ERR(nn->svc_expkey_cache);
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1207
  		goto unregister_export_cache;
e5f06f720   Stanislav Kinsbursky   nfsd: make expkey...
1208
1209
1210
1211
  	}
  	rv = cache_register_net(nn->svc_expkey_cache, net);
  	if (rv)
  		goto destroy_expkey_cache;
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1212
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213

e5f06f720   Stanislav Kinsbursky   nfsd: make expkey...
1214
1215
  destroy_expkey_cache:
  	cache_destroy_net(nn->svc_expkey_cache, net);
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1216
1217
1218
1219
1220
  unregister_export_cache:
  	cache_unregister_net(nn->svc_export_cache, net);
  destroy_export_cache:
  	cache_destroy_net(nn->svc_export_cache, net);
  	return rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
1222
1223
1224
1225
1226
  }
  
  /*
   * Flush exports table - called when last nfsd thread is killed
   */
  void
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1227
  nfsd_export_flush(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
  {
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1229
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
e5f06f720   Stanislav Kinsbursky   nfsd: make expkey...
1230
  	cache_purge(nn->svc_expkey_cache);
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1231
  	cache_purge(nn->svc_export_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
1233
1234
1235
1236
1237
  }
  
  /*
   * Shutdown the exports module.
   */
  void
b89109bef   Stanislav Kinsbursky   nfsd: pass networ...
1238
  nfsd_export_shutdown(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1239
  {
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1240
  	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241

b89109bef   Stanislav Kinsbursky   nfsd: pass networ...
1242
1243
  	dprintk("nfsd: shutting down export module (net: %p).
  ", net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244

e5f06f720   Stanislav Kinsbursky   nfsd: make expkey...
1245
  	cache_unregister_net(nn->svc_expkey_cache, net);
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1246
  	cache_unregister_net(nn->svc_export_cache, net);
e5f06f720   Stanislav Kinsbursky   nfsd: make expkey...
1247
  	cache_destroy_net(nn->svc_expkey_cache, net);
b3853e0ea   Stanislav Kinsbursky   nfsd: make export...
1248
  	cache_destroy_net(nn->svc_export_cache, net);
e5f06f720   Stanislav Kinsbursky   nfsd: make expkey...
1249
  	svcauth_unix_purge(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250

b89109bef   Stanislav Kinsbursky   nfsd: pass networ...
1251
1252
  	dprintk("nfsd: export shutdown complete (net: %p).
  ", net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1253
  }