Blame view

fs/nfsd/export.c 29.9 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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17

f15364bd4   AurĂ©lien Charbon   IPv6 support for ...
18
  #include <net/ipv6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

9a74af213   Boaz Harrosh   nfsd: Move privat...
20
  #include "nfsd.h"
1557aca79   J. Bruce Fields   nfsd: move most o...
21
  #include "nfsfh.h"
9a74af213   Boaz Harrosh   nfsd: Move privat...
22

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  #define NFSDDBG_FACILITY	NFSDDBG_EXPORT
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
  
  typedef struct auth_domain	svc_client;
  typedef struct svc_export	svc_export;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
33
34
35
36
37
38
39
  /*
   * 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];
74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
40
  static void expkey_put(struct kref *ref)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  {
baab935ff   NeilBrown   [PATCH] knfsd: Co...
42
43
44
  	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...
45
46
  	    !test_bit(CACHE_NEGATIVE, &key->h.flags))
  		path_put(&key->ek_path);
baab935ff   NeilBrown   [PATCH] knfsd: Co...
47
48
  	auth_domain_put(key->ek_client);
  	kfree(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  }
  
  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] = '
  ';
  }
bc74b4f5e   Trond Myklebust   SUNRPC: Allow the...
66
67
68
69
  static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
  {
  	return sunrpc_cache_pipe_upcall(cd, h, expkey_request);
  }
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
70
71
  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 *);
74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
72
  static struct cache_detail svc_expkey_cache;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
78
79
80
81
82
  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;
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
83
  	struct svc_expkey *ek = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
89
90
91
  
  	if (mesg[mlen-1] != '
  ')
  		return -EINVAL;
  	mesg[mlen-1] = 0;
  
  	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  	err = -ENOMEM;
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
92
93
  	if (!buf)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  
  	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...
114
  	if (key_len(fsidtype)==0) /* invalid type */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  		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);
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
132
133
134
135
  	ek = svc_expkey_lookup(&key);
  	err = -ENOMEM;
  	if (!ek)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  	/* now we want a pathname, or empty meaning NEGATIVE  */
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
137
  	err = -EINVAL;
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
138
139
  	len = qword_get(&mesg, buf, PAGE_SIZE);
  	if (len < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
  		goto out;
  	dprintk("Path seems to be <%s>
  ", buf);
  	err = 0;
  	if (len == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  		set_bit(CACHE_NEGATIVE, &key.h.flags);
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
146
  		ek = svc_expkey_update(&key, ek);
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
147
148
  		if (!ek)
  			err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  	} else {
a63bb9966   Al Viro   [PATCH] switch nf...
150
  		err = kern_path(buf, 0, &key.ek_path);
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
151
  		if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
155
  			goto out;
  
  		dprintk("Found the path %s
  ", buf);
e83aece3a   Jan Blunck   Use struct path i...
156

8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
157
  		ek = svc_expkey_update(&key, ek);
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
158
  		if (!ek)
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
159
  			err = -ENOMEM;
a63bb9966   Al Viro   [PATCH] switch nf...
160
  		path_put(&key.ek_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
  	}
  	cache_flush();
   out:
30bc4dfd3   J. Bruce Fields   nfsd: clean up ex...
164
165
  	if (ek)
  		cache_put(&ek->h, &svc_expkey_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
  	if (dom)
  		auth_domain_put(dom);
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
168
  	kfree(buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
175
176
  	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...
177
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
180
181
182
183
184
  
  	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...
185
186
187
188
  	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
189
190
191
  	if (test_bit(CACHE_VALID, &h->flags) && 
  	    !test_bit(CACHE_NEGATIVE, &h->flags)) {
  		seq_printf(m, " ");
c32c2f63a   Jan Blunck   d_path: Make seq_...
192
193
  		seq_path(m, &ek->ek_path, "\\ \t
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
  	}
  	seq_printf(m, "
  ");
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199

8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
200
  static inline int expkey_match (struct cache_head *a, struct cache_head *b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  {
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
202
203
204
205
206
207
  	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
208
209
210
  		return 0;
  	return 1;
  }
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
211
212
  static inline void expkey_init(struct cache_head *cnew,
  				   struct cache_head *citem)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  {
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
214
215
  	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...
216
  	kref_get(&item->ek_client->ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
  	new->ek_client = item->ek_client;
  	new->ek_fsidtype = item->ek_fsidtype;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
219
220
  
  	memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  }
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
222
223
  static inline void expkey_update(struct cache_head *cnew,
  				   struct cache_head *citem)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  {
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
225
226
  	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...
227
228
  	new->ek_path = item->ek_path;
  	path_get(&item->ek_path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  }
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
230
231
232
233
234
235
236
237
  static struct cache_head *expkey_alloc(void)
  {
  	struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
  	if (i)
  		return &i->h;
  	else
  		return NULL;
  }
74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
238
  static struct cache_detail svc_expkey_cache = {
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
239
240
241
242
243
  	.owner		= THIS_MODULE,
  	.hash_size	= EXPKEY_HASHMAX,
  	.hash_table	= expkey_table,
  	.name		= "nfsd.fh",
  	.cache_put	= expkey_put,
bc74b4f5e   Trond Myklebust   SUNRPC: Allow the...
244
  	.cache_upcall	= expkey_upcall,
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
245
246
247
248
249
250
251
  	.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 ...
252
253
  static int
  svc_expkey_hash(struct svc_expkey *item)
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
254
  {
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
255
256
257
258
259
260
261
  	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 ...
262
263
264
265
266
267
268
269
  	return hash;
  }
  
  static struct svc_expkey *
  svc_expkey_lookup(struct svc_expkey *item)
  {
  	struct cache_head *ch;
  	int hash = svc_expkey_hash(item);
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
270
271
272
273
274
275
276
277
278
279
280
281
282
  
  	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;
61f8603d9   NeilBrown   nfsd: factor out ...
283
  	int hash = svc_expkey_hash(new);
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
284
285
286
287
288
289
290
291
  
  	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;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
  
  #define	EXPORT_HASHBITS		8
  #define	EXPORT_HASHMAX		(1<< EXPORT_HASHBITS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
  
  static struct cache_head *export_table[EXPORT_HASHMAX];
933469190   Manoj Naik   [PATCH] knfsd: nf...
297
298
299
300
301
302
303
304
305
306
  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);
  }
baab935ff   NeilBrown   [PATCH] knfsd: Co...
307
  static void svc_export_put(struct kref *ref)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  {
baab935ff   NeilBrown   [PATCH] knfsd: Co...
309
  	struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
547754916   Jan Blunck   Use struct path i...
310
  	path_put(&exp->ex_path);
baab935ff   NeilBrown   [PATCH] knfsd: Co...
311
  	auth_domain_put(exp->ex_client);
933469190   Manoj Naik   [PATCH] knfsd: nf...
312
  	nfsd4_fslocs_free(&exp->ex_fslocs);
baab935ff   NeilBrown   [PATCH] knfsd: Co...
313
  	kfree(exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
317
318
319
320
321
322
323
324
  }
  
  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...
325
  	pth = d_path(&exp->ex_path, *bpp, *blen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
331
332
333
334
335
  	if (IS_ERR(pth)) {
  		/* is this correct? */
  		(*bpp)[0] = '
  ';
  		return;
  	}
  	qword_add(bpp, blen, pth);
  	(*bpp)[-1] = '
  ';
  }
bc74b4f5e   Trond Myklebust   SUNRPC: Allow the...
336
337
338
339
  static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
  {
  	return sunrpc_cache_pipe_upcall(cd, h, svc_export_request);
  }
74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
340
341
  static struct svc_export *svc_export_update(struct svc_export *new,
  					    struct svc_export *old);
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
342
  static struct svc_export *svc_export_lookup(struct svc_export *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343

774b14782   J. Bruce Fields   nfsd: make V4ROOT...
344
  static int check_export(struct inode *inode, int *flags, unsigned char *uuid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  {
f2ca7153c   J. Bruce Fields   nfsd: allow expor...
346
347
348
  	/*
  	 * We currently export only dirs, regular files, and (for v4
  	 * pseudoroot) symlinks.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
  	 */
  	if (!S_ISDIR(inode->i_mode) &&
f2ca7153c   J. Bruce Fields   nfsd: allow expor...
351
  	    !S_ISLNK(inode->i_mode) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
  	    !S_ISREG(inode->i_mode))
  		return -ENOTDIR;
774b14782   J. Bruce Fields   nfsd: make V4ROOT...
354
355
356
357
358
359
  	/*
  	 * 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
360
361
362
  	/* 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...
363
  	 *       or an FSID number (so NFSEXP_FSID or ->uuid is needed).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
367
  	 * 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...
368
  	    !(*flags & NFSEXP_FSID) &&
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
369
  	    uuid == NULL) {
3e3b48009   Greg Banks   [PATCH] knfsd: ad...
370
371
  		dprintk("exp_export: export of non-dev fs without fsid
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
  		return -EINVAL;
  	}
cfaea787c   Christoph Hellwig   exportfs: remove ...
374
375
376
  
  	if (!inode->i_sb->s_export_op ||
  	    !inode->i_sb->s_export_op->fh_to_dentry) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
  		dprintk("exp_export: export of invalid fs type.
  ");
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
  	return 0;
  
  }
933469190   Manoj Naik   [PATCH] knfsd: nf...
384
385
386
387
388
389
390
  #ifdef CONFIG_NFSD_V4
  
  static int
  fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
  {
  	int len;
  	int migrated, i, err;
933469190   Manoj Naik   [PATCH] knfsd: nf...
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
434
435
436
  	/* 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;
  }
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  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;
  		/*
80492e7d4   Roel Kluin   rpcgss: remove re...
453
454
455
456
  		 * 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...
457
  		 */
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
458
459
460
461
462
463
464
465
466
467
  		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;
  }
933469190   Manoj Naik   [PATCH] knfsd: nf...
468
  #else /* CONFIG_NFSD_V4 */
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
469
470
471
472
  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...
473
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
477
478
479
480
  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 ...
481
  	struct svc_export exp = {}, *expp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  	int an_int;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
486
487
488
  	if (mesg[mlen-1] != '
  ')
  		return -EINVAL;
  	mesg[mlen-1] = 0;
  
  	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
c1a2a4756   Al Viro   [PATCH] sanitize ...
489
490
  	if (!buf)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
  
  	/* client */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
  	err = -EINVAL;
c1a2a4756   Al Viro   [PATCH] sanitize ...
494
495
496
  	len = qword_get(&mesg, buf, PAGE_SIZE);
  	if (len <= 0)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
501
502
503
504
  
  	err = -ENOENT;
  	dom = auth_domain_find(buf);
  	if (!dom)
  		goto out;
  
  	/* path */
  	err = -EINVAL;
c1a2a4756   Al Viro   [PATCH] sanitize ...
505
506
507
508
509
510
  	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
511

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  	exp.ex_client = dom;
c1a2a4756   Al Viro   [PATCH] sanitize ...
513

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
  	/* expiry */
  	err = -EINVAL;
  	exp.h.expiry_time = get_expiry(&mesg);
  	if (exp.h.expiry_time == 0)
c1a2a4756   Al Viro   [PATCH] sanitize ...
518
  		goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
521
  
  	/* flags */
  	err = get_int(&mesg, &an_int);
4a4b88317   J. Bruce Fields   knfsd: eliminate ...
522
523
  	if (err == -ENOENT) {
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  		set_bit(CACHE_NEGATIVE, &exp.h.flags);
4a4b88317   J. Bruce Fields   knfsd: eliminate ...
525
  	} else {
c1a2a4756   Al Viro   [PATCH] sanitize ...
526
527
  		if (err || an_int < 0)
  			goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
531
  		exp.ex_flags= an_int;
  	
  		/* anon uid */
  		err = get_int(&mesg, &an_int);
c1a2a4756   Al Viro   [PATCH] sanitize ...
532
533
  		if (err)
  			goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
537
  		exp.ex_anon_uid= an_int;
  
  		/* anon gid */
  		err = get_int(&mesg, &an_int);
c1a2a4756   Al Viro   [PATCH] sanitize ...
538
539
  		if (err)
  			goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
543
  		exp.ex_anon_gid= an_int;
  
  		/* fsid */
  		err = get_int(&mesg, &an_int);
c1a2a4756   Al Viro   [PATCH] sanitize ...
544
545
  		if (err)
  			goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
  		exp.ex_fsid = an_int;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
  		while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
  			if (strcmp(buf, "fsloc") == 0)
  				err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
  			else if (strcmp(buf, "uuid") == 0) {
  				/* expect a 16 byte uuid encoded as \xXXXX... */
  				len = qword_get(&mesg, buf, PAGE_SIZE);
  				if (len != 16)
  					err  = -EINVAL;
  				else {
  					exp.ex_uuid =
  						kmemdup(buf, 16, GFP_KERNEL);
  					if (exp.ex_uuid == NULL)
  						err = -ENOMEM;
  				}
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
561
562
563
  			} else if (strcmp(buf, "secinfo") == 0)
  				err = secinfo_parse(&mesg, buf, &exp);
  			else
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
564
565
566
567
568
569
  				/* 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 ...
570
  				goto out4;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
571
  		}
933469190   Manoj Naik   [PATCH] knfsd: nf...
572

774b14782   J. Bruce Fields   nfsd: make V4ROOT...
573
  		err = check_export(exp.ex_path.dentry->d_inode, &exp.ex_flags,
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
574
  				   exp.ex_uuid);
c1a2a4756   Al Viro   [PATCH] sanitize ...
575
576
  		if (err)
  			goto out4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
  	}
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
578
  	expp = svc_export_lookup(&exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
  	if (expp)
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
580
581
582
  		expp = svc_export_update(&exp, expp);
  	else
  		err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  	cache_flush();
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
584
585
586
587
  	if (expp == NULL)
  		err = -ENOMEM;
  	else
  		exp_put(expp);
c1a2a4756   Al Viro   [PATCH] sanitize ...
588
  out4:
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
589
590
  	nfsd4_fslocs_free(&exp.ex_fslocs);
  	kfree(exp.ex_uuid);
c1a2a4756   Al Viro   [PATCH] sanitize ...
591
  out3:
c1a2a4756   Al Viro   [PATCH] sanitize ...
592
593
594
595
  	path_put(&exp.ex_path);
  out1:
  	auth_domain_put(dom);
  out:
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
596
  	kfree(buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
  	return err;
  }
933469190   Manoj Naik   [PATCH] knfsd: nf...
599
600
  static void exp_flags(struct seq_file *m, int flag, int fsid,
  		uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
601
  static void show_secinfo(struct seq_file *m, struct svc_export *exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
605
606
607
608
609
610
611
612
613
614
  
  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_...
615
616
  	seq_path(m, &exp->ex_path, " \t
  \\");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
619
620
621
  	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...
622
  	    !test_bit(CACHE_NEGATIVE, &h->flags)) {
933469190   Manoj Naik   [PATCH] knfsd: nf...
623
624
  		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...
625
626
627
628
629
630
631
632
633
  		if (exp->ex_uuid) {
  			int i;
  			seq_puts(m, ",uuid=");
  			for (i=0; i<16; i++) {
  				if ((i&3) == 0 && i)
  					seq_putc(m, ':');
  				seq_printf(m, "%02x", exp->ex_uuid[i]);
  			}
  		}
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
634
  		show_secinfo(m, exp);
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
635
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
638
639
  	seq_puts(m, ")
  ");
  	return 0;
  }
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
640
  static int svc_export_match(struct cache_head *a, struct cache_head *b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
  {
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
642
643
644
  	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 &&
547754916   Jan Blunck   Use struct path i...
645
646
  		orig->ex_path.dentry == new->ex_path.dentry &&
  		orig->ex_path.mnt == new->ex_path.mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  }
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
648
649
  
  static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  {
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
651
652
  	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...
653
  	kref_get(&item->ex_client->ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  	new->ex_client = item->ex_client;
547754916   Jan Blunck   Use struct path i...
655
656
  	new->ex_path.dentry = dget(item->ex_path.dentry);
  	new->ex_path.mnt = mntget(item->ex_path.mnt);
933469190   Manoj Naik   [PATCH] knfsd: nf...
657
658
659
  	new->ex_fslocs.locations = NULL;
  	new->ex_fslocs.locations_count = 0;
  	new->ex_fslocs.migrated = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
  }
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
661
  static void export_update(struct cache_head *cnew, struct cache_head *citem)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  {
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
663
664
  	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...
665
  	int i;
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
666

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
669
670
  	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;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
671
672
  	new->ex_uuid = item->ex_uuid;
  	item->ex_uuid = NULL;
933469190   Manoj Naik   [PATCH] knfsd: nf...
673
674
675
676
677
678
  	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;
e677bfe4d   Andy Adamson   knfsd: nfsd4: par...
679
680
681
682
  	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
683
  }
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  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;
  }
  
  struct cache_detail svc_export_cache = {
  	.owner		= THIS_MODULE,
  	.hash_size	= EXPORT_HASHMAX,
  	.hash_table	= export_table,
  	.name		= "nfsd.export",
  	.cache_put	= svc_export_put,
bc74b4f5e   Trond Myklebust   SUNRPC: Allow the...
699
  	.cache_upcall	= svc_export_upcall,
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
700
701
702
703
704
705
706
  	.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 ...
707
708
  static int
  svc_export_hash(struct svc_export *exp)
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
709
  {
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
710
  	int hash;
61f8603d9   NeilBrown   nfsd: factor out ...
711

4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
712
  	hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
547754916   Jan Blunck   Use struct path i...
713
714
  	hash ^= hash_ptr(exp->ex_path.dentry, EXPORT_HASHBITS);
  	hash ^= hash_ptr(exp->ex_path.mnt, EXPORT_HASHBITS);
61f8603d9   NeilBrown   nfsd: factor out ...
715
716
717
718
719
720
721
722
  	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...
723
724
725
726
727
728
729
730
  
  	ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h,
  				 hash);
  	if (ch)
  		return container_of(ch, struct svc_export, h);
  	else
  		return NULL;
  }
74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
731
  static struct svc_export *
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
732
733
734
  svc_export_update(struct svc_export *new, struct svc_export *old)
  {
  	struct cache_head *ch;
61f8603d9   NeilBrown   nfsd: factor out ...
735
  	int hash = svc_export_hash(old);
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
736
737
738
739
740
741
742
743
744
  
  	ch = sunrpc_cache_update(&svc_export_cache, &new->h,
  				 &old->h,
  				 hash);
  	if (ch)
  		return container_of(ch, struct svc_export, h);
  	else
  		return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745

74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
746
  static struct svc_expkey *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
750
751
752
  exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
  {
  	struct svc_expkey key, *ek;
  	int err;
  	
  	if (!clp)
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
753
  		return ERR_PTR(-ENOENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
756
757
  
  	key.ek_client = clp;
  	key.ek_fsidtype = fsid_type;
  	memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
758
  	ek = svc_expkey_lookup(&key);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
759
760
761
762
763
  	if (ek == NULL)
  		return ERR_PTR(-ENOMEM);
  	err = cache_check(&svc_expkey_cache, &ek->h, reqp);
  	if (err)
  		return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
  	return ek;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766

55430e2ec   Al Viro   nfsd struct path ...
767
768
  static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
  				     struct cache_req *reqp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
770
  {
  	struct svc_export *exp, key;
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
771
  	int err;
e83aece3a   Jan Blunck   Use struct path i...
772

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  	if (!clp)
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
774
  		return ERR_PTR(-ENOENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
  
  	key.ex_client = clp;
55430e2ec   Al Viro   nfsd struct path ...
777
  	key.ex_path = *path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778

4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
779
  	exp = svc_export_lookup(&key);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
780
781
782
783
784
  	if (exp == NULL)
  		return ERR_PTR(-ENOMEM);
  	err = cache_check(&svc_export_cache, &exp->h, reqp);
  	if (err)
  		return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
788
789
790
  	return exp;
  }
  
  /*
   * Find the export entry for a given dentry.
   */
5bf3bd2b5   Al Viro   switch exp_parent...
791
  static struct svc_export *exp_parent(svc_client *clp, struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
  {
5bf3bd2b5   Al Viro   switch exp_parent...
793
794
795
796
797
798
799
800
  	struct dentry *saved = dget(path->dentry);
  	svc_export *exp = exp_get_by_name(clp, path, NULL);
  
  	while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
  		struct dentry *parent = dget_parent(path->dentry);
  		dput(path->dentry);
  		path->dentry = parent;
  		exp = exp_get_by_name(clp, path, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
  	}
5bf3bd2b5   Al Viro   switch exp_parent...
802
803
  	dput(path->dentry);
  	path->dentry = saved;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
  	return exp;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
809
810
811
812
813
  
  /*
   * 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
a63bb9966   Al Viro   [PATCH] switch nf...
814
  exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
  {
  	struct svc_export	*exp;
a63bb9966   Al Viro   [PATCH] switch nf...
817
  	struct path		path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
820
821
822
823
  	struct inode		*inode;
  	struct svc_fh		fh;
  	int			err;
  
  	err = -EPERM;
  	/* NB: we probably ought to check that it's NUL-terminated */
a63bb9966   Al Viro   [PATCH] switch nf...
824
825
  	if (kern_path(name, 0, &path)) {
  		printk("nfsd: exp_rootfh path not found %s", name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
827
  		return err;
  	}
a63bb9966   Al Viro   [PATCH] switch nf...
828
  	inode = path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
  
  	dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)
  ",
a63bb9966   Al Viro   [PATCH] switch nf...
832
  		 name, path.dentry, clp->name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
  		 inode->i_sb->s_id, inode->i_ino);
5bf3bd2b5   Al Viro   switch exp_parent...
834
  	exp = exp_parent(clp, &path);
4b41bd85d   J.Bruce Fields   [PATCH] knfsd: nf...
835
836
837
838
  	if (IS_ERR(exp)) {
  		err = PTR_ERR(exp);
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
840
841
842
843
  
  	/*
  	 * fh must be initialized before calling fh_compose
  	 */
  	fh_init(&fh, maxsize);
a63bb9966   Al Viro   [PATCH] switch nf...
844
  	if (fh_compose(&fh, exp, path.dentry, NULL))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
848
849
850
851
  		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...
852
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
  	return err;
  }
cce76f9b9   Adrian Bunk   fs/nfsd/export.c:...
855
856
  static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type,
  				   u32 *fsidv, struct cache_req *reqp)
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
857
858
859
  {
  	struct svc_export *exp;
  	struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
860
  	if (IS_ERR(ek))
e231c2ee6   David Howells   Convert ERR_PTR(P...
861
  		return ERR_CAST(ek);
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
862

55430e2ec   Al Viro   nfsd struct path ...
863
  	exp = exp_get_by_name(clp, &ek->ek_path, reqp);
baab935ff   NeilBrown   [PATCH] knfsd: Co...
864
  	cache_put(&ek->h, &svc_expkey_cache);
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
865

2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
866
  	if (IS_ERR(exp))
e231c2ee6   David Howells   Convert ERR_PTR(P...
867
  		return ERR_CAST(exp);
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
868
869
  	return exp;
  }
32c1eb0cd   Andy Adamson   knfsd: nfsd4: ret...
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
  __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;
  }
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
891
  /*
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
892
893
894
895
   * 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...
896
897
898
899
900
   * 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...
901
  rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
902
  {
9a25b96c1   J. Bruce Fields   nfsd: return erro...
903
  	struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
904
905
906
  
  	if (rqstp->rq_client == NULL)
  		goto gss;
3ab4d8b12   J. Bruce Fields   knfsd: nfsd: set ...
907

2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
908
  	/* First try the auth_unix client: */
91c9fa8f7   Al Viro   switch rqst_exp_g...
909
  	exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
910
911
912
913
914
915
916
917
918
919
920
  	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;
91c9fa8f7   Al Viro   switch rqst_exp_g...
921
  	gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
922
923
  	if (PTR_ERR(gssexp) == -ENOENT)
  		return exp;
9a25b96c1   J. Bruce Fields   nfsd: return erro...
924
  	if (!IS_ERR(exp))
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
925
926
  		exp_put(exp);
  	return gssexp;
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
927
928
929
930
931
  }
  
  struct svc_export *
  rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
  {
9a25b96c1   J. Bruce Fields   nfsd: return erro...
932
  	struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
933
934
935
  
  	if (rqstp->rq_client == NULL)
  		goto gss;
3ab4d8b12   J. Bruce Fields   knfsd: nfsd: set ...
936

2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
  	/* 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;
9a25b96c1   J. Bruce Fields   nfsd: return erro...
954
  	if (!IS_ERR(exp))
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
955
956
  		exp_put(exp);
  	return gssexp;
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
957
958
959
  }
  
  struct svc_export *
e64c390ca   Al Viro   switch rqst_exp_p...
960
  rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
961
  {
e64c390ca   Al Viro   switch rqst_exp_p...
962
963
  	struct dentry *saved = dget(path->dentry);
  	struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
964

e64c390ca   Al Viro   switch rqst_exp_p...
965
966
967
968
969
  	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 ...
970
  	}
e64c390ca   Al Viro   switch rqst_exp_p...
971
972
  	dput(path->dentry);
  	path->dentry = saved;
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
973
  	return exp;
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
974
  }
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
975

ed748aacb   Trond Myklebust   NFSD: Cleanup for...
976
  struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp)
f39bde24b   J. Bruce Fields   nfsd4: fix error ...
977
  {
f39bde24b   J. Bruce Fields   nfsd4: fix error ...
978
979
980
  	u32 fsidv[2];
  
  	mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
260c64d23   J. Bruce Fields   Revert "nfsd4: fi...
981
  	return rqst_exp_find(rqstp, FSID_NUM, fsidv);
f39bde24b   J. Bruce Fields   nfsd4: fix error ...
982
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
984
985
986
987
  /*
   * 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...
988
  __be32
df547efb0   J. Bruce Fields   knfsd: nfsd4: sim...
989
  exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
  {
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
991
  	struct svc_export *exp;
c7afef1f9   Al Viro   [PATCH] nfsd: mis...
992
  	__be32 rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
993

ed748aacb   Trond Myklebust   NFSD: Cleanup for...
994
  	exp = rqst_find_fsidzero_export(rqstp);
6899320c2   J.Bruce Fields   [PATCH] knfsd: nf...
995
996
  	if (IS_ERR(exp))
  		return nfserrno(PTR_ERR(exp));
547754916   Jan Blunck   Use struct path i...
997
  	rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
d0ebd9c0e   J.Bruce Fields   [PATCH] knfsd: nf...
998
  	exp_put(exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
1001
1002
1003
1004
  	return rv;
  }
  
  /* Iterator */
  
  static void *e_start(struct seq_file *m, loff_t *pos)
896440d56   Josh Triplett   [PATCH] nfsd: add...
1005
  	__acquires(svc_export_cache.hash_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
1007
1008
1009
1010
  {
  	loff_t n = *pos;
  	unsigned hash, export;
  	struct cache_head *ch;
  	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011
1012
  	read_lock(&svc_export_cache.hash_lock);
  	if (!n--)
bc6f02e51   Greg Banks   [PATCH] knfsd: Us...
1013
  		return SEQ_START_TOKEN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
  	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);
bc6f02e51   Greg Banks   [PATCH] knfsd: Us...
1036
  	if (p == SEQ_START_TOKEN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
  		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)
896440d56   Josh Triplett   [PATCH] nfsd: add...
1057
  	__releases(svc_export_cache.hash_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
1059
  {
  	read_unlock(&svc_export_cache.hash_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
  }
  
  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", ""}},
eb4c86c6a   Steve Dickson   nfsd: introduce e...
1076
  	{ NFSEXP_V4ROOT, {"v4root", ""}},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
1078
  	{ 0, {"", ""}}
  };
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1079
  static void show_expflags(struct seq_file *m, int flags, int mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1080
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
  	struct flags *flg;
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1082
  	int state, first = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083
1084
  
  	for (flg = expflags; flg->flag; flg++) {
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1085
1086
1087
  		if (flg->flag & ~mask)
  			continue;
  		state = (flg->flag & flags) ? 0 : 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
1090
  		if (*flg->name[state])
  			seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
  	}
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1091
  }
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
1092
1093
1094
1095
1096
  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...
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
  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...
1117
1118
1119
1120
  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...
1121
  	int flags;
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
1122
1123
1124
  
  	if (exp->ex_nflavors == 0)
  		return;
74ec1e126   J. Bruce Fields   nfsd: fix /proc/n...
1125
1126
1127
1128
1129
1130
1131
  	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...
1132
  	}
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
1133
  }
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1134
1135
1136
1137
  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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
  	if (flag & NFSEXP_FSID)
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1139
  		seq_printf(m, ",fsid=%d", fsid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
  	if (anonu != (uid_t)-2 && anonu != (0x10000-2))
3e63516c8   J. Bruce Fields   knfsd: fix typo i...
1141
  		seq_printf(m, ",anonuid=%u", anonu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
  	if (anong != (gid_t)-2 && anong != (0x10000-2))
3e63516c8   J. Bruce Fields   knfsd: fix typo i...
1143
  		seq_printf(m, ",anongid=%u", anong);
933469190   Manoj Naik   [PATCH] knfsd: nf...
1144
1145
1146
  	if (fsloc && fsloc->locations_count > 0) {
  		char *loctype = (fsloc->migrated) ? "refer" : "replicas";
  		int i;
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1147
  		seq_printf(m, ",%s=", loctype);
933469190   Manoj Naik   [PATCH] knfsd: nf...
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
  		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
1162
1163
1164
1165
1166
1167
  }
  
  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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168

bc6f02e51   Greg Banks   [PATCH] knfsd: Us...
1169
  	if (p == SEQ_START_TOKEN) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
1172
1173
1174
1175
  		seq_puts(m, "# Version 1.1
  ");
  		seq_puts(m, "# Path Client(Flags) # IPs
  ");
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1176
1177
1178
  	cache_get(&exp->h);
  	if (cache_check(&svc_export_cache, &exp->h, NULL))
  		return 0;
baab935ff   NeilBrown   [PATCH] knfsd: Co...
1179
  	cache_put(&exp->h, &svc_export_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
1181
  	return svc_export_show(m, &svc_export_cache, cp);
  }
88e9d34c7   James Morris   seq_file: constif...
1182
  const struct seq_operations nfs_exports_op = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1183
1184
1185
1186
1187
  	.start	= e_start,
  	.next	= e_next,
  	.stop	= e_stop,
  	.show	= e_show,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1188
1189
1190
1191
  
  /*
   * Initialize the exports module.
   */
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1192
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
1194
  nfsd_export_init(void)
  {
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1195
  	int rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
1197
  	dprintk("nfsd: initializing export module.
  ");
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1198
1199
1200
1201
1202
1203
1204
  	rv = cache_register(&svc_export_cache);
  	if (rv)
  		return rv;
  	rv = cache_register(&svc_expkey_cache);
  	if (rv)
  		cache_unregister(&svc_export_cache);
  	return rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1205
1206
1207
1208
1209
1210
1211
1212
1213
  
  }
  
  /*
   * Flush exports table - called when last nfsd thread is killed
   */
  void
  nfsd_export_flush(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
1215
  	cache_purge(&svc_expkey_cache);
  	cache_purge(&svc_export_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
  }
  
  /*
   * Shutdown the exports module.
   */
  void
  nfsd_export_shutdown(void)
  {
  
  	dprintk("nfsd: shutting down export module.
  ");
df95a9d4f   J. Bruce Fields   knfsd: cache unre...
1227
1228
  	cache_unregister(&svc_expkey_cache);
  	cache_unregister(&svc_export_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
  	svcauth_unix_purge();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1230
1231
1232
  	dprintk("nfsd: export shutdown complete.
  ");
  }