Blame view

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include <linux/nfsd/syscall.h>
f15364bd4   Aurélien Charbon   IPv6 support for ...
20
  #include <net/ipv6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21

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

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

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

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

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

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

b009a873d   J.Bruce Fields   [PATCH] knfsd: nf...
522
  	err = -ENOMEM;
c1a2a4756   Al Viro   [PATCH] sanitize ...
523
  	exp.ex_pathname = kstrdup(buf, GFP_KERNEL);
547754916   Jan Blunck   Use struct path i...
524
  	if (!exp.ex_pathname)
c1a2a4756   Al Viro   [PATCH] sanitize ...
525
  		goto out2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
529
530
  
  	/* expiry */
  	err = -EINVAL;
  	exp.h.expiry_time = get_expiry(&mesg);
  	if (exp.h.expiry_time == 0)
c1a2a4756   Al Viro   [PATCH] sanitize ...
531
  		goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
534
  
  	/* flags */
  	err = get_int(&mesg, &an_int);
4a4b88317   J. Bruce Fields   knfsd: eliminate ...
535
536
  	if (err == -ENOENT) {
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  		set_bit(CACHE_NEGATIVE, &exp.h.flags);
4a4b88317   J. Bruce Fields   knfsd: eliminate ...
538
  	} else {
c1a2a4756   Al Viro   [PATCH] sanitize ...
539
540
  		if (err || an_int < 0)
  			goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
544
  		exp.ex_flags= an_int;
  	
  		/* anon uid */
  		err = get_int(&mesg, &an_int);
c1a2a4756   Al Viro   [PATCH] sanitize ...
545
546
  		if (err)
  			goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
549
550
  		exp.ex_anon_uid= an_int;
  
  		/* anon gid */
  		err = get_int(&mesg, &an_int);
c1a2a4756   Al Viro   [PATCH] sanitize ...
551
552
  		if (err)
  			goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
555
556
  		exp.ex_anon_gid= an_int;
  
  		/* fsid */
  		err = get_int(&mesg, &an_int);
c1a2a4756   Al Viro   [PATCH] sanitize ...
557
558
  		if (err)
  			goto out3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  		exp.ex_fsid = an_int;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
560
561
562
563
564
565
566
567
568
569
570
571
572
573
  		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...
574
575
576
  			} else if (strcmp(buf, "secinfo") == 0)
  				err = secinfo_parse(&mesg, buf, &exp);
  			else
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
577
578
579
580
581
582
  				/* 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 ...
583
  				goto out4;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
584
  		}
933469190   Manoj Naik   [PATCH] knfsd: nf...
585

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
686
  	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...
687
688
  	new->ex_uuid = item->ex_uuid;
  	item->ex_uuid = NULL;
547754916   Jan Blunck   Use struct path i...
689
690
  	new->ex_pathname = item->ex_pathname;
  	item->ex_pathname = NULL;
933469190   Manoj Naik   [PATCH] knfsd: nf...
691
692
693
694
695
696
  	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...
697
698
699
700
  	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
701
  }
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
  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...
717
  	.cache_upcall	= svc_export_upcall,
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
718
719
720
721
722
723
724
  	.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 ...
725
726
  static int
  svc_export_hash(struct svc_export *exp)
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
727
  {
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
728
  	int hash;
61f8603d9   NeilBrown   nfsd: factor out ...
729

4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
730
  	hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
547754916   Jan Blunck   Use struct path i...
731
732
  	hash ^= hash_ptr(exp->ex_path.dentry, EXPORT_HASHBITS);
  	hash ^= hash_ptr(exp->ex_path.mnt, EXPORT_HASHBITS);
61f8603d9   NeilBrown   nfsd: factor out ...
733
734
735
736
737
738
739
740
  	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...
741
742
743
744
745
746
747
748
  
  	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...
749
  static struct svc_export *
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
750
751
752
  svc_export_update(struct svc_export *new, struct svc_export *old)
  {
  	struct cache_head *ch;
61f8603d9   NeilBrown   nfsd: factor out ...
753
  	int hash = svc_export_hash(old);
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
754
755
756
757
758
759
760
761
762
  
  	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
763

74cae61ab   Adrian Bunk   [PATCH] fs/nfsd/e...
764
  static struct svc_expkey *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
767
768
769
770
  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...
771
  		return ERR_PTR(-ENOENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
774
775
  
  	key.ek_client = clp;
  	key.ek_fsidtype = fsid_type;
  	memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
776
  	ek = svc_expkey_lookup(&key);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
777
778
779
780
781
  	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
782
783
784
785
786
787
788
789
790
791
792
  	return ek;
  }
  
  static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
  		       struct svc_export *exp)
  {
  	struct svc_expkey key, *ek;
  
  	key.ek_client = clp;
  	key.ek_fsidtype = fsid_type;
  	memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
e83aece3a   Jan Blunck   Use struct path i...
793
  	key.ek_path = exp->ex_path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
  	key.h.expiry_time = NEVER;
  	key.h.flags = 0;
8d270f7f4   NeilBrown   [PATCH] knfsd: Us...
796
797
798
  	ek = svc_expkey_lookup(&key);
  	if (ek)
  		ek = svc_expkey_update(&key,ek);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
  	if (ek) {
baab935ff   NeilBrown   [PATCH] knfsd: Co...
800
  		cache_put(&ek->h, &svc_expkey_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
802
803
804
805
806
807
808
809
810
811
812
813
814
  		return 0;
  	}
  	return -ENOMEM;
  }
  
  /*
   * Find the client's export entry matching xdev/xino.
   */
  static inline struct svc_expkey *
  exp_get_key(svc_client *clp, dev_t dev, ino_t ino)
  {
  	u32 fsidv[3];
  	
  	if (old_valid_dev(dev)) {
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
815
816
  		mk_fsid(FSID_DEV, fsidv, dev, ino, 0, NULL);
  		return exp_find_key(clp, FSID_DEV, fsidv, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
  	}
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
818
819
  	mk_fsid(FSID_ENCODE_DEV, fsidv, dev, ino, 0, NULL);
  	return exp_find_key(clp, FSID_ENCODE_DEV, fsidv, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
822
823
824
825
826
827
828
  }
  
  /*
   * Find the client's export entry matching fsid
   */
  static inline struct svc_expkey *
  exp_get_fsid_key(svc_client *clp, int fsid)
  {
  	u32 fsidv[2];
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
829
  	mk_fsid(FSID_NUM, fsidv, 0, 0, fsid, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830

af6a4e280   NeilBrown   [PATCH] knfsd: ad...
831
  	return exp_find_key(clp, FSID_NUM, fsidv, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
  }
55430e2ec   Al Viro   nfsd struct path ...
833
834
  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
835
836
  {
  	struct svc_export *exp, key;
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
837
  	int err;
e83aece3a   Jan Blunck   Use struct path i...
838

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  	if (!clp)
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
840
  		return ERR_PTR(-ENOENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
  
  	key.ex_client = clp;
55430e2ec   Al Viro   nfsd struct path ...
843
  	key.ex_path = *path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844

4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
845
  	exp = svc_export_lookup(&key);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
846
847
848
849
850
  	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
851
852
853
854
855
856
  	return exp;
  }
  
  /*
   * Find the export entry for a given dentry.
   */
5bf3bd2b5   Al Viro   switch exp_parent...
857
  static struct svc_export *exp_parent(svc_client *clp, struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
  {
5bf3bd2b5   Al Viro   switch exp_parent...
859
860
861
862
863
864
865
866
  	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
867
  	}
5bf3bd2b5   Al Viro   switch exp_parent...
868
869
  	dput(path->dentry);
  	path->dentry = saved;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
  	return exp;
  }
  
  /*
   * Hashtable locking. Write locks are placed only by user processes
   * wanting to modify export information.
   * Write locking only done in this file.  Read locking
   * needed externally.
   */
  
  static DECLARE_RWSEM(hash_sem);
  
  void
  exp_readlock(void)
  {
  	down_read(&hash_sem);
  }
  
  static inline void
  exp_writelock(void)
  {
  	down_write(&hash_sem);
  }
  
  void
  exp_readunlock(void)
  {
  	up_read(&hash_sem);
  }
  
  static inline void
  exp_writeunlock(void)
  {
  	up_write(&hash_sem);
  }
  
  static void exp_fsid_unhash(struct svc_export *exp)
  {
  	struct svc_expkey *ek;
  
  	if ((exp->ex_flags & NFSEXP_FSID) == 0)
  		return;
  
  	ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
914
  	if (!IS_ERR(ek)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
  		ek->h.expiry_time = get_seconds()-1;
baab935ff   NeilBrown   [PATCH] knfsd: Co...
916
  		cache_put(&ek->h, &svc_expkey_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
922
923
924
925
926
  	}
  	svc_expkey_cache.nextcheck = get_seconds();
  }
  
  static int exp_fsid_hash(svc_client *clp, struct svc_export *exp)
  {
  	u32 fsid[2];
   
  	if ((exp->ex_flags & NFSEXP_FSID) == 0)
  		return 0;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
927
928
  	mk_fsid(FSID_NUM, fsid, 0, 0, exp->ex_fsid, NULL);
  	return exp_set_key(clp, FSID_NUM, fsid, exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
931
932
933
  }
  
  static int exp_hash(struct auth_domain *clp, struct svc_export *exp)
  {
  	u32 fsid[2];
547754916   Jan Blunck   Use struct path i...
934
  	struct inode *inode = exp->ex_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
936
937
  	dev_t dev = inode->i_sb->s_dev;
  
  	if (old_valid_dev(dev)) {
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
938
939
  		mk_fsid(FSID_DEV, fsid, dev, inode->i_ino, 0, NULL);
  		return exp_set_key(clp, FSID_DEV, fsid, exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
  	}
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
941
942
  	mk_fsid(FSID_ENCODE_DEV, fsid, dev, inode->i_ino, 0, NULL);
  	return exp_set_key(clp, FSID_ENCODE_DEV, fsid, exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
945
946
947
  }
  
  static void exp_unhash(struct svc_export *exp)
  {
  	struct svc_expkey *ek;
547754916   Jan Blunck   Use struct path i...
948
  	struct inode *inode = exp->ex_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
  
  	ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
951
  	if (!IS_ERR(ek)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
  		ek->h.expiry_time = get_seconds()-1;
baab935ff   NeilBrown   [PATCH] knfsd: Co...
953
  		cache_put(&ek->h, &svc_expkey_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
956
957
958
959
960
961
962
963
964
965
966
967
  	}
  	svc_expkey_cache.nextcheck = get_seconds();
  }
  	
  /*
   * Export a file system.
   */
  int
  exp_export(struct nfsctl_export *nxp)
  {
  	svc_client	*clp;
  	struct svc_export	*exp = NULL;
  	struct svc_export	new;
  	struct svc_expkey	*fsid_key = NULL;
a63bb9966   Al Viro   [PATCH] switch nf...
968
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
  	int		err;
  
  	/* Consistency check */
  	err = -EINVAL;
  	if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
  	    !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
  		goto out;
  
  	dprintk("exp_export called for %s:%s (%x/%ld fl %x).
  ",
  			nxp->ex_client, nxp->ex_path,
  			(unsigned)nxp->ex_dev, (long)nxp->ex_ino,
  			nxp->ex_flags);
  
  	/* Try to lock the export table for update */
  	exp_writelock();
  
  	/* Look up client info */
  	if (!(clp = auth_domain_find(nxp->ex_client)))
  		goto out_unlock;
  
  
  	/* Look up the dentry */
a63bb9966   Al Viro   [PATCH] switch nf...
992
  	err = kern_path(nxp->ex_path, 0, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
993
  	if (err)
53e6d8d18   Julia Lawall   fs/nfsd/export.c:...
994
  		goto out_put_clp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  	err = -EINVAL;
55430e2ec   Al Viro   nfsd struct path ...
996
  	exp = exp_get_by_name(clp, &path, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997

f988443a8   NeilBrown   [PATCH] knfsd: Fi...
998
  	memset(&new, 0, sizeof(new));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
  	/* must make sure there won't be an ex_fsid clash */
  	if ((nxp->ex_flags & NFSEXP_FSID) &&
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
1001
  	    (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
e83aece3a   Jan Blunck   Use struct path i...
1002
  	    fsid_key->ek_path.mnt &&
a63bb9966   Al Viro   [PATCH] switch nf...
1003
1004
  	    (fsid_key->ek_path.mnt != path.mnt ||
  	     fsid_key->ek_path.dentry != path.dentry))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
  		goto finish;
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
1006
  	if (!IS_ERR(exp)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  		/* just a flags/id/fsid update */
  
  		exp_fsid_unhash(exp);
  		exp->ex_flags    = nxp->ex_flags;
  		exp->ex_anon_uid = nxp->ex_anon_uid;
  		exp->ex_anon_gid = nxp->ex_anon_gid;
  		exp->ex_fsid     = nxp->ex_dev;
  
  		err = exp_fsid_hash(clp, exp);
  		goto finish;
  	}
774b14782   J. Bruce Fields   nfsd: make V4ROOT...
1018
  	err = check_export(path.dentry->d_inode, &nxp->ex_flags, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
1020
1021
1022
1023
1024
1025
1026
1027
  	if (err) goto finish;
  
  	err = -ENOMEM;
  
  	dprintk("nfsd: creating export entry %p for client %p
  ", exp, clp);
  
  	new.h.expiry_time = NEVER;
  	new.h.flags = 0;
547754916   Jan Blunck   Use struct path i...
1028
1029
  	new.ex_pathname = kstrdup(nxp->ex_path, GFP_KERNEL);
  	if (!new.ex_pathname)
f988443a8   NeilBrown   [PATCH] knfsd: Fi...
1030
  		goto finish;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
  	new.ex_client = clp;
a63bb9966   Al Viro   [PATCH] switch nf...
1032
  	new.ex_path = path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
1035
1036
  	new.ex_flags = nxp->ex_flags;
  	new.ex_anon_uid = nxp->ex_anon_uid;
  	new.ex_anon_gid = nxp->ex_anon_gid;
  	new.ex_fsid = nxp->ex_dev;
4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
1037
1038
1039
  	exp = svc_export_lookup(&new);
  	if (exp)
  		exp = svc_export_update(&new, exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040

4f7774c3a   NeilBrown   [PATCH] knfsd: Us...
1041
  	if (!exp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
  		goto finish;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
1044
1045
1046
1047
  	if (exp_hash(clp, exp) ||
  	    exp_fsid_hash(clp, exp)) {
  		/* failed to create at least one index */
  		exp_do_unexport(exp);
  		cache_flush();
f988443a8   NeilBrown   [PATCH] knfsd: Fi...
1048
1049
  	} else
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
  finish:
547754916   Jan Blunck   Use struct path i...
1051
  	kfree(new.ex_pathname);
d03859a4a   Dan Carpenter   nfsd: potential E...
1052
  	if (!IS_ERR_OR_NULL(exp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
  		exp_put(exp);
d03859a4a   Dan Carpenter   nfsd: potential E...
1054
  	if (!IS_ERR_OR_NULL(fsid_key))
baab935ff   NeilBrown   [PATCH] knfsd: Co...
1055
  		cache_put(&fsid_key->h, &svc_expkey_cache);
a63bb9966   Al Viro   [PATCH] switch nf...
1056
  	path_put(&path);
53e6d8d18   Julia Lawall   fs/nfsd/export.c:...
1057
1058
  out_put_clp:
  	auth_domain_put(clp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
  out_unlock:
  	exp_writeunlock();
  out:
  	return err;
  }
  
  /*
   * Unexport a file system. The export entry has already
   * been removed from the client's list of exported fs's.
   */
  static void
  exp_do_unexport(svc_export *unexp)
  {
  	unexp->h.expiry_time = get_seconds()-1;
  	svc_export_cache.nextcheck = get_seconds();
  	exp_unhash(unexp);
  	exp_fsid_unhash(unexp);
  }
  
  
  /*
   * unexport syscall.
   */
  int
  exp_unexport(struct nfsctl_export *nxp)
  {
  	struct auth_domain *dom;
  	svc_export *exp;
a63bb9966   Al Viro   [PATCH] switch nf...
1087
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
  	int		err;
  
  	/* Consistency check */
  	if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
  	    !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
  		return -EINVAL;
  
  	exp_writelock();
  
  	err = -EINVAL;
  	dom = auth_domain_find(nxp->ex_client);
  	if (!dom) {
  		dprintk("nfsd: unexport couldn't find %s
  ", nxp->ex_client);
  		goto out_unlock;
  	}
a63bb9966   Al Viro   [PATCH] switch nf...
1104
  	err = kern_path(nxp->ex_path, 0, &path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
1106
1107
1108
  	if (err)
  		goto out_domain;
  
  	err = -EINVAL;
55430e2ec   Al Viro   nfsd struct path ...
1109
  	exp = exp_get_by_name(dom, &path, NULL);
a63bb9966   Al Viro   [PATCH] switch nf...
1110
  	path_put(&path);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
1111
  	if (IS_ERR(exp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  		goto out_domain;
  
  	exp_do_unexport(exp);
  	exp_put(exp);
  	err = 0;
  
  out_domain:
  	auth_domain_put(dom);
  	cache_flush();
  out_unlock:
  	exp_writeunlock();
  	return err;
  }
  
  /*
   * Obtain the root fh on behalf of a client.
   * This could be done in user space, but I feel that it adds some safety
   * since its harder to fool a kernel module than a user space program.
   */
  int
a63bb9966   Al Viro   [PATCH] switch nf...
1132
  exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
1134
  {
  	struct svc_export	*exp;
a63bb9966   Al Viro   [PATCH] switch nf...
1135
  	struct path		path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
1137
1138
1139
1140
1141
  	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...
1142
1143
  	if (kern_path(name, 0, &path)) {
  		printk("nfsd: exp_rootfh path not found %s", name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1144
1145
  		return err;
  	}
a63bb9966   Al Viro   [PATCH] switch nf...
1146
  	inode = path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
1148
1149
  
  	dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)
  ",
a63bb9966   Al Viro   [PATCH] switch nf...
1150
  		 name, path.dentry, clp->name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
  		 inode->i_sb->s_id, inode->i_ino);
5bf3bd2b5   Al Viro   switch exp_parent...
1152
  	exp = exp_parent(clp, &path);
4b41bd85d   J.Bruce Fields   [PATCH] knfsd: nf...
1153
1154
1155
1156
  	if (IS_ERR(exp)) {
  		err = PTR_ERR(exp);
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
1158
1159
1160
1161
  
  	/*
  	 * fh must be initialized before calling fh_compose
  	 */
  	fh_init(&fh, maxsize);
a63bb9966   Al Viro   [PATCH] switch nf...
1162
  	if (fh_compose(&fh, exp, path.dentry, NULL))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
1164
1165
1166
1167
1168
1169
  		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...
1170
  	path_put(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
1172
  	return err;
  }
cce76f9b9   Adrian Bunk   fs/nfsd/export.c:...
1173
1174
  static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type,
  				   u32 *fsidv, struct cache_req *reqp)
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
1175
1176
1177
  {
  	struct svc_export *exp;
  	struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
1178
  	if (IS_ERR(ek))
e231c2ee6   David Howells   Convert ERR_PTR(P...
1179
  		return ERR_CAST(ek);
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
1180

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

2d3bb2520   J. Bruce Fields   knfsd: nfsd: make...
1184
  	if (IS_ERR(exp))
e231c2ee6   David Howells   Convert ERR_PTR(P...
1185
  		return ERR_CAST(exp);
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
1186
1187
  	return exp;
  }
32c1eb0cd   Andy Adamson   knfsd: nfsd4: ret...
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
  __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...
1209
  /*
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1210
1211
1212
1213
   * 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...
1214
1215
1216
1217
1218
   * 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...
1219
  rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
1220
  {
9a25b96c1   J. Bruce Fields   nfsd: return erro...
1221
  	struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1222
1223
1224
  
  	if (rqstp->rq_client == NULL)
  		goto gss;
3ab4d8b12   J. Bruce Fields   knfsd: nfsd: set ...
1225

2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1226
  	/* First try the auth_unix client: */
91c9fa8f7   Al Viro   switch rqst_exp_g...
1227
  	exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
  	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...
1239
  	gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1240
1241
  	if (PTR_ERR(gssexp) == -ENOENT)
  		return exp;
9a25b96c1   J. Bruce Fields   nfsd: return erro...
1242
  	if (!IS_ERR(exp))
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1243
1244
  		exp_put(exp);
  	return gssexp;
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
1245
1246
1247
1248
1249
  }
  
  struct svc_export *
  rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
  {
9a25b96c1   J. Bruce Fields   nfsd: return erro...
1250
  	struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1251
1252
1253
  
  	if (rqstp->rq_client == NULL)
  		goto gss;
3ab4d8b12   J. Bruce Fields   knfsd: nfsd: set ...
1254

2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
  	/* 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...
1272
  	if (!IS_ERR(exp))
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1273
1274
  		exp_put(exp);
  	return gssexp;
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
1275
1276
1277
  }
  
  struct svc_export *
e64c390ca   Al Viro   switch rqst_exp_p...
1278
  rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
1279
  {
e64c390ca   Al Viro   switch rqst_exp_p...
1280
1281
  	struct dentry *saved = dget(path->dentry);
  	struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1282

e64c390ca   Al Viro   switch rqst_exp_p...
1283
1284
1285
1286
1287
  	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 ...
1288
  	}
e64c390ca   Al Viro   switch rqst_exp_p...
1289
1290
  	dput(path->dentry);
  	path->dentry = saved;
2ea2209f0   J. Bruce Fields   knfsd: nfsd: use ...
1291
  	return exp;
0989a7889   J. Bruce Fields   knfsd: nfsd: prov...
1292
  }
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
1293

f39bde24b   J. Bruce Fields   nfsd4: fix error ...
1294
1295
  static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp)
  {
f39bde24b   J. Bruce Fields   nfsd4: fix error ...
1296
1297
1298
  	u32 fsidv[2];
  
  	mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
260c64d23   J. Bruce Fields   Revert "nfsd4: fi...
1299
  	return rqst_exp_find(rqstp, FSID_NUM, fsidv);
f39bde24b   J. Bruce Fields   nfsd4: fix error ...
1300
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301
1302
1303
1304
1305
  /*
   * 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...
1306
  __be32
df547efb0   J. Bruce Fields   knfsd: nfsd4: sim...
1307
  exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
  {
eab7e2e64   NeilBrown   [PATCH] knfsd: Br...
1309
  	struct svc_export *exp;
c7afef1f9   Al Viro   [PATCH] nfsd: mis...
1310
  	__be32 rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1311

f39bde24b   J. Bruce Fields   nfsd4: fix error ...
1312
  	exp = find_fsidzero_export(rqstp);
6899320c2   J.Bruce Fields   [PATCH] knfsd: nf...
1313
1314
  	if (IS_ERR(exp))
  		return nfserrno(PTR_ERR(exp));
547754916   Jan Blunck   Use struct path i...
1315
  	rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
32c1eb0cd   Andy Adamson   knfsd: nfsd4: ret...
1316
1317
1318
  	if (rv)
  		goto out;
  	rv = check_nfsd_access(exp, rqstp);
2671a4bf3   Trond Myklebust   NFSd: Fix filehan...
1319
1320
  	if (rv)
  		fh_put(fhp);
32c1eb0cd   Andy Adamson   knfsd: nfsd4: ret...
1321
  out:
d0ebd9c0e   J.Bruce Fields   [PATCH] knfsd: nf...
1322
  	exp_put(exp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
1324
1325
1326
1327
1328
  	return rv;
  }
  
  /* Iterator */
  
  static void *e_start(struct seq_file *m, loff_t *pos)
896440d56   Josh Triplett   [PATCH] nfsd: add...
1329
  	__acquires(svc_export_cache.hash_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330
1331
1332
1333
1334
1335
1336
1337
  {
  	loff_t n = *pos;
  	unsigned hash, export;
  	struct cache_head *ch;
  	
  	exp_readlock();
  	read_lock(&svc_export_cache.hash_lock);
  	if (!n--)
bc6f02e51   Greg Banks   [PATCH] knfsd: Us...
1338
  		return SEQ_START_TOKEN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
  	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...
1361
  	if (p == SEQ_START_TOKEN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
  		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...
1382
  	__releases(svc_export_cache.hash_lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
  {
  	read_unlock(&svc_export_cache.hash_lock);
  	exp_readunlock();
  }
  
  static struct flags {
  	int flag;
  	char *name[2];
  } expflags[] = {
  	{ NFSEXP_READONLY, {"ro", "rw"}},
  	{ NFSEXP_INSECURE_PORT, {"insecure", ""}},
  	{ NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
  	{ NFSEXP_ALLSQUASH, {"all_squash", ""}},
  	{ NFSEXP_ASYNC, {"async", "sync"}},
  	{ NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
  	{ NFSEXP_NOHIDE, {"nohide", ""}},
  	{ NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
  	{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
  	{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
eb4c86c6a   Steve Dickson   nfsd: introduce e...
1402
  	{ NFSEXP_V4ROOT, {"v4root", ""}},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
1404
1405
1406
1407
  #ifdef MSNFS
  	{ NFSEXP_MSNFS, {"msnfs", ""}},
  #endif
  	{ 0, {"", ""}}
  };
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1408
  static void show_expflags(struct seq_file *m, int flags, int mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410
  	struct flags *flg;
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1411
  	int state, first = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
  
  	for (flg = expflags; flg->flag; flg++) {
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1414
1415
1416
  		if (flg->flag & ~mask)
  			continue;
  		state = (flg->flag & flags) ? 0 : 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1417
1418
1419
  		if (*flg->name[state])
  			seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
  	}
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1420
  }
91fe39d35   J. Bruce Fields   knfsd: nfsd: disp...
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
  static void show_secinfo_flags(struct seq_file *m, int flags)
  {
  	seq_printf(m, ",");
  	show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
  }
  
  static void show_secinfo(struct seq_file *m, struct svc_export *exp)
  {
  	struct exp_flavor_info *f;
  	struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
  	int lastflags = 0, first = 0;
  
  	if (exp->ex_nflavors == 0)
  		return;
  	for (f = exp->ex_flavors; f < end; f++) {
  		if (first || f->flags != lastflags) {
  			if (!first)
  				show_secinfo_flags(m, lastflags);
  			seq_printf(m, ",sec=%d", f->pseudoflavor);
  			lastflags = f->flags;
  		} else {
  			seq_printf(m, ":%d", f->pseudoflavor);
  		}
  	}
  	show_secinfo_flags(m, lastflags);
  }
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1447
1448
1449
1450
  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
1451
  	if (flag & NFSEXP_FSID)
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1452
  		seq_printf(m, ",fsid=%d", fsid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1453
  	if (anonu != (uid_t)-2 && anonu != (0x10000-2))
3e63516c8   J. Bruce Fields   knfsd: fix typo i...
1454
  		seq_printf(m, ",anonuid=%u", anonu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455
  	if (anong != (gid_t)-2 && anong != (0x10000-2))
3e63516c8   J. Bruce Fields   knfsd: fix typo i...
1456
  		seq_printf(m, ",anongid=%u", anong);
933469190   Manoj Naik   [PATCH] knfsd: nf...
1457
1458
1459
  	if (fsloc && fsloc->locations_count > 0) {
  		char *loctype = (fsloc->migrated) ? "refer" : "replicas";
  		int i;
ac34cdb03   J. Bruce Fields   knfsd: nfsd: fact...
1460
  		seq_printf(m, ",%s=", loctype);
933469190   Manoj Naik   [PATCH] knfsd: nf...
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
  		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
1475
1476
1477
1478
1479
1480
  }
  
  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
1481

bc6f02e51   Greg Banks   [PATCH] knfsd: Us...
1482
  	if (p == SEQ_START_TOKEN) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1483
1484
1485
1486
1487
1488
  		seq_puts(m, "# Version 1.1
  ");
  		seq_puts(m, "# Path Client(Flags) # IPs
  ");
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1489
1490
1491
  	cache_get(&exp->h);
  	if (cache_check(&svc_export_cache, &exp->h, NULL))
  		return 0;
baab935ff   NeilBrown   [PATCH] knfsd: Co...
1492
  	cache_put(&exp->h, &svc_export_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1493
1494
  	return svc_export_show(m, &svc_export_cache, cp);
  }
88e9d34c7   James Morris   seq_file: constif...
1495
  const struct seq_operations nfs_exports_op = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
  	.start	= e_start,
  	.next	= e_next,
  	.stop	= e_stop,
  	.show	= e_show,
  };
  
  /*
   * Add or modify a client.
   * Change requests may involve the list of host addresses. The list of
   * exports and possibly existing uid maps are left untouched.
   */
  int
  exp_addclient(struct nfsctl_client *ncp)
  {
  	struct auth_domain	*dom;
  	int			i, err;
f15364bd4   Aurélien Charbon   IPv6 support for ...
1512
  	struct in6_addr addr6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
  
  	/* First, consistency check. */
  	err = -EINVAL;
  	if (! exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
  		goto out;
  	if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
  		goto out;
  
  	/* Lock the hashtable */
  	exp_writelock();
  
  	dom = unix_domain_find(ncp->cl_ident);
  
  	err = -ENOMEM;
  	if (!dom)
  		goto out_unlock;
  
  	/* Insert client into hashtable. */
f15364bd4   Aurélien Charbon   IPv6 support for ...
1531
1532
1533
1534
  	for (i = 0; i < ncp->cl_naddr; i++) {
  		ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6);
  		auth_unix_add_addr(&addr6, dom);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
  	auth_unix_forget_old(dom);
  	auth_domain_put(dom);
  
  	err = 0;
  
  out_unlock:
  	exp_writeunlock();
  out:
  	return err;
  }
  
  /*
   * Delete a client given an identifier.
   */
  int
  exp_delclient(struct nfsctl_client *ncp)
  {
  	int		err;
  	struct auth_domain *dom;
  
  	err = -EINVAL;
  	if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
  		goto out;
  
  	/* Lock the hashtable */
  	exp_writelock();
  
  	dom = auth_domain_find(ncp->cl_ident);
  	/* just make sure that no addresses work 
  	 * and that it will expire soon 
  	 */
  	if (dom) {
  		err = auth_unix_forget_old(dom);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
  		auth_domain_put(dom);
  	}
  
  	exp_writeunlock();
  out:
  	return err;
  }
  
  /*
   * Verify that string is non-empty and does not exceed max length.
   */
  static int
  exp_verify_string(char *cp, int max)
  {
  	int	i;
  
  	for (i = 0; i < max; i++)
  		if (!cp[i])
  			return i;
  	cp[i] = 0;
  	printk(KERN_NOTICE "nfsd: couldn't validate string %s
  ", cp);
  	return 0;
  }
  
  /*
   * Initialize the exports module.
   */
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1596
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
1598
  nfsd_export_init(void)
  {
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1599
  	int rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1600
1601
  	dprintk("nfsd: initializing export module.
  ");
dbf847ecb   J. Bruce Fields   knfsd: allow cach...
1602
1603
1604
1605
1606
1607
1608
  	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
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
  
  }
  
  /*
   * Flush exports table - called when last nfsd thread is killed
   */
  void
  nfsd_export_flush(void)
  {
  	exp_writelock();
  	cache_purge(&svc_expkey_cache);
  	cache_purge(&svc_export_cache);
  	exp_writeunlock();
  }
  
  /*
   * Shutdown the exports module.
   */
  void
  nfsd_export_shutdown(void)
  {
  
  	dprintk("nfsd: shutting down export module.
  ");
  
  	exp_writelock();
df95a9d4f   J. Bruce Fields   knfsd: cache unre...
1635
1636
  	cache_unregister(&svc_expkey_cache);
  	cache_unregister(&svc_export_cache);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1637
1638
1639
1640
1641
1642
  	svcauth_unix_purge();
  
  	exp_writeunlock();
  	dprintk("nfsd: export shutdown complete.
  ");
  }