export.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,206 行 · 第 1/2 页
C
1,206 行
exp = exp_get_by_name(clp, mnt, dentry, reqp); while (exp == NULL && !IS_ROOT(dentry)) { struct dentry *parent; parent = dget_parent(dentry); dput(dentry); dentry = parent; exp = exp_get_by_name(clp, mnt, dentry, reqp); } dput(dentry); 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);voidexp_readlock(void){ down_read(&hash_sem);}static inline voidexp_writelock(void){ down_write(&hash_sem);}voidexp_readunlock(void){ up_read(&hash_sem);}static inline voidexp_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); if (ek && !IS_ERR(ek)) { ek->h.expiry_time = get_seconds()-1; expkey_put(&ek->h, &svc_expkey_cache); } 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; mk_fsid_v1(fsid, exp->ex_fsid); return exp_set_key(clp, 1, fsid, exp);}static int exp_hash(struct auth_domain *clp, struct svc_export *exp){ u32 fsid[2]; struct inode *inode = exp->ex_dentry->d_inode; dev_t dev = inode->i_sb->s_dev; if (old_valid_dev(dev)) { mk_fsid_v0(fsid, dev, inode->i_ino); return exp_set_key(clp, 0, fsid, exp); } mk_fsid_v3(fsid, dev, inode->i_ino); return exp_set_key(clp, 3, fsid, exp);}static void exp_unhash(struct svc_export *exp){ struct svc_expkey *ek; struct inode *inode = exp->ex_dentry->d_inode; ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); if (ek && !IS_ERR(ek)) { ek->h.expiry_time = get_seconds()-1; expkey_put(&ek->h, &svc_expkey_cache); } svc_expkey_cache.nextcheck = get_seconds();} /* * Export a file system. */intexp_export(struct nfsctl_export *nxp){ svc_client *clp; struct svc_export *exp = NULL; struct svc_export new; struct svc_expkey *fsid_key = NULL; struct nameidata nd; 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).\n", 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 */ err = path_lookup(nxp->ex_path, 0, &nd); if (err) goto out_unlock; err = -EINVAL; exp = exp_get_by_name(clp, nd.mnt, nd.dentry, NULL); /* must make sure there won't be an ex_fsid clash */ if ((nxp->ex_flags & NFSEXP_FSID) && (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && !IS_ERR(fsid_key) && fsid_key->ek_export && fsid_key->ek_export != exp) goto finish; if (exp) { /* 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; } err = check_export(nd.dentry->d_inode, nxp->ex_flags); if (err) goto finish; err = -ENOMEM; dprintk("nfsd: creating export entry %p for client %p\n", exp, clp); new.h.expiry_time = NEVER; new.h.flags = 0; new.ex_client = clp; new.ex_mnt = nd.mnt; new.ex_dentry = nd.dentry; 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; exp = svc_export_lookup(&new, 1); if (exp == NULL) goto finish; err = 0; if (exp_hash(clp, exp) || exp_fsid_hash(clp, exp)) { /* failed to create at least one index */ exp_do_unexport(exp); cache_flush(); err = -ENOMEM; }finish: if (exp) exp_put(exp); if (fsid_key && !IS_ERR(fsid_key)) expkey_put(&fsid_key->h, &svc_expkey_cache); if (clp) auth_domain_put(clp); path_release(&nd);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 voidexp_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. */intexp_unexport(struct nfsctl_export *nxp){ struct auth_domain *dom; svc_export *exp; struct nameidata nd; 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\n", nxp->ex_client); goto out_unlock; } err = path_lookup(nxp->ex_path, 0, &nd); if (err) goto out_domain; err = -EINVAL; exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); path_release(&nd); if (!exp) 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. */intexp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize){ struct svc_export *exp; struct nameidata nd; struct inode *inode; struct svc_fh fh; int err; err = -EPERM; /* NB: we probably ought to check that it's NUL-terminated */ if (path_lookup(path, 0, &nd)) { printk("nfsd: exp_rootfh path not found %s", path); return err; } inode = nd.dentry->d_inode; dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", path, nd.dentry, clp->name, inode->i_sb->s_id, inode->i_ino); exp = exp_parent(clp, nd.mnt, nd.dentry, NULL); if (!exp) { dprintk("nfsd: exp_rootfh export not found.\n"); goto out; } /* * fh must be initialized before calling fh_compose */ fh_init(&fh, maxsize); if (fh_compose(&fh, exp, nd.dentry, NULL)) err = -EINVAL; else err = 0; memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh)); fh_put(&fh); exp_put(exp);out: path_release(&nd); return err;}/* * 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 */intexp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, struct cache_req *creq){ struct svc_expkey *fsid_key; int rv; u32 fsidv[2]; mk_fsid_v1(fsidv, 0); fsid_key = exp_find_key(clp, 1, fsidv, creq); if (IS_ERR(fsid_key) && PTR_ERR(fsid_key) == -EAGAIN) return nfserr_dropit; if (!fsid_key || IS_ERR(fsid_key)) return nfserr_perm; rv = fh_compose(fhp, fsid_key->ek_export, fsid_key->ek_export->ex_dentry, NULL); expkey_put(&fsid_key->h, &svc_expkey_cache); return rv;}/* Iterator */static void *e_start(struct seq_file *m, loff_t *pos){ loff_t n = *pos; unsigned hash, export; struct cache_head *ch; exp_readlock(); read_lock(&svc_export_cache.hash_lock); if (!n--) return (void *)1; 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); if (p == (void *)1) 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){ read_unlock(&svc_export_cache.hash_lock); exp_readunlock();}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", ""}},#ifdef MSNFS { NFSEXP_MSNFS, {"msnfs", ""}},#endif { 0, {"", ""}}};static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong){ int first = 0; struct flags *flg; for (flg = expflags; flg->flag; flg++) { int state = (flg->flag & flag)?0:1; if (*flg->name[state]) seq_printf(m, "%s%s", first++?",":"", flg->name[state]); } if (flag & NFSEXP_FSID) seq_printf(m, "%sfsid=%d", first++?",":"", fsid); if (anonu != (uid_t)-2 && anonu != (0x10000-2)) seq_printf(m, "%sanonuid=%d", first++?",":"", anonu); if (anong != (gid_t)-2 && anong != (0x10000-2)) seq_printf(m, "%sanongid=%d", first++?",":"", anong);}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); svc_client *clp; if (p == (void *)1) { seq_puts(m, "# Version 1.1\n"); seq_puts(m, "# Path Client(Flags) # IPs\n"); return 0; } clp = exp->ex_client; cache_get(&exp->h); if (cache_check(&svc_export_cache, &exp->h, NULL)) return 0; if (cache_put(&exp->h, &svc_export_cache)) BUG(); return svc_export_show(m, &svc_export_cache, cp);}struct seq_operations nfs_exports_op = { .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. */intexp_addclient(struct nfsctl_client *ncp){ struct auth_domain *dom; int i, err; /* 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. */ for (i = 0; i < ncp->cl_naddr; i++) auth_unix_add_addr(ncp->cl_addrlist[i], dom); auth_unix_forget_old(dom); auth_domain_put(dom); err = 0;out_unlock: exp_writeunlock();out: return err;}/* * Delete a client given an identifier. */intexp_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); dom->h.expiry_time = get_seconds(); auth_domain_put(dom); } exp_writeunlock();out: return err;}/* * Verify that string is non-empty and does not exceed max length. */static intexp_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\n", cp); return 0;}/* * Initialize the exports module. */voidnfsd_export_init(void){ dprintk("nfsd: initializing export module.\n"); cache_register(&svc_export_cache); cache_register(&svc_expkey_cache);}/* * Flush exports table - called when last nfsd thread is killed */voidnfsd_export_flush(void){ exp_writelock(); cache_purge(&svc_expkey_cache); cache_purge(&svc_export_cache); exp_writeunlock();}/* * Shutdown the exports module. */voidnfsd_export_shutdown(void){ dprintk("nfsd: shutting down export module.\n"); exp_writelock(); if (cache_unregister(&svc_expkey_cache)) printk(KERN_ERR "nfsd: failed to unregister expkey cache\n"); if (cache_unregister(&svc_export_cache)) printk(KERN_ERR "nfsd: failed to unregister export cache\n"); svcauth_unix_purge(); exp_writeunlock(); dprintk("nfsd: export shutdown complete.\n");}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?