| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | #define MSNFS /* HACK HACK */ | |||
| 2 | /* | |||
| 3 | * linux/fs/nfsd/export.c | |||
| 4 | * | |||
| 5 | * NFS exporting and validation. | |||
| 6 | * | |||
| 7 | * We maintain a list of clients, each of which has a list of | |||
| 8 | * exports. To export an fs to a given client, you first have | |||
| 9 | * to create the client entry with NFSCTL_ADDCLIENT, which | |||
| 10 | * creates a client control block and adds it to the hash | |||
| 11 | * table. Then, you call NFSCTL_EXPORT for each fs. | |||
| 12 | * | |||
| 13 | * | |||
| 14 | * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de> | |||
| 15 | */ | |||
| 16 | ||||
| 17 | #include <linux/unistd.h> | |||
| 18 | #include <linux/slab.h> | |||
| 19 | #include <linux/sched.h> | |||
| 20 | #include <linux/stat.h> | |||
| 21 | #include <linux/in.h> | |||
| 22 | #include <linux/seq_file.h> | |||
| 23 | #include <linux/syscalls.h> | |||
| 24 | #include <linux/rwsem.h> | |||
| 25 | #include <linux/dcache.h> | |||
| 26 | #include <linux/namei.h> | |||
| 27 | #include <linux/mount.h> | |||
| 28 | #include <linux/hash.h> | |||
| 29 | #include <linux/module.h> | |||
| 30 | ||||
| 31 | #include <linux/sunrpc/svc.h> | |||
| 32 | #include <linux/nfsd/nfsd.h> | |||
| 33 | #include <linux/nfsd/nfsfh.h> | |||
| 34 | #include <linux/nfsd/syscall.h> | |||
| 35 | #include <linux/lockd/bind.h> | |||
| 36 | ||||
| 37 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT | |||
| 38 | #define NFSD_PARANOIA 1 | |||
| 39 | ||||
| 40 | typedef struct auth_domain svc_client; | |||
| 41 | typedef struct svc_export svc_export; | |||
| 42 | ||||
| 43 | static void exp_do_unexport(svc_export *unexp); | |||
| 44 | static int exp_verify_string(char *cp, int max); | |||
| 45 | ||||
| 46 | /* | |||
| 47 | * We have two caches. | |||
| 48 | * One maps client+vfsmnt+dentry to export options - the export map | |||
| 49 | * The other maps client+filehandle-fragment to export options. - the expkey map | |||
| 50 | * | |||
| 51 | * The export options are actually stored in the first map, and the | |||
| 52 | * second map contains a reference to the entry in the first map. | |||
| 53 | */ | |||
| 54 | ||||
| 55 | #define EXPKEY_HASHBITS 8 | |||
| 56 | #define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS) | |||
| 57 | #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) | |||
| 58 | static struct cache_head *expkey_table[EXPKEY_HASHMAX]; | |||
| 59 | ||||
| 0 | 0 | - | 60 | static inline int svc_expkey_hash(struct svc_expkey *item) |
| 61 | { | |||
| 62 | int hash = item->ek_fsidtype; | |||
| 63 | char * cp = (char*)item->ek_fsid; | |||
| 64 | int len = key_len(item->ek_fsidtype); | |||
| 65 | ||||
| 66 | hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); | |||
| 67 | hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS); | |||
| 0 | - | 68 | return hash & EXPKEY_HASHMASK; | |
| 69 | } | |||
| 70 | ||||
| 0 | 0 | - | 71 | void expkey_put(struct cache_head *item, struct cache_detail *cd) |
| 72 | { | |||
| 0 | 0 | - | 73 | if (cache_put(item, cd)) { |
| 74 | struct svc_expkey *key = container_of(item, struct svc_expkey, h); | |||
| 75 | if (test_bit(CACHE_VALID, &item->flags) && | |||
| 0 | 0 | - | 76 | !test_bit(CACHE_NEGATIVE, &item->flags)) |
| 0 | - | 76 | (T) && !(F) | |
| 0 | - | 76 | (T) && !(T) | |
| 0 | - | 76 | (F) && !(_) | |
| 0 | 0 | - | 76 | ternary-?: __builtin_constant_p ( 0 ) |
| 0 | 0 | - | 76 | ternary-?: __builtin_constant_p ( 1 ) |
| 77 | exp_put(key->ek_export); | |||
| 78 | auth_domain_put(key->ek_client); | |||
| 79 | kfree(key); | |||
| 80 | } | |||
| 81 | } | |||
| 82 | ||||
| 0 | 0 | - | 83 | static void expkey_request(struct cache_detail *cd, |
| 84 | struct cache_head *h, | |||
| 85 | char **bpp, int *blen) | |||
| 86 | { | |||
| 87 | /* client fsidtype \xfsid */ | |||
| 88 | struct svc_expkey *ek = container_of(h, struct svc_expkey, h); | |||
| 89 | char type[5]; | |||
| 90 | ||||
| 91 | qword_add(bpp, blen, ek->ek_client->name); | |||
| 92 | snprintf(type, 5, "%d", ek->ek_fsidtype); | |||
| 93 | qword_add(bpp, blen, type); | |||
| 94 | qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype)); | |||
| 95 | (*bpp)[-1] = '\n'; | |||
| 96 | } | |||
| 97 | ||||
| 98 | static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int); | |||
| 0 | 0 | - | 99 | static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) |
| 100 | { | |||
| 101 | /* client fsidtype fsid [path] */ | |||
| 102 | char *buf; | |||
| 103 | int len; | |||
| 104 | struct auth_domain *dom = NULL; | |||
| 105 | int err; | |||
| 106 | int fsidtype; | |||
| 107 | char *ep; | |||
| 108 | struct svc_expkey key; | |||
| 109 | ||||
| 0 | 0 | - | 110 | if (mesg[mlen-1] != '\n') |
| 0 | - | 111 | return -EINVAL; | |
| 112 | mesg[mlen-1] = 0; | |||
| 113 | ||||
| 114 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | |||
| 115 | err = -ENOMEM; | |||
| 0 | 0 | - | 116 | if (!buf) goto out; |
| 0 | - | 116 | goto out | |
| 117 | ||||
| 118 | err = -EINVAL; | |||
| 0 | 0 | - | 119 | if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) |
| 0 | - | 120 | goto out; | |
| 121 | ||||
| 122 | err = -ENOENT; | |||
| 123 | dom = auth_domain_find(buf); | |||
| 0 | 0 | - | 124 | if (!dom) |
| 0 | - | 125 | goto out; | |
| 126 | dprintk("found domain %s\n", buf); | |||
| 0 | 0 | - | 126 | if (nfsd_debug & 0x0004) |
| 0 | 0 | - | 126 | do-while (0) |
| 127 | ||||
| 128 | err = -EINVAL; | |||
| 0 | 0 | - | 129 | if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) |
| 0 | - | 130 | goto out; | |
| 131 | fsidtype = simple_strtoul(buf, &ep, 10); | |||
| 0 | 0 | - | 132 | if (*ep) |
| 0 | - | 133 | goto out; | |
| 134 | dprintk("found fsidtype %d\n", fsidtype); | |||
| 0 | 0 | - | 134 | if (nfsd_debug & 0x0004) |
| 0 | 0 | - | 134 | do-while (0) |
| 0 | 0 | - | 135 | if (fsidtype > 2) |
| 0 | - | 136 | goto out; | |
| 0 | 0 | - | 137 | if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) |
| 0 | - | 138 | goto out; | |
| 139 | dprintk("found fsid length %d\n", len); | |||
| 0 | 0 | - | 139 | if (nfsd_debug & 0x0004) |
| 0 | 0 | - | 139 | do-while (0) |
| 0 | 0 | - | 140 | if (len != key_len(fsidtype)) |
| 0 | - | 141 | goto out; | |
| 142 | ||||
| 143 | /* OK, we seem to have a valid key */ | |||
| 144 | key.h.flags = 0; | |||
| 145 | key.h.expiry_time = get_expiry(&mesg); | |||
| 0 | 0 | - | 146 | if (key.h.expiry_time == 0) |
| 0 | - | 147 | goto out; | |
| 148 | ||||
| 149 | key.ek_client = dom; | |||
| 150 | key.ek_fsidtype = fsidtype; | |||
| 151 | memcpy(key.ek_fsid, buf, len); | |||
| 152 | ||||
| 153 | /* now we want a pathname, or empty meaning NEGATIVE */ | |||
| 0 | 0 | - | 154 | if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) |
| 0 | - | 155 | goto out; | |
| 156 | dprintk("Path seems to be <%s>\n", buf); | |||
| 0 | 0 | - | 156 | if (nfsd_debug & 0x0004) |
| 0 | 0 | - | 156 | do-while (0) |
| 157 | err = 0; | |||
| 0 | 0 | - | 158 | if (len == 0) { |
| 159 | struct svc_expkey *ek; | |||
| 160 | set_bit(CACHE_NEGATIVE, &key.h.flags); | |||
| 161 | ek = svc_expkey_lookup(&key, 1); | |||
| 0 | 0 | - | 162 | if (ek) |
| 163 | expkey_put(&ek->h, &svc_expkey_cache); | |||
| 164 | } else { | |||
| 165 | struct nameidata nd; | |||
| 166 | struct svc_expkey *ek; | |||
| 167 | struct svc_export *exp; | |||
| 168 | err = path_lookup(buf, 0, &nd); | |||
| 0 | 0 | - | 169 | if (err) |
| 0 | - | 170 | goto out; | |
| 171 | ||||
| 172 | dprintk("Found the path %s\n", buf); | |||
| 0 | 0 | - | 172 | if (nfsd_debug & 0x0004) |
| 0 | 0 | - | 172 | do-while (0) |
| 173 | exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); | |||
| 174 | ||||
| 175 | err = -ENOENT; | |||
| 0 | 0 | - | 176 | if (!exp) |
| 0 | - | 177 | goto out_nd; | |
| 178 | key.ek_export = exp; | |||
| 179 | dprintk("And found export\n"); | |||
| 0 | 0 | - | 179 | if (nfsd_debug & 0x0004) |
| 0 | 0 | - | 179 | do-while (0) |
| 180 | ||||
| 181 | ek = svc_expkey_lookup(&key, 1); | |||
| 0 | 0 | - | 182 | if (ek) |
| 183 | expkey_put(&ek->h, &svc_expkey_cache); | |||
| 184 | exp_put(exp); | |||
| 185 | err = 0; | |||
| 186 | out_nd: | |||
| 187 | path_release(&nd); | |||
| 188 | } | |||
| 189 | cache_flush(); | |||
| 190 | out: | |||
| 0 | 0 | - | 191 | if (dom) |
| 192 | auth_domain_put(dom); | |||
| 193 | kfree(buf); | |||
| 0 | - | 194 | return err; | |
| 195 | } | |||
| 196 | ||||
| 0 | 0 | - | 197 | static int expkey_show(struct seq_file *m, |
| 198 | struct cache_detail *cd, | |||
| 199 | struct cache_head *h) | |||
| 200 | { | |||
| 201 | struct svc_expkey *ek ; | |||
| 202 | ||||
| 0 | 0 | - | 203 | if (h ==NULL) { |
| 204 | seq_puts(m, "#domain fsidtype fsid [path]\n"); | |||
| 0 | - | 205 | return 0; | |
| 206 | } | |||
| 207 | ek = container_of(h, struct svc_expkey, h); | |||
| 208 | seq_printf(m, "%s %d 0x%08x", ek->ek_client->name, | |||
| 209 | ek->ek_fsidtype, ek->ek_fsid[0]); | |||
| 0 | 0 | - | 210 | if (ek->ek_fsidtype != 1) |
| 211 | seq_printf(m, "%08x", ek->ek_fsid[1]); | |||
| 0 | 0 | - | 212 | if (ek->ek_fsidtype == 2) |
| 213 | seq_printf(m, "%08x", ek->ek_fsid[2]); | |||
| 214 | if (test_bit(CACHE_VALID, &h->flags) && | |||
| 0 | 0 | - | 215 | !test_bit(CACHE_NEGATIVE, &h->flags)) { |
| 0 | - | 215 | (T) && !(F) | |
| 0 | - | 215 | (T) && !(T) | |
| 0 | - | 215 | (F) && !(_) | |
| 0 | 0 | - | 215 | ternary-?: __builtin_constant_p ( 0 ) |
| 0 | 0 | - | 215 | ternary-?: __builtin_constant_p ( 1 ) |
| 216 | seq_printf(m, " "); | |||
| 217 | seq_path(m, ek->ek_export->ex_mnt, ek->ek_export->ex_dentry, "\\ \t\n"); | |||
| 218 | } | |||
| 219 | seq_printf(m, "\n"); | |||
| 0 | - | 220 | return 0; | |
| 221 | } | |||
| 222 | ||||
| 223 | struct cache_detail svc_expkey_cache = { | |||
| 224 | .owner = THIS_MODULE, | |||
| 225 | .hash_size = EXPKEY_HASHMAX, | |||
| 226 | .hash_table = expkey_table, | |||
| 227 | .name = "nfsd.fh", | |||
| 228 | .cache_put = expkey_put, | |||
| 229 | .cache_request = expkey_request, | |||
| 230 | .cache_parse = expkey_parse, | |||
| 231 | .cache_show = expkey_show, | |||
| 232 | }; | |||
| 233 | ||||
| 0 | 0 | - | 234 | static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b) |
| 235 | { | |||
| 236 | if (a->ek_fsidtype != b->ek_fsidtype || | |||
| 237 | a->ek_client != b->ek_client || | |||
| 0 | 0 | - | 238 | memcmp(a->ek_fsid, b->ek_fsid, key_len(a->ek_fsidtype)) != 0) |
| 0 | - | 238 | T || _ || _ | |
| 0 | - | 238 | F || T || _ | |
| 0 | - | 238 | F || F || T | |
| 0 | - | 238 | F || F || F | |
| 0 | - | 239 | return 0; | |
| 0 | - | 240 | return 1; | |
| 241 | } | |||
| 242 | ||||
| 0 | 0 | - | 243 | static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item) |
| 244 | { | |||
| 245 | cache_get(&item->ek_client->h); | |||
| 246 | new->ek_client = item->ek_client; | |||
| 247 | new->ek_fsidtype = item->ek_fsidtype; | |||
| 248 | new->ek_fsid[0] = item->ek_fsid[0]; | |||
| 249 | new->ek_fsid[1] = item->ek_fsid[1]; | |||
| 250 | new->ek_fsid[2] = item->ek_fsid[2]; | |||
| 251 | } | |||
| 252 | ||||
| 0 | 0 | - | 253 | static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item) |
| 254 | { | |||
| 255 | cache_get(&item->ek_export->h); | |||
| 256 | new->ek_export = item->ek_export; | |||
| 257 | } | |||
| 258 | ||||
| 0 | 0 | - | 259 | static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */ |
| 0 | 0 | - | 259 | if (set || new) |
| 0 | - | 259 | T || _ | |
| 0 | - | 259 | F || T | |
| 0 | - | 259 | F || F | |
| 259 | do | |||
| 259 | do | |||
| 0 | 0 | - | 259 | do-while (0) |
| 0 | 0 | - | 259 | do-while (0) |
| 259 | else | |||
| 259 | do | |||
| 259 | do | |||
| 0 | 0 | - | 259 | do-while (0) |
| 0 | 0 | - | 259 | do-while (0) |
| 0 | 0 | - | 259 | for (;* hp != ( ( void * ) 0 );) |
| 0 | 0 | - | 259 | if (svc_expkey_match ( item , tmp )) |
| 0 | 0 | - | 259 | if (set && ! 0 && ( __builtin_constant_p (.. |
| 0 | - | 259 | T && T && (T) && T | |
| 0 | - | 259 | T && T && (T) && F | |
| 0 | - | 259 | T && T && (F) && _ | |
| 0 | - | 259 | T && F && (_) && _ | |
| 0 | - | 259 | F && _ && (_) && _ | |
| 0 | 0 | - | 259 | ternary-?: __builtin_constant_p ( 0 ) |
| 0 | - | 259 | break | |
| 0 | 0 | - | 259 | if (new) |
| 0 | 0 | - | 259 | if (set) |
| 0 | 0 | - | 259 | if (! 0 && ( __builtin_constant_p ( 0 ) .. |
| 0 | - | 259 | T && (T) | |
| 0 | - | 259 | T && (F) | |
| 0 | - | 259 | F && (_) | |
| 0 | 0 | - | 259 | ternary-?: __builtin_constant_p ( 0 ) |
| 0 | 0 | - | 259 | if (( __builtin_constant_p ( 1 ) ? const.. |
| 0 | 0 | - | 259 | ternary-?: __builtin_constant_p ( 1 ) |
| 259 | else | |||
| 0 | 0 | - | 259 | if (set || new) |
| 0 | - | 259 | T || _ | |
| 0 | - | 259 | F || T | |
| 0 | - | 259 | F || F | |
| 259 | do | |||
| 259 | do | |||
| 0 | 0 | - | 259 | do-while (0) |
| 0 | 0 | - | 259 | do-while (0) |
| 259 | else | |||
| 259 | do | |||
| 259 | do | |||
| 0 | 0 | - | 259 | do-while (0) |
| 0 | 0 | - | 259 | do-while (0) |
| 0 | 0 | - | 259 | if (set) |
| 0 | 0 | - | 259 | if (set && ! 0 && new) |
| 0 | - | 259 | T && T && T | |
| 0 | - | 259 | T && T && F | |
| 0 | - | 259 | T && F && _ | |
| 0 | - | 259 | F && _ && _ | |
| 0 | 0 | - | 259 | if (new) |
| 0 | - | 259 | return tmp | |
| 0 | 0 | - | 259 | if (new) |
| 0 | 0 | - | 259 | if (set) |
| 0 | 0 | - | 259 | if (( __builtin_constant_p ( 1 ) ? constan.. |
| 0 | 0 | - | 259 | ternary-?: __builtin_constant_p ( 1 ) |
| 259 | else | |||
| 0 | 0 | - | 259 | if (set || new) |
| 0 | - | 259 | T || _ | |
| 0 | - | 259 | F || T | |
| 0 | - | 259 | F || F | |
| 259 | do | |||
| 259 | do | |||
| 0 | 0 | - | 259 | do-while (0) |
| 0 | 0 | - | 259 | do-while (0) |
| 259 | else | |||
| 259 | do | |||
| 259 | do | |||
| 0 | 0 | - | 259 | do-while (0) |
| 0 | 0 | - | 259 | do-while (0) |
| 0 | 0 | - | 259 | if (new && set) |
| 0 | - | 259 | T && T | |
| 0 | - | 259 | T && F | |
| 0 | - | 259 | F && _ | |
| 0 | 0 | - | 259 | if (new) |
| 0 | - | 259 | return new | |
| 0 | 0 | - | 259 | if (new) |
| 0 | - | 259 | goto retry | |
| 0 | - | 259 | return ( ( void * ) 0 ) | |
| 260 | ||||
| 261 | #define EXPORT_HASHBITS 8 | |||
| 262 | #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) | |||
| 263 | #define EXPORT_HASHMASK (EXPORT_HASHMAX -1) | |||
| 264 | ||||
| 265 | static struct cache_head *export_table[EXPORT_HASHMAX]; | |||
| 266 | ||||
| 0 | 0 | - | 267 | static inline int svc_export_hash(struct svc_export *item) |
| 268 | { | |||
| 269 | int rv; | |||
| 270 | ||||
| 271 | rv = hash_ptr(item->ex_client, EXPORT_HASHBITS); | |||
| 272 | rv ^= hash_ptr(item->ex_dentry, EXPORT_HASHBITS); | |||
| 273 | rv ^= hash_ptr(item->ex_mnt, EXPORT_HASHBITS); | |||
| 0 | - | 274 | return rv; | |
| 275 | } | |||
| 276 | ||||
| 0 | 0 | - | 277 | void svc_export_put(struct cache_head *item, struct cache_detail *cd) |
| 278 | { | |||
| 0 | 0 | - | 279 | if (cache_put(item, cd)) { |
| 280 | struct svc_export *exp = container_of(item, struct svc_export, h); | |||
| 281 | dput(exp->ex_dentry); | |||
| 282 | mntput(exp->ex_mnt); | |||
| 283 | auth_domain_put(exp->ex_client); | |||
| 284 | kfree(exp); | |||
| 285 | } | |||
| 286 | } | |||
| 287 | ||||
| 0 | 0 | - | 288 | static void svc_export_request(struct cache_detail *cd, |
| 289 | struct cache_head *h, | |||
| 290 | char **bpp, int *blen) | |||
| 291 | { | |||
| 292 | /* client path */ | |||
| 293 | struct svc_export *exp = container_of(h, struct svc_export, h); | |||
| 294 | char *pth; | |||
| 295 | ||||
| 296 | qword_add(bpp, blen, exp->ex_client->name); | |||
| 297 | pth = d_path(exp->ex_dentry, exp->ex_mnt, *bpp, *blen); | |||
| 0 | 0 | - | 298 | if (IS_ERR(pth)) { |
| 299 | /* is this correct? */ | |||
| 300 | (*bpp)[0] = '\n'; | |||
| 0 | - | 301 | return; | |
| 302 | } | |||
| 303 | qword_add(bpp, blen, pth); | |||
| 304 | (*bpp)[-1] = '\n'; | |||
| 305 | } | |||
| 306 | ||||
| 307 | static struct svc_export *svc_export_lookup(struct svc_export *, int); | |||
| 308 | ||||
| 0 | 0 | - | 309 | static int check_export(struct inode *inode, int flags) |
| 310 | { | |||
| 311 | ||||
| 312 | /* We currently export only dirs and regular files. | |||
| 313 | * This is what umountd does. | |||
| 314 | */ | |||
| 315 | if (!S_ISDIR(inode->i_mode) && | |||
| 0 | 0 | - | 316 | !S_ISREG(inode->i_mode)) |
| 0 | - | 316 | !(F) && !(F) | |
| 0 | - | 316 | !(T) && !(_) | |
| 0 | - | 316 | !(F) && !(T) | |
| 0 | - | 317 | return -ENOTDIR; | |
| 318 | ||||
| 319 | /* There are two requirements on a filesystem to be exportable. | |||
| 320 | * 1: We must be able to identify the filesystem from a number. | |||
| 321 | * either a device number (so FS_REQUIRES_DEV needed) | |||
| 322 | * or an FSID number (so NFSEXP_FSID needed). | |||
| 323 | * 2: We must be able to find an inode from a filehandle. | |||
| 324 | * This means that s_export_op must be set. | |||
| 325 | */ | |||
| 326 | if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) && | |||
| 0 | 0 | - | 327 | !(flags & NFSEXP_FSID)) { |
| 0 | - | 327 | !(F) && !(F) | |
| 0 | - | 327 | !(T) && !(_) | |
| 0 | - | 327 | !(F) && !(T) | |
| 328 | dprintk("exp_export: export of non-dev fs without fsid"); | |||
| 0 | 0 | - | 328 | if (nfsd_debug & 0x0004) |
| 0 | 0 | - | 328 | do-while (0) |
| 0 | - | 329 | return -EINVAL; | |
| 330 | } | |||
| 0 | 0 | - | 331 | if (!inode->i_sb->s_export_op) { |
| 332 | dprintk("exp_export: export of invalid fs type.\n"); | |||
| 0 | 0 | - | 332 | if (nfsd_debug & 0x0004) |
| 0 | 0 | - | 332 | do-while (0) |
| 0 | - | 333 | return -EINVAL; | |
| 334 | } | |||
| 335 | ||||
| 336 | /* Ok, we can export it */; | |||
| 0 | 0 | - | 337 | if (!inode->i_sb->s_export_op->find_exported_dentry) |
| 338 | inode->i_sb->s_export_op->find_exported_dentry = | |||
| 339 | find_exported_dentry; | |||
| 0 | - | 340 | return 0; | |
| 341 | ||||
| 342 | } | |||
| 343 | ||||
| 0 | 0 | - | 344 | static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) |
| 345 | { | |||
| 346 | /* client path expiry [flags anonuid anongid fsid] */ | |||
| 347 | char *buf; | |||
| 348 | int len; | |||
| 349 | int err; | |||
| 350 | struct auth_domain *dom = NULL; | |||
| 351 | struct nameidata nd; | |||
| 352 | struct svc_export exp, *expp; | |||
| 353 | int an_int; | |||
| 354 | ||||
| 355 | nd.dentry = NULL; | |||
| 356 | ||||
| 0 | 0 | - | 357 | if (mesg[mlen-1] != '\n') |
| 0 | - | 358 | return -EINVAL; | |
| 359 | mesg[mlen-1] = 0; | |||
| 360 | ||||
| 361 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | |||
| 362 | err = -ENOMEM; | |||
| 0 | 0 | - | 363 | if (!buf) goto out; |
| 0 | - | 363 | goto out | |
| 364 | ||||
| 365 | /* client */ | |||
| 366 | len = qword_get(&mesg, buf, PAGE_SIZE); | |||
| 367 | err = -EINVAL; | |||
| 0 | 0 | - | 368 | if (len <= 0) goto out; |
| 0 | - | 368 | goto out | |
| 369 | ||||
| 370 | err = -ENOENT; | |||
| 371 | dom = auth_domain_find(buf); | |||
| 0 | 0 | - | 372 | if (!dom) |
| 0 | - | 373 | goto out; | |
| 374 | ||||
| 375 | /* path */ | |||
| 376 | err = -EINVAL; | |||
| 0 | 0 | - | 377 | if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) |
| 0 | - | 378 | goto out; | |
| 379 | ||||