📄 export.c
字号:
current->sigpending = 0; want_lock++; while (hash_count || hash_lock) { interruptible_sleep_on(&hash_wait); if (signal_pending(current)) break; } want_lock--; /* restore the task's signals */ spin_lock_irq(¤t->sigmask_lock); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); if (!hash_count && !hash_lock) goto lock_it; return -EINTR;}voidexp_unlock(void){ if (!hash_count && !hash_lock) printk(KERN_WARNING "exp_unlock: not locked!\n"); if (hash_count) hash_count--; else hash_lock = 0; wake_up(&hash_wait);}/* * Find a valid client given an inet address. We always move the most * recently used client to the front of the hash chain to speed up * future lookups. * Locking against other processes is the responsibility of the caller. */struct svc_client *exp_getclient(struct sockaddr_in *sin){ struct svc_clnthash **hp, **head, *tmp; unsigned long addr = sin->sin_addr.s_addr; if (!initialized) return NULL; head = &clnt_hash[CLIENT_HASH(addr)]; for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) { if (tmp->h_addr.s_addr == addr) { /* Move client to the front */ if (head != hp) { *hp = tmp->h_next; tmp->h_next = *head; *head = tmp; } return tmp->h_client; } } return NULL;}/* * Find a client given its identifier. */static svc_client *exp_getclientbyname(char *ident){ svc_client * clp; for (clp = clients; clp; clp = clp->cl_next) { if (!strcmp(clp->cl_ident, ident)) return clp; } return NULL;}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_UIDMAP, {"uidmap", ""}}, { NFSEXP_KERBEROS, { "kerberos", ""}}, { NFSEXP_SUNSECURE, { "sunsecure", ""}}, { NFSEXP_CROSSMNT, {"nohide", ""}}, { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},#ifdef MSNFS { NFSEXP_MSNFS, {"msnfs", ""}},#endif { 0, {"", ""}}};static intexp_flags(char *buffer, int flag){ int len = 0, first = 0; struct flags *flg = expflags; for (;flg->flag;flg++) { int state = (flg->flag & flag)?0:1; if (!flg->flag) break; if (*flg->name[state]) { len += sprintf(buffer + len, "%s%s", first++?",":"", flg->name[state]); } } return len;}/* mangling borrowed from fs/super.c *//* Use octal escapes, like mount does, for embedded spaces etc. */static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };static intmangle(const unsigned char *s, char *buf, int len) { char *sp; int n; sp = buf; while(*s && sp-buf < len-3) { for (n = 0; n < sizeof(need_escaping); n++) { if (*s == need_escaping[n]) { *sp++ = '\\'; *sp++ = '0' + ((*s & 0300) >> 6); *sp++ = '0' + ((*s & 070) >> 3); *sp++ = '0' + (*s & 07); goto next; } } *sp++ = *s; next: s++; } return sp - buf; /* no trailing NUL */}#define FREEROOM ((int)PAGE_SIZE-200-len)#define MANGLE(s) len += mangle((s), buffer+len, FREEROOM);intexp_procfs_exports(char *buffer, char **start, off_t offset, int length, int *eof, void *data){ struct svc_clnthash **hp, **head, *tmp; struct svc_client *clp; svc_export *exp; off_t pos = 0; off_t begin = 0; int len = 0; int i,j; len += sprintf(buffer, "# Version 1.1\n"); len += sprintf(buffer+len, "# Path Client(Flags) # IPs\n"); for (clp = clients; clp; clp = clp->cl_next) { for (i = 0; i < NFSCLNT_EXPMAX; i++) { exp = clp->cl_export[i]; while (exp) { int first = 0; MANGLE(exp->ex_path); buffer[len++]='\t'; MANGLE(clp->cl_ident); buffer[len++]='('; len += exp_flags(buffer+len, exp->ex_flags); len += sprintf(buffer+len, ") # "); for (j = 0; j < clp->cl_naddr; j++) { struct in_addr addr = clp->cl_addr[j]; head = &clnt_hash[CLIENT_HASH(addr.s_addr)]; for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) { if (tmp->h_addr.s_addr == addr.s_addr) { if (first++) len += sprintf(buffer+len, "%s", " "); if (tmp->h_client != clp) len += sprintf(buffer+len, "("); len += sprintf(buffer+len, "%d.%d.%d.%d", htonl(addr.s_addr) >> 24 & 0xff, htonl(addr.s_addr) >> 16 & 0xff, htonl(addr.s_addr) >> 8 & 0xff, htonl(addr.s_addr) >> 0 & 0xff); if (tmp->h_client != clp) len += sprintf(buffer+len, ")"); break; } } } exp = exp->ex_next; buffer[len++]='\n'; pos=begin+len; if(pos<offset) { len=0; begin=pos; } if (pos > offset + length) goto done; } } } *eof = 1;done: *start = buffer + (offset - begin); len -= (offset - begin); if ( len > length ) len = length; return len;}/* * 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 svc_clnthash * ch[NFSCLNT_ADDRMAX]; svc_client * clp; int i, err, change = 0, ilen; /* First, consistency check. */ err = -EINVAL; if (!(ilen = exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))) goto out; if (ncp->cl_naddr > NFSCLNT_ADDRMAX) goto out; /* Lock the hashtable */ if ((err = exp_writelock()) < 0) goto out; /* First check if this is a change request for a client. */ for (clp = clients; clp; clp = clp->cl_next) if (!strcmp(clp->cl_ident, ncp->cl_ident)) break; err = -ENOMEM; if (clp) { change = 1; } else { if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL))) goto out_unlock; memset(clp, 0, sizeof(*clp)); dprintk("created client %s (%p)\n", ncp->cl_ident, clp); strcpy(clp->cl_ident, ncp->cl_ident); clp->cl_idlen = ilen; } /* Allocate hash buckets */ for (i = 0; i < ncp->cl_naddr; i++) { ch[i] = kmalloc(sizeof(struct svc_clnthash), GFP_KERNEL); if (!ch[i]) { while (i--) kfree(ch[i]); if (!change) kfree(clp); goto out_unlock; } } /* Copy addresses. */ for (i = 0; i < ncp->cl_naddr; i++) { clp->cl_addr[i] = ncp->cl_addrlist[i]; } clp->cl_naddr = ncp->cl_naddr; /* Remove old client hash entries. */ if (change) exp_unhashclient(clp); /* Insert client into hashtable. */ for (i = 0; i < ncp->cl_naddr; i++) { struct in_addr addr = clp->cl_addr[i]; int hash; hash = CLIENT_HASH(addr.s_addr); ch[i]->h_client = clp; ch[i]->h_addr = addr; ch[i]->h_next = clnt_hash[hash]; clnt_hash[hash] = ch[i]; } if (!change) { clp->cl_next = clients; clients = clp; } err = 0;out_unlock: exp_unlock();out: return err;}/* * Delete a client given an identifier. */intexp_delclient(struct nfsctl_client *ncp){ svc_client **clpp, *clp; int err; err = -EINVAL; if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)) goto out; /* Lock the hashtable */ if ((err = exp_writelock()) < 0) goto out; err = -EINVAL; for (clpp = &clients; (clp = *clpp); clpp = &(clp->cl_next)) if (!strcmp(ncp->cl_ident, clp->cl_ident)) break; if (clp) { *clpp = clp->cl_next; exp_freeclient(clp); err = 0; } exp_unlock();out: return err;}/* * Free a client. The caller has already removed it from the client list. */static voidexp_freeclient(svc_client *clp){ exp_unhashclient(clp); /* umap_free(&(clp->cl_umap)); */ exp_unexport_all(clp); nfsd_lockd_unexport(clp); kfree (clp);}/* * Remove client from hashtable. We first collect all hashtable * entries and free them in one go. * The hash table must be writelocked by the caller. */static voidexp_unhashclient(svc_client *clp){ struct svc_clnthash **hpp, *hp, *ch[NFSCLNT_ADDRMAX]; int i, count, err;again: err = 0; for (i = 0, count = 0; i < CLIENT_HASHMAX && !err; i++) { hpp = clnt_hash + i; while ((hp = *hpp) && !err) { if (hp->h_client == clp) { *hpp = hp->h_next; ch[count++] = hp; err = (count >= NFSCLNT_ADDRMAX); } else { hpp = &(hp->h_next); } } } if (count != clp->cl_naddr) printk(KERN_WARNING "nfsd: bad address count in freeclient!\n"); if (err) goto again; for (i = 0; i < count; i++) kfree (ch[i]);}/* * Lockd is shutting down and tells us to unregister all clients */voidexp_nlmdetach(void){ struct svc_client *clp; for (clp = clients; clp; clp = clp->cl_next) nfsd_lockd_unexport(clp);}/* * 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){ int i; dprintk("nfsd: initializing export module.\n"); if (initialized) return; for (i = 0; i < CLIENT_HASHMAX; i++) clnt_hash[i] = NULL; clients = NULL; initialized = 1;}/* * Shutdown the exports module. */voidnfsd_export_shutdown(void){ int i; dprintk("nfsd: shutting down export module.\n"); if (!initialized) return; if (exp_writelock() < 0) { printk(KERN_WARNING "Weird: hashtable locked in exp_shutdown"); return; } for (i = 0; i < CLIENT_HASHMAX; i++) { while (clnt_hash[i]) exp_freeclient(clnt_hash[i]->h_client); } clients = NULL; /* we may be restarted before the module unloads */ exp_unlock(); dprintk("nfsd: export shutdown complete.\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -