static ssize_t write_filehandle(struct file *file, char *buf, size_t size) { /* request is: * domain path maxsize * response is * filehandle * * qword quoting is used, so filehandle will be \x.... */ char *dname, *path; int maxsize; char *mesg = buf; int len; struct auth_domain *dom; struct knfsd_fh fh; if (size == 0) return -EINVAL; if (buf[size-1] != '\n') return -EINVAL; buf[size-1] = 0; dname = mesg; len = qword_get(&mesg, dname, size); if (len <= 0) return -EINVAL; path = dname+len+1; len = qword_get(&mesg, path, size); if (len <= 0) return -EINVAL; len = get_int(&mesg, &maxsize); if (len) return len; if (maxsize < NFS_FHSIZE) return -EINVAL; if (maxsize > NFS3_FHSIZE) maxsize = NFS3_FHSIZE; if (qword_get(&mesg, mesg, size)>0) return -EINVAL; /* we have all the words, they are in buf.. */ dom = unix_domain_find(dname); if (!dom) return -ENOMEM; len = exp_rootfh(dom, path, &fh, maxsize); auth_domain_put(dom); if (len) return len; mesg = buf; len = SIMPLE_TRANSACTION_LIMIT; qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); mesg[-1] = '\n'; return mesg - buf; }
static ssize_t write_filehandle(struct file *file, char *buf, size_t size) { char *dname, *path; int uninitialized_var(maxsize); char *mesg = buf; int len; struct auth_domain *dom; struct knfsd_fh fh; if (size == 0) return -EINVAL; if (buf[size-1] != '\n') return -EINVAL; buf[size-1] = 0; dname = mesg; len = qword_get(&mesg, dname, size); if (len <= 0) return -EINVAL; path = dname+len+1; len = qword_get(&mesg, path, size); if (len <= 0) return -EINVAL; len = get_int(&mesg, &maxsize); if (len) return len; if (maxsize < NFS_FHSIZE) return -EINVAL; if (maxsize > NFS3_FHSIZE) maxsize = NFS3_FHSIZE; if (qword_get(&mesg, mesg, size)>0) return -EINVAL; dom = unix_domain_find(dname); if (!dom) return -ENOMEM; len = exp_rootfh(dom, path, &fh, maxsize); auth_domain_put(dom); if (len) return len; mesg = buf; len = SIMPLE_TRANSACTION_LIMIT; qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); mesg[-1] = '\n'; return mesg - buf; }
static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) { char *mesg = buf; char *recdir; int len, status; if (size > 0) { if (nfsd_serv) return -EBUSY; if (size > PATH_MAX || buf[size-1] != '\n') return -EINVAL; buf[size-1] = 0; recdir = mesg; len = qword_get(&mesg, recdir, size); if (len <= 0) return -EINVAL; status = nfs4_reset_recoverydir(recdir); if (status) return status; } return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", nfs4_recoverydir()); }
/** * write_unlock_fs - Release all locks on a local file system * * Experimental. * * Input: * buf: '\n'-terminated C string containing the * absolute pathname of a local file system * size: length of C string in @buf * Output: * On success: returns zero if all specified locks were released; * returns one if one or more locks were not released * On error: return code is negative errno value */ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size) { struct path path; char *fo_path; int error; /* sanity check */ if (size == 0) return -EINVAL; if (buf[size-1] != '\n') return -EINVAL; fo_path = buf; if (qword_get(&buf, fo_path, size) < 0) return -EINVAL; error = kern_path(fo_path, 0, &path); if (error) return error; /* * XXX: Needs better sanity checking. Otherwise we could end up * releasing locks on the wrong file system. * * For example: * 1. Does the path refer to a directory? * 2. Is that directory a mount point, or * 3. Is that directory the root of an exported file system? */ error = nlmsvc_unlock_all_by_sb(path.mnt->mnt_sb); path_put(&path); return error; }
static ssize_t __write_pnfs_dlm_device(struct file *file, char *buf, size_t size) { char *mesg = buf; char *pnfs_dlm_device; int max_size = NFSD_PNFS_DLM_DEVICE_MAX; int len, ret = 0; if (size > 0) { ret = -EINVAL; if (size > max_size || buf[size-1] != '\n') return ret; buf[size-1] = 0; pnfs_dlm_device = mesg; len = qword_get(&mesg, pnfs_dlm_device, size); if (len <= 0) return ret; ret = nfsd4_set_pnfs_dlm_device(pnfs_dlm_device, len); } else return nfsd4_get_pnfs_dlm_device_list(buf, SIMPLE_TRANSACTION_LIMIT); return ret <= 0 ? ret : strlen(buf); }
static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size) { struct path path; char *fo_path; int error; if (size == 0) return -EINVAL; if (buf[size-1] != '\n') return -EINVAL; fo_path = buf; if (qword_get(&buf, fo_path, size) < 0) return -EINVAL; error = kern_path(fo_path, 0, &path); if (error) return error; error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb); path_put(&path); return error; }
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) { char *mesg = buf; char *recdir; int len, status; if (size > PATH_MAX || buf[size-1] != '\n') return -EINVAL; buf[size-1] = 0; recdir = mesg; len = qword_get(&mesg, recdir, size); if (len <= 0) return -EINVAL; status = nfs4_reset_recoverydir(recdir); return strlen(buf); }
/** * write_unlock_ip - Release all locks used by a client * * Experimental. * * Input: * buf: '\n'-terminated C string containing a * presentation format IP address * size: length of C string in @buf * Output: * On success: returns zero if all specified locks were released; * returns one if one or more locks were not released * On error: return code is negative errno value */ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size) { struct sockaddr_storage address; struct sockaddr *sap = (struct sockaddr *)&address; size_t salen = sizeof(address); char *fo_path; /* sanity check */ if (size == 0) return -EINVAL; if (buf[size-1] != '\n') return -EINVAL; fo_path = buf; if (qword_get(&buf, fo_path, size) < 0) return -EINVAL; if (rpc_pton(fo_path, size, sap, salen) == 0) return -EINVAL; return nlmsvc_unlock_all_by_ip(sap); }
static ssize_t write_versions(struct file *file, char *buf, size_t size) { /* * Format: * [-/+]vers [-/+]vers ... */ char *mesg = buf; char *vers, sign; int len, num; ssize_t tlen = 0; char *sep; if (size>0) { if (nfsd_serv) /* Cannot change versions without updating * nfsd_serv->sv_xdrsize, and reallocing * rq_argp and rq_resp */ return -EBUSY; if (buf[size-1] != '\n') return -EINVAL; buf[size-1] = 0; vers = mesg; len = qword_get(&mesg, vers, size); if (len <= 0) return -EINVAL; do { sign = *vers; if (sign == '+' || sign == '-') num = simple_strtol((vers+1), NULL, 0); else num = simple_strtol(vers, NULL, 0); switch(num) { case 2: case 3: case 4: nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET); break; default: return -EINVAL; } vers += len + 1; tlen += len; } while ((len = qword_get(&mesg, vers, size)) > 0); /* If all get turned off, turn them back on, as * having no versions is BAD */ nfsd_reset_versions(); } /* Now write current state into reply buffer */ len = 0; sep = ""; for (num=2 ; num <= 4 ; num++) if (nfsd_vers(num, NFSD_AVAIL)) { len += sprintf(buf+len, "%s%c%d", sep, nfsd_vers(num, NFSD_TEST)?'+':'-', num); sep = " "; } len += sprintf(buf+len, "\n"); return len; }
static ssize_t write_versions(struct file *file, char *buf, size_t size) { /* * Format: * [-/+]vers [-/+]vers ... */ char *mesg = buf; char *vers, sign; int len, num; ssize_t tlen = 0; char *sep; if (size>0) { if (nfsd_serv) return -EBUSY; if (buf[size-1] != '\n') return -EINVAL; buf[size-1] = 0; vers = mesg; len = qword_get(&mesg, vers, size); if (len <= 0) return -EINVAL; do { sign = *vers; if (sign == '+' || sign == '-') num = simple_strtol((vers+1), NULL, 0); else num = simple_strtol(vers, NULL, 0); switch(num) { case 2: case 3: case 4: if (sign != '-') NFSCTL_VERSET(nfsd_versbits, num); else NFSCTL_VERUNSET(nfsd_versbits, num); break; default: return -EINVAL; } vers += len + 1; tlen += len; } while ((len = qword_get(&mesg, vers, size)) > 0); /* If all get turned off, turn them back on, as * having no versions is BAD */ if ((nfsd_versbits & NFSCTL_VERALL)==0) nfsd_versbits = NFSCTL_VERALL; } /* Now write current state into reply buffer */ len = 0; sep = ""; for (num=2 ; num <= 4 ; num++) if (NFSCTL_VERISSET(NFSCTL_VERALL, num)) { len += sprintf(buf+len, "%s%c%d", sep, NFSCTL_VERISSET(nfsd_versbits, num)?'+':'-', num); sep = " "; } len += sprintf(buf+len, "\n"); return len; }
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; if (mesg[mlen-1] != '\n') return -EINVAL; mesg[mlen-1] = 0; buf = kmalloc(PAGE_SIZE, GFP_KERNEL); err = -ENOMEM; if (!buf) goto out; 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\n", 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\n", fsidtype); if (fsidtype > 2) goto out; if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) goto out; dprintk("found fsid length %d\n", 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); /* now we want a pathname, or empty meaning NEGATIVE */ if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) goto out; dprintk("Path seems to be <%s>\n", buf); err = 0; if (len == 0) { struct svc_expkey *ek; set_bit(CACHE_NEGATIVE, &key.h.flags); ek = svc_expkey_lookup(&key, 1); if (ek) expkey_put(&ek->h, &svc_expkey_cache); } else { struct nameidata nd; struct svc_expkey *ek; struct svc_export *exp; err = path_lookup(buf, 0, &nd); if (err) goto out; dprintk("Found the path %s\n", buf); exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); err = -ENOENT; if (!exp) goto out_nd; key.ek_export = exp; dprintk("And found export\n"); ek = svc_expkey_lookup(&key, 1); if (ek) expkey_put(&ek->h, &svc_expkey_cache); exp_put(exp); err = 0; out_nd: path_release(&nd); } cache_flush(); out: if (dom) auth_domain_put(dom); if (buf) kfree(buf); return err; }
static ssize_t __write_versions(struct file *file, char *buf, size_t size) { char *mesg = buf; char *vers, *minorp, sign; int len, num, remaining; unsigned minor; ssize_t tlen = 0; char *sep; if (size>0) { if (nfsd_serv) /* Cannot change versions without updating * nfsd_serv->sv_xdrsize, and reallocing * rq_argp and rq_resp */ return -EBUSY; if (buf[size-1] != '\n') return -EINVAL; buf[size-1] = 0; vers = mesg; len = qword_get(&mesg, vers, size); if (len <= 0) return -EINVAL; do { sign = *vers; if (sign == '+' || sign == '-') num = simple_strtol((vers+1), &minorp, 0); else num = simple_strtol(vers, &minorp, 0); if (*minorp == '.') { if (num < 4) return -EINVAL; minor = simple_strtoul(minorp+1, NULL, 0); if (minor == 0) return -EINVAL; if (nfsd_minorversion(minor, sign == '-' ? NFSD_CLEAR : NFSD_SET) < 0) return -EINVAL; goto next; } switch(num) { case 2: case 3: case 4: nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET); break; default: return -EINVAL; } next: vers += len + 1; } while ((len = qword_get(&mesg, vers, size)) > 0); /* If all get turned off, turn them back on, as * having no versions is BAD */ nfsd_reset_versions(); } /* Now write current state into reply buffer */ len = 0; sep = ""; remaining = SIMPLE_TRANSACTION_LIMIT; for (num=2 ; num <= 4 ; num++) if (nfsd_vers(num, NFSD_AVAIL)) { len = snprintf(buf, remaining, "%s%c%d", sep, nfsd_vers(num, NFSD_TEST)?'+':'-', num); sep = " "; if (len > remaining) break; remaining -= len; buf += len; tlen += len; } if (nfsd_vers(4, NFSD_AVAIL)) for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; minor++) { len = snprintf(buf, remaining, " %c4.%u", (nfsd_vers(4, NFSD_TEST) && nfsd_minorversion(minor, NFSD_TEST)) ? '+' : '-', minor); if (len > remaining) break; remaining -= len; buf += len; tlen += len; } len = snprintf(buf, remaining, "\n"); if (len > remaining) return -EINVAL; return tlen + len; }