aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/auth.c1
-rw-r--r--fs/nfsd/export.c9
-rw-r--r--fs/nfsd/nfs4callback.c28
-rw-r--r--fs/nfsd/nfs4idmap.c2
-rw-r--r--fs/nfsd/nfs4state.c71
-rw-r--r--fs/nfsd/nfs4xdr.c13
-rw-r--r--fs/nfsd/nfsctl.c22
-rw-r--r--fs/nfsd/nfsfh.c228
-rw-r--r--fs/nfsd/nfssvc.c2
-rw-r--r--fs/nfsd/vfs.c35
10 files changed, 229 insertions, 182 deletions
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index d13403e33622..294992e9bf69 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -10,6 +10,7 @@
10#include <linux/sunrpc/svcauth.h> 10#include <linux/sunrpc/svcauth.h>
11#include <linux/nfsd/nfsd.h> 11#include <linux/nfsd/nfsd.h>
12#include <linux/nfsd/export.h> 12#include <linux/nfsd/export.h>
13#include "auth.h"
13 14
14int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) 15int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
15{ 16{
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 8a6f7c924c75..33bfcf09db46 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -35,6 +35,7 @@
35#include <linux/lockd/bind.h> 35#include <linux/lockd/bind.h>
36#include <linux/sunrpc/msg_prot.h> 36#include <linux/sunrpc/msg_prot.h>
37#include <linux/sunrpc/gss_api.h> 37#include <linux/sunrpc/gss_api.h>
38#include <net/ipv6.h>
38 39
39#define NFSDDBG_FACILITY NFSDDBG_EXPORT 40#define NFSDDBG_FACILITY NFSDDBG_EXPORT
40 41
@@ -1548,6 +1549,7 @@ exp_addclient(struct nfsctl_client *ncp)
1548{ 1549{
1549 struct auth_domain *dom; 1550 struct auth_domain *dom;
1550 int i, err; 1551 int i, err;
1552 struct in6_addr addr6;
1551 1553
1552 /* First, consistency check. */ 1554 /* First, consistency check. */
1553 err = -EINVAL; 1555 err = -EINVAL;
@@ -1566,9 +1568,10 @@ exp_addclient(struct nfsctl_client *ncp)
1566 goto out_unlock; 1568 goto out_unlock;
1567 1569
1568 /* Insert client into hashtable. */ 1570 /* Insert client into hashtable. */
1569 for (i = 0; i < ncp->cl_naddr; i++) 1571 for (i = 0; i < ncp->cl_naddr; i++) {
1570 auth_unix_add_addr(ncp->cl_addrlist[i], dom); 1572 ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6);
1571 1573 auth_unix_add_addr(&addr6, dom);
1574 }
1572 auth_unix_forget_old(dom); 1575 auth_unix_forget_old(dom);
1573 auth_domain_put(dom); 1576 auth_domain_put(dom);
1574 1577
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index aae2b29ae2c9..562abf3380d0 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -344,6 +344,21 @@ static struct rpc_version * nfs_cb_version[] = {
344 &nfs_cb_version4, 344 &nfs_cb_version4,
345}; 345};
346 346
347static struct rpc_program cb_program;
348
349static struct rpc_stat cb_stats = {
350 .program = &cb_program
351};
352
353#define NFS4_CALLBACK 0x40000000
354static struct rpc_program cb_program = {
355 .name = "nfs4_cb",
356 .number = NFS4_CALLBACK,
357 .nrvers = ARRAY_SIZE(nfs_cb_version),
358 .version = nfs_cb_version,
359 .stats = &cb_stats,
360};
361
347/* Reference counting, callback cleanup, etc., all look racy as heck. 362/* Reference counting, callback cleanup, etc., all look racy as heck.
348 * And why is cb_set an atomic? */ 363 * And why is cb_set an atomic? */
349 364
@@ -358,13 +373,12 @@ static int do_probe_callback(void *data)
358 .to_maxval = (NFSD_LEASE_TIME/2) * HZ, 373 .to_maxval = (NFSD_LEASE_TIME/2) * HZ,
359 .to_exponential = 1, 374 .to_exponential = 1,
360 }; 375 };
361 struct rpc_program * program = &cb->cb_program;
362 struct rpc_create_args args = { 376 struct rpc_create_args args = {
363 .protocol = IPPROTO_TCP, 377 .protocol = IPPROTO_TCP,
364 .address = (struct sockaddr *)&addr, 378 .address = (struct sockaddr *)&addr,
365 .addrsize = sizeof(addr), 379 .addrsize = sizeof(addr),
366 .timeout = &timeparms, 380 .timeout = &timeparms,
367 .program = program, 381 .program = &cb_program,
368 .version = nfs_cb_version[1]->number, 382 .version = nfs_cb_version[1]->number,
369 .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ 383 .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
370 .flags = (RPC_CLNT_CREATE_NOPING), 384 .flags = (RPC_CLNT_CREATE_NOPING),
@@ -382,16 +396,8 @@ static int do_probe_callback(void *data)
382 addr.sin_port = htons(cb->cb_port); 396 addr.sin_port = htons(cb->cb_port);
383 addr.sin_addr.s_addr = htonl(cb->cb_addr); 397 addr.sin_addr.s_addr = htonl(cb->cb_addr);
384 398
385 /* Initialize rpc_program */
386 program->name = "nfs4_cb";
387 program->number = cb->cb_prog;
388 program->nrvers = ARRAY_SIZE(nfs_cb_version);
389 program->version = nfs_cb_version;
390 program->stats = &cb->cb_stat;
391
392 /* Initialize rpc_stat */ 399 /* Initialize rpc_stat */
393 memset(program->stats, 0, sizeof(cb->cb_stat)); 400 memset(args.program->stats, 0, sizeof(struct rpc_stat));
394 program->stats->program = program;
395 401
396 /* Create RPC client */ 402 /* Create RPC client */
397 client = rpc_create(&args); 403 client = rpc_create(&args);
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 996bd88b75ba..5b398421b051 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -202,7 +202,7 @@ static struct cache_detail idtoname_cache = {
202 .alloc = ent_alloc, 202 .alloc = ent_alloc,
203}; 203};
204 204
205int 205static int
206idtoname_parse(struct cache_detail *cd, char *buf, int buflen) 206idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
207{ 207{
208 struct ent ent, *res; 208 struct ent ent, *res;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 81a75f3081f4..55dfdd71f1b0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1639,6 +1639,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
1639 locks_init_lock(&fl); 1639 locks_init_lock(&fl);
1640 fl.fl_lmops = &nfsd_lease_mng_ops; 1640 fl.fl_lmops = &nfsd_lease_mng_ops;
1641 fl.fl_flags = FL_LEASE; 1641 fl.fl_flags = FL_LEASE;
1642 fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
1642 fl.fl_end = OFFSET_MAX; 1643 fl.fl_end = OFFSET_MAX;
1643 fl.fl_owner = (fl_owner_t)dp; 1644 fl.fl_owner = (fl_owner_t)dp;
1644 fl.fl_file = stp->st_vfs_file; 1645 fl.fl_file = stp->st_vfs_file;
@@ -1647,8 +1648,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
1647 /* vfs_setlease checks to see if delegation should be handed out. 1648 /* vfs_setlease checks to see if delegation should be handed out.
1648 * the lock_manager callbacks fl_mylease and fl_change are used 1649 * the lock_manager callbacks fl_mylease and fl_change are used
1649 */ 1650 */
1650 if ((status = vfs_setlease(stp->st_vfs_file, 1651 if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) {
1651 flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
1652 dprintk("NFSD: setlease failed [%d], no delegation\n", status); 1652 dprintk("NFSD: setlease failed [%d], no delegation\n", status);
1653 unhash_delegation(dp); 1653 unhash_delegation(dp);
1654 flag = NFS4_OPEN_DELEGATE_NONE; 1654 flag = NFS4_OPEN_DELEGATE_NONE;
@@ -1763,10 +1763,6 @@ out:
1763 return status; 1763 return status;
1764} 1764}
1765 1765
1766static struct workqueue_struct *laundry_wq;
1767static void laundromat_main(struct work_struct *);
1768static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
1769
1770__be32 1766__be32
1771nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 1767nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1772 clientid_t *clid) 1768 clientid_t *clid)
@@ -1874,7 +1870,11 @@ nfs4_laundromat(void)
1874 return clientid_val; 1870 return clientid_val;
1875} 1871}
1876 1872
1877void 1873static struct workqueue_struct *laundry_wq;
1874static void laundromat_main(struct work_struct *);
1875static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
1876
1877static void
1878laundromat_main(struct work_struct *not_used) 1878laundromat_main(struct work_struct *not_used)
1879{ 1879{
1880 time_t t; 1880 time_t t;
@@ -1975,6 +1975,26 @@ io_during_grace_disallowed(struct inode *inode, int flags)
1975 && mandatory_lock(inode); 1975 && mandatory_lock(inode);
1976} 1976}
1977 1977
1978static int check_stateid_generation(stateid_t *in, stateid_t *ref)
1979{
1980 /* If the client sends us a stateid from the future, it's buggy: */
1981 if (in->si_generation > ref->si_generation)
1982 return nfserr_bad_stateid;
1983 /*
1984 * The following, however, can happen. For example, if the
1985 * client sends an open and some IO at the same time, the open
1986 * may bump si_generation while the IO is still in flight.
1987 * Thanks to hard links and renames, the client never knows what
1988 * file an open will affect. So it could avoid that situation
1989 * only by serializing all opens and IO from the same open
1990 * owner. To recover from the old_stateid error, the client
1991 * will just have to retry the IO:
1992 */
1993 if (in->si_generation < ref->si_generation)
1994 return nfserr_old_stateid;
1995 return nfs_ok;
1996}
1997
1978/* 1998/*
1979* Checks for stateid operations 1999* Checks for stateid operations
1980*/ 2000*/
@@ -2023,12 +2043,8 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl
2023 goto out; 2043 goto out;
2024 stidp = &stp->st_stateid; 2044 stidp = &stp->st_stateid;
2025 } 2045 }
2026 if (stateid->si_generation > stidp->si_generation) 2046 status = check_stateid_generation(stateid, stidp);
2027 goto out; 2047 if (status)
2028
2029 /* OLD STATEID */
2030 status = nfserr_old_stateid;
2031 if (stateid->si_generation < stidp->si_generation)
2032 goto out; 2048 goto out;
2033 if (stp) { 2049 if (stp) {
2034 if ((status = nfs4_check_openmode(stp,flags))) 2050 if ((status = nfs4_check_openmode(stp,flags)))
@@ -2036,7 +2052,7 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl
2036 renew_client(stp->st_stateowner->so_client); 2052 renew_client(stp->st_stateowner->so_client);
2037 if (filpp) 2053 if (filpp)
2038 *filpp = stp->st_vfs_file; 2054 *filpp = stp->st_vfs_file;
2039 } else if (dp) { 2055 } else {
2040 if ((status = nfs4_check_delegmode(dp, flags))) 2056 if ((status = nfs4_check_delegmode(dp, flags)))
2041 goto out; 2057 goto out;
2042 renew_client(dp->dl_client); 2058 renew_client(dp->dl_client);
@@ -2065,6 +2081,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
2065{ 2081{
2066 struct nfs4_stateid *stp; 2082 struct nfs4_stateid *stp;
2067 struct nfs4_stateowner *sop; 2083 struct nfs4_stateowner *sop;
2084 __be32 status;
2068 2085
2069 dprintk("NFSD: preprocess_seqid_op: seqid=%d " 2086 dprintk("NFSD: preprocess_seqid_op: seqid=%d "
2070 "stateid = (%08x/%08x/%08x/%08x)\n", seqid, 2087 "stateid = (%08x/%08x/%08x/%08x)\n", seqid,
@@ -2127,7 +2144,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
2127 } 2144 }
2128 } 2145 }
2129 2146
2130 if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { 2147 if (nfs4_check_fh(current_fh, stp)) {
2131 dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); 2148 dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
2132 return nfserr_bad_stateid; 2149 return nfserr_bad_stateid;
2133 } 2150 }
@@ -2150,15 +2167,9 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
2150 " confirmed yet!\n"); 2167 " confirmed yet!\n");
2151 return nfserr_bad_stateid; 2168 return nfserr_bad_stateid;
2152 } 2169 }
2153 if (stateid->si_generation > stp->st_stateid.si_generation) { 2170 status = check_stateid_generation(stateid, &stp->st_stateid);
2154 dprintk("NFSD: preprocess_seqid_op: future stateid?!\n"); 2171 if (status)
2155 return nfserr_bad_stateid; 2172 return status;
2156 }
2157
2158 if (stateid->si_generation < stp->st_stateid.si_generation) {
2159 dprintk("NFSD: preprocess_seqid_op: old stateid!\n");
2160 return nfserr_old_stateid;
2161 }
2162 renew_client(sop->so_client); 2173 renew_client(sop->so_client);
2163 return nfs_ok; 2174 return nfs_ok;
2164 2175
@@ -2194,7 +2205,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2194 2205
2195 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2206 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2196 oc->oc_seqid, &oc->oc_req_stateid, 2207 oc->oc_seqid, &oc->oc_req_stateid,
2197 CHECK_FH | CONFIRM | OPEN_STATE, 2208 CONFIRM | OPEN_STATE,
2198 &oc->oc_stateowner, &stp, NULL))) 2209 &oc->oc_stateowner, &stp, NULL)))
2199 goto out; 2210 goto out;
2200 2211
@@ -2265,7 +2276,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
2265 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2276 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2266 od->od_seqid, 2277 od->od_seqid,
2267 &od->od_stateid, 2278 &od->od_stateid,
2268 CHECK_FH | OPEN_STATE, 2279 OPEN_STATE,
2269 &od->od_stateowner, &stp, NULL))) 2280 &od->od_stateowner, &stp, NULL)))
2270 goto out; 2281 goto out;
2271 2282
@@ -2318,7 +2329,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2318 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2329 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2319 close->cl_seqid, 2330 close->cl_seqid,
2320 &close->cl_stateid, 2331 &close->cl_stateid,
2321 CHECK_FH | OPEN_STATE | CLOSE_STATE, 2332 OPEN_STATE | CLOSE_STATE,
2322 &close->cl_stateowner, &stp, NULL))) 2333 &close->cl_stateowner, &stp, NULL)))
2323 goto out; 2334 goto out;
2324 status = nfs_ok; 2335 status = nfs_ok;
@@ -2623,7 +2634,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2623 status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2634 status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2624 lock->lk_new_open_seqid, 2635 lock->lk_new_open_seqid,
2625 &lock->lk_new_open_stateid, 2636 &lock->lk_new_open_stateid,
2626 CHECK_FH | OPEN_STATE, 2637 OPEN_STATE,
2627 &lock->lk_replay_owner, &open_stp, 2638 &lock->lk_replay_owner, &open_stp,
2628 lock); 2639 lock);
2629 if (status) 2640 if (status)
@@ -2650,7 +2661,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2650 status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2661 status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2651 lock->lk_old_lock_seqid, 2662 lock->lk_old_lock_seqid,
2652 &lock->lk_old_lock_stateid, 2663 &lock->lk_old_lock_stateid,
2653 CHECK_FH | LOCK_STATE, 2664 LOCK_STATE,
2654 &lock->lk_replay_owner, &lock_stp, lock); 2665 &lock->lk_replay_owner, &lock_stp, lock);
2655 if (status) 2666 if (status)
2656 goto out; 2667 goto out;
@@ -2847,7 +2858,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2847 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, 2858 if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh,
2848 locku->lu_seqid, 2859 locku->lu_seqid,
2849 &locku->lu_stateid, 2860 &locku->lu_stateid,
2850 CHECK_FH | LOCK_STATE, 2861 LOCK_STATE,
2851 &locku->lu_stateowner, &stp, NULL))) 2862 &locku->lu_stateowner, &stp, NULL)))
2852 goto out; 2863 goto out;
2853 2864
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 0e6a179eccaf..1ba7ad981935 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1867,6 +1867,15 @@ out_serverfault:
1867 goto out; 1867 goto out;
1868} 1868}
1869 1869
1870static inline int attributes_need_mount(u32 *bmval)
1871{
1872 if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME))
1873 return 1;
1874 if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID)
1875 return 1;
1876 return 0;
1877}
1878
1870static __be32 1879static __be32
1871nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, 1880nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1872 const char *name, int namlen, __be32 *p, int *buflen) 1881 const char *name, int namlen, __be32 *p, int *buflen)
@@ -1888,9 +1897,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1888 * we will not follow the cross mount and will fill the attribtutes 1897 * we will not follow the cross mount and will fill the attribtutes
1889 * directly from the mountpoint dentry. 1898 * directly from the mountpoint dentry.
1890 */ 1899 */
1891 if (d_mountpoint(dentry) && 1900 if (d_mountpoint(dentry) && !attributes_need_mount(cd->rd_bmval))
1892 (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 &&
1893 (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0)
1894 ignore_crossmnt = 1; 1901 ignore_crossmnt = 1;
1895 else if (d_mountpoint(dentry)) { 1902 else if (d_mountpoint(dentry)) {
1896 int err; 1903 int err;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 8516137cdbb0..613bcb8171a5 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -37,6 +37,7 @@
37#include <linux/nfsd/syscall.h> 37#include <linux/nfsd/syscall.h>
38 38
39#include <asm/uaccess.h> 39#include <asm/uaccess.h>
40#include <net/ipv6.h>
40 41
41/* 42/*
42 * We have a single directory with 9 nodes in it. 43 * We have a single directory with 9 nodes in it.
@@ -149,7 +150,6 @@ static const struct file_operations transaction_ops = {
149 .release = simple_transaction_release, 150 .release = simple_transaction_release,
150}; 151};
151 152
152extern struct seq_operations nfs_exports_op;
153static int exports_open(struct inode *inode, struct file *file) 153static int exports_open(struct inode *inode, struct file *file)
154{ 154{
155 return seq_open(file, &nfs_exports_op); 155 return seq_open(file, &nfs_exports_op);
@@ -222,6 +222,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
222 struct auth_domain *clp; 222 struct auth_domain *clp;
223 int err = 0; 223 int err = 0;
224 struct knfsd_fh *res; 224 struct knfsd_fh *res;
225 struct in6_addr in6;
225 226
226 if (size < sizeof(*data)) 227 if (size < sizeof(*data))
227 return -EINVAL; 228 return -EINVAL;
@@ -236,7 +237,11 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
236 res = (struct knfsd_fh*)buf; 237 res = (struct knfsd_fh*)buf;
237 238
238 exp_readlock(); 239 exp_readlock();
239 if (!(clp = auth_unix_lookup(sin->sin_addr))) 240
241 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
242
243 clp = auth_unix_lookup(&in6);
244 if (!clp)
240 err = -EPERM; 245 err = -EPERM;
241 else { 246 else {
242 err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); 247 err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
@@ -257,6 +262,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
257 int err = 0; 262 int err = 0;
258 struct knfsd_fh fh; 263 struct knfsd_fh fh;
259 char *res; 264 char *res;
265 struct in6_addr in6;
260 266
261 if (size < sizeof(*data)) 267 if (size < sizeof(*data))
262 return -EINVAL; 268 return -EINVAL;
@@ -271,7 +277,11 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size)
271 res = buf; 277 res = buf;
272 sin = (struct sockaddr_in *)&data->gd_addr; 278 sin = (struct sockaddr_in *)&data->gd_addr;
273 exp_readlock(); 279 exp_readlock();
274 if (!(clp = auth_unix_lookup(sin->sin_addr))) 280
281 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6);
282
283 clp = auth_unix_lookup(&in6);
284 if (!clp)
275 err = -EPERM; 285 err = -EPERM;
276 else { 286 else {
277 err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); 287 err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
@@ -347,8 +357,6 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
347 return mesg - buf; 357 return mesg - buf;
348} 358}
349 359
350extern int nfsd_nrthreads(void);
351
352static ssize_t write_threads(struct file *file, char *buf, size_t size) 360static ssize_t write_threads(struct file *file, char *buf, size_t size)
353{ 361{
354 /* if size > 0, look for a number of threads and call nfsd_svc 362 /* if size > 0, look for a number of threads and call nfsd_svc
@@ -371,10 +379,6 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
371 return strlen(buf); 379 return strlen(buf);
372} 380}
373 381
374extern int nfsd_nrpools(void);
375extern int nfsd_get_nrthreads(int n, int *);
376extern int nfsd_set_nrthreads(int n, int *);
377
378static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) 382static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
379{ 383{
380 /* if size > 0, look for an array of number of threads per node 384 /* if size > 0, look for an array of number of threads per node
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 3e6b3f41ee1f..100ae5641162 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -113,6 +113,124 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
113} 113}
114 114
115/* 115/*
116 * Use the given filehandle to look up the corresponding export and
117 * dentry. On success, the results are used to set fh_export and
118 * fh_dentry.
119 */
120static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
121{
122 struct knfsd_fh *fh = &fhp->fh_handle;
123 struct fid *fid = NULL, sfid;
124 struct svc_export *exp;
125 struct dentry *dentry;
126 int fileid_type;
127 int data_left = fh->fh_size/4;
128 __be32 error;
129
130 error = nfserr_stale;
131 if (rqstp->rq_vers > 2)
132 error = nfserr_badhandle;
133 if (rqstp->rq_vers == 4 && fh->fh_size == 0)
134 return nfserr_nofilehandle;
135
136 if (fh->fh_version == 1) {
137 int len;
138
139 if (--data_left < 0)
140 return error;
141 if (fh->fh_auth_type != 0)
142 return error;
143 len = key_len(fh->fh_fsid_type) / 4;
144 if (len == 0)
145 return error;
146 if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
147 /* deprecated, convert to type 3 */
148 len = key_len(FSID_ENCODE_DEV)/4;
149 fh->fh_fsid_type = FSID_ENCODE_DEV;
150 fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
151 fh->fh_fsid[1] = fh->fh_fsid[2];
152 }
153 data_left -= len;
154 if (data_left < 0)
155 return error;
156 exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_auth);
157 fid = (struct fid *)(fh->fh_auth + len);
158 } else {
159 __u32 tfh[2];
160 dev_t xdev;
161 ino_t xino;
162
163 if (fh->fh_size != NFS_FHSIZE)
164 return error;
165 /* assume old filehandle format */
166 xdev = old_decode_dev(fh->ofh_xdev);
167 xino = u32_to_ino_t(fh->ofh_xino);
168 mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
169 exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
170 }
171
172 error = nfserr_stale;
173 if (PTR_ERR(exp) == -ENOENT)
174 return error;
175
176 if (IS_ERR(exp))
177 return nfserrno(PTR_ERR(exp));
178
179 error = nfsd_setuser_and_check_port(rqstp, exp);
180 if (error)
181 goto out;
182
183 /*
184 * Look up the dentry using the NFS file handle.
185 */
186 error = nfserr_stale;
187 if (rqstp->rq_vers > 2)
188 error = nfserr_badhandle;
189
190 if (fh->fh_version != 1) {
191 sfid.i32.ino = fh->ofh_ino;
192 sfid.i32.gen = fh->ofh_generation;
193 sfid.i32.parent_ino = fh->ofh_dirino;
194 fid = &sfid;
195 data_left = 3;
196 if (fh->ofh_dirino == 0)
197 fileid_type = FILEID_INO32_GEN;
198 else
199 fileid_type = FILEID_INO32_GEN_PARENT;
200 } else
201 fileid_type = fh->fh_fileid_type;
202
203 if (fileid_type == FILEID_ROOT)
204 dentry = dget(exp->ex_path.dentry);
205 else {
206 dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
207 data_left, fileid_type,
208 nfsd_acceptable, exp);
209 }
210 if (dentry == NULL)
211 goto out;
212 if (IS_ERR(dentry)) {
213 if (PTR_ERR(dentry) != -EINVAL)
214 error = nfserrno(PTR_ERR(dentry));
215 goto out;
216 }
217
218 if (S_ISDIR(dentry->d_inode->i_mode) &&
219 (dentry->d_flags & DCACHE_DISCONNECTED)) {
220 printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
221 dentry->d_parent->d_name.name, dentry->d_name.name);
222 }
223
224 fhp->fh_dentry = dentry;
225 fhp->fh_export = exp;
226 nfsd_nr_verified++;
227 return 0;
228out:
229 exp_put(exp);
230 return error;
231}
232
233/*
116 * Perform sanity checks on the dentry in a client's file handle. 234 * Perform sanity checks on the dentry in a client's file handle.
117 * 235 *
118 * Note that the file handle dentry may need to be freed even after 236 * Note that the file handle dentry may need to be freed even after
@@ -124,115 +242,18 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
124__be32 242__be32
125fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) 243fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
126{ 244{
127 struct knfsd_fh *fh = &fhp->fh_handle; 245 struct svc_export *exp;
128 struct svc_export *exp = NULL;
129 struct dentry *dentry; 246 struct dentry *dentry;
130 __be32 error = 0; 247 __be32 error;
131 248
132 dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); 249 dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
133 250
134 if (!fhp->fh_dentry) { 251 if (!fhp->fh_dentry) {
135 struct fid *fid = NULL, sfid; 252 error = nfsd_set_fh_dentry(rqstp, fhp);
136 int fileid_type;
137 int data_left = fh->fh_size/4;
138
139 error = nfserr_stale;
140 if (rqstp->rq_vers > 2)
141 error = nfserr_badhandle;
142 if (rqstp->rq_vers == 4 && fh->fh_size == 0)
143 return nfserr_nofilehandle;
144
145 if (fh->fh_version == 1) {
146 int len;
147 if (--data_left<0) goto out;
148 switch (fh->fh_auth_type) {
149 case 0: break;
150 default: goto out;
151 }
152 len = key_len(fh->fh_fsid_type) / 4;
153 if (len == 0) goto out;
154 if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
155 /* deprecated, convert to type 3 */
156 len = key_len(FSID_ENCODE_DEV)/4;
157 fh->fh_fsid_type = FSID_ENCODE_DEV;
158 fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
159 fh->fh_fsid[1] = fh->fh_fsid[2];
160 }
161 if ((data_left -= len)<0) goto out;
162 exp = rqst_exp_find(rqstp, fh->fh_fsid_type,
163 fh->fh_auth);
164 fid = (struct fid *)(fh->fh_auth + len);
165 } else {
166 __u32 tfh[2];
167 dev_t xdev;
168 ino_t xino;
169 if (fh->fh_size != NFS_FHSIZE)
170 goto out;
171 /* assume old filehandle format */
172 xdev = old_decode_dev(fh->ofh_xdev);
173 xino = u32_to_ino_t(fh->ofh_xino);
174 mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
175 exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
176 }
177
178 error = nfserr_stale;
179 if (PTR_ERR(exp) == -ENOENT)
180 goto out;
181
182 if (IS_ERR(exp)) {
183 error = nfserrno(PTR_ERR(exp));
184 goto out;
185 }
186
187 error = nfsd_setuser_and_check_port(rqstp, exp);
188 if (error) 253 if (error)
189 goto out; 254 goto out;
190 255 dentry = fhp->fh_dentry;
191 /* 256 exp = fhp->fh_export;
192 * Look up the dentry using the NFS file handle.
193 */
194 error = nfserr_stale;
195 if (rqstp->rq_vers > 2)
196 error = nfserr_badhandle;
197
198 if (fh->fh_version != 1) {
199 sfid.i32.ino = fh->ofh_ino;
200 sfid.i32.gen = fh->ofh_generation;
201 sfid.i32.parent_ino = fh->ofh_dirino;
202 fid = &sfid;
203 data_left = 3;
204 if (fh->ofh_dirino == 0)
205 fileid_type = FILEID_INO32_GEN;
206 else
207 fileid_type = FILEID_INO32_GEN_PARENT;
208 } else
209 fileid_type = fh->fh_fileid_type;
210
211 if (fileid_type == FILEID_ROOT)
212 dentry = dget(exp->ex_path.dentry);
213 else {
214 dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
215 data_left, fileid_type,
216 nfsd_acceptable, exp);
217 }
218 if (dentry == NULL)
219 goto out;
220 if (IS_ERR(dentry)) {
221 if (PTR_ERR(dentry) != -EINVAL)
222 error = nfserrno(PTR_ERR(dentry));
223 goto out;
224 }
225
226 if (S_ISDIR(dentry->d_inode->i_mode) &&
227 (dentry->d_flags & DCACHE_DISCONNECTED)) {
228 printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
229 dentry->d_parent->d_name.name, dentry->d_name.name);
230 }
231
232 fhp->fh_dentry = dentry;
233 fhp->fh_export = exp;
234 nfsd_nr_verified++;
235 cache_get(&exp->h);
236 } else { 257 } else {
237 /* 258 /*
238 * just rechecking permissions 259 * just rechecking permissions
@@ -242,7 +263,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
242 dprintk("nfsd: fh_verify - just checking\n"); 263 dprintk("nfsd: fh_verify - just checking\n");
243 dentry = fhp->fh_dentry; 264 dentry = fhp->fh_dentry;
244 exp = fhp->fh_export; 265 exp = fhp->fh_export;
245 cache_get(&exp->h);
246 /* 266 /*
247 * Set user creds for this exportpoint; necessary even 267 * Set user creds for this exportpoint; necessary even
248 * in the "just checking" case because this may be a 268 * in the "just checking" case because this may be a
@@ -281,8 +301,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
281 access, ntohl(error)); 301 access, ntohl(error));
282 } 302 }
283out: 303out:
284 if (exp && !IS_ERR(exp))
285 exp_put(exp);
286 if (error == nfserr_stale) 304 if (error == nfserr_stale)
287 nfsdstats.fh_stale++; 305 nfsdstats.fh_stale++;
288 return error; 306 return error;
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 9647b0f7bc0c..941041f4b136 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -244,7 +244,6 @@ static int nfsd_init_socks(int port)
244 if (error < 0) 244 if (error < 0)
245 return error; 245 return error;
246 246
247#ifdef CONFIG_NFSD_TCP
248 error = lockd_up(IPPROTO_TCP); 247 error = lockd_up(IPPROTO_TCP);
249 if (error >= 0) { 248 if (error >= 0) {
250 error = svc_create_xprt(nfsd_serv, "tcp", port, 249 error = svc_create_xprt(nfsd_serv, "tcp", port,
@@ -254,7 +253,6 @@ static int nfsd_init_socks(int port)
254 } 253 }
255 if (error < 0) 254 if (error < 0)
256 return error; 255 return error;
257#endif
258 return 0; 256 return 0;
259} 257}
260 258
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 304bf5f643c9..a3a291f771f4 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -264,7 +264,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
264 struct inode *inode; 264 struct inode *inode;
265 int accmode = MAY_SATTR; 265 int accmode = MAY_SATTR;
266 int ftype = 0; 266 int ftype = 0;
267 int imode;
268 __be32 err; 267 __be32 err;
269 int host_err; 268 int host_err;
270 int size_change = 0; 269 int size_change = 0;
@@ -360,25 +359,25 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
360 DQUOT_INIT(inode); 359 DQUOT_INIT(inode);
361 } 360 }
362 361
363 imode = inode->i_mode; 362 /* sanitize the mode change */
364 if (iap->ia_valid & ATTR_MODE) { 363 if (iap->ia_valid & ATTR_MODE) {
365 iap->ia_mode &= S_IALLUGO; 364 iap->ia_mode &= S_IALLUGO;
366 imode = iap->ia_mode |= (imode & ~S_IALLUGO); 365 iap->ia_mode |= (inode->i_mode & ~S_IALLUGO);
367 /* if changing uid/gid revoke setuid/setgid in mode */ 366 }
368 if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) { 367
369 iap->ia_valid |= ATTR_KILL_PRIV; 368 /* Revoke setuid/setgid on chown */
369 if (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) ||
370 ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)) {
371 iap->ia_valid |= ATTR_KILL_PRIV;
372 if (iap->ia_valid & ATTR_MODE) {
373 /* we're setting mode too, just clear the s*id bits */
370 iap->ia_mode &= ~S_ISUID; 374 iap->ia_mode &= ~S_ISUID;
375 if (iap->ia_mode & S_IXGRP)
376 iap->ia_mode &= ~S_ISGID;
377 } else {
378 /* set ATTR_KILL_* bits and let VFS handle it */
379 iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID);
371 } 380 }
372 if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)
373 iap->ia_mode &= ~S_ISGID;
374 } else {
375 /*
376 * Revoke setuid/setgid bit on chown/chgrp
377 */
378 if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid)
379 iap->ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV;
380 if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)
381 iap->ia_valid |= ATTR_KILL_SGID;
382 } 381 }
383 382
384 /* Change the attributes. */ 383 /* Change the attributes. */
@@ -988,7 +987,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
988 * flushing the data to disk is handled separately below. 987 * flushing the data to disk is handled separately below.
989 */ 988 */
990 989
991 if (file->f_op->fsync == 0) {/* COMMIT3 cannot work */ 990 if (!file->f_op->fsync) {/* COMMIT3 cannot work */
992 stable = 2; 991 stable = 2;
993 *stablep = 2; /* FILE_SYNC */ 992 *stablep = 2; /* FILE_SYNC */
994 } 993 }
@@ -1152,7 +1151,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
1152} 1151}
1153#endif /* CONFIG_NFSD_V3 */ 1152#endif /* CONFIG_NFSD_V3 */
1154 1153
1155__be32 1154static __be32
1156nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, 1155nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
1157 struct iattr *iap) 1156 struct iattr *iap)
1158{ 1157{