aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/nfs/nfs41-server.txt5
-rw-r--r--fs/lockd/host.c2
-rw-r--r--fs/lockd/mon.c12
-rw-r--r--fs/lockd/svc.c2
-rw-r--r--fs/nfs/callback.c2
-rw-r--r--fs/nfsd/nfs4callback.c5
-rw-r--r--fs/nfsd/nfs4recover.c4
-rw-r--r--fs/nfsd/nfs4state.c4
-rw-r--r--fs/nfsd/nfs4xdr.c2
-rw-r--r--fs/nfsd/nfsctl.c24
-rw-r--r--fs/nfsd/vfs.c153
-rw-r--r--fs/xfs/linux-2.6/xfs_export.c20
-rw-r--r--include/linux/exportfs.h5
-rw-r--r--net/sunrpc/svc_xprt.c27
-rw-r--r--net/sunrpc/svcauth_unix.c49
-rw-r--r--net/sunrpc/svcsock.c3
16 files changed, 174 insertions, 145 deletions
diff --git a/Documentation/filesystems/nfs/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt
index 1bd0d0c05171..6a53a84afc72 100644
--- a/Documentation/filesystems/nfs/nfs41-server.txt
+++ b/Documentation/filesystems/nfs/nfs41-server.txt
@@ -17,8 +17,7 @@ kernels must turn 4.1 on or off *before* turning support for version 4
17on or off; rpc.nfsd does this correctly.) 17on or off; rpc.nfsd does this correctly.)
18 18
19The NFSv4 minorversion 1 (NFSv4.1) implementation in nfsd is based 19The NFSv4 minorversion 1 (NFSv4.1) implementation in nfsd is based
20on the latest NFSv4.1 Internet Draft: 20on RFC 5661.
21http://tools.ietf.org/html/draft-ietf-nfsv4-minorversion1-29
22 21
23From the many new features in NFSv4.1 the current implementation 22From the many new features in NFSv4.1 the current implementation
24focuses on the mandatory-to-implement NFSv4.1 Sessions, providing 23focuses on the mandatory-to-implement NFSv4.1 Sessions, providing
@@ -44,7 +43,7 @@ interoperability problems with future clients. Known issues:
44 trunking, but this is a mandatory feature, and its use is 43 trunking, but this is a mandatory feature, and its use is
45 recommended to clients in a number of places. (E.g. to ensure 44 recommended to clients in a number of places. (E.g. to ensure
46 timely renewal in case an existing connection's retry timeouts 45 timely renewal in case an existing connection's retry timeouts
47 have gotten too long; see section 8.3 of the draft.) 46 have gotten too long; see section 8.3 of the RFC.)
48 Therefore, lack of this feature may cause future clients to 47 Therefore, lack of this feature may cause future clients to
49 fail. 48 fail.
50 - Incomplete backchannel support: incomplete backchannel gss 49 - Incomplete backchannel support: incomplete backchannel gss
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 4600c2037b8b..bb464d12104c 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -479,8 +479,8 @@ again: mutex_lock(&nlm_host_mutex);
479 } 479 }
480 } 480 }
481 } 481 }
482
483 mutex_unlock(&nlm_host_mutex); 482 mutex_unlock(&nlm_host_mutex);
483 nsm_release(nsm);
484} 484}
485 485
486/* 486/*
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index f956651d0f65..fefa4df3f005 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -349,9 +349,9 @@ retry:
349 * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle 349 * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle
350 * @info: pointer to NLMPROC_SM_NOTIFY arguments 350 * @info: pointer to NLMPROC_SM_NOTIFY arguments
351 * 351 *
352 * Returns a matching nsm_handle if found in the nsm cache; the returned 352 * Returns a matching nsm_handle if found in the nsm cache. The returned
353 * nsm_handle's reference count is bumped and sm_monitored is cleared. 353 * nsm_handle's reference count is bumped. Otherwise returns NULL if some
354 * Otherwise returns NULL if some error occurred. 354 * error occurred.
355 */ 355 */
356struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info) 356struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
357{ 357{
@@ -370,12 +370,6 @@ struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
370 atomic_inc(&cached->sm_count); 370 atomic_inc(&cached->sm_count);
371 spin_unlock(&nsm_lock); 371 spin_unlock(&nsm_lock);
372 372
373 /*
374 * During subsequent lock activity, force a fresh
375 * notification to be set up for this host.
376 */
377 cached->sm_monitored = 0;
378
379 dprintk("lockd: host %s (%s) rebooted, cnt %d\n", 373 dprintk("lockd: host %s (%s) rebooted, cnt %d\n",
380 cached->sm_name, cached->sm_addrbuf, 374 cached->sm_name, cached->sm_addrbuf,
381 atomic_read(&cached->sm_count)); 375 atomic_read(&cached->sm_count));
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index e50cfa3d9654..7d150517ddf0 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -243,11 +243,9 @@ static int make_socks(struct svc_serv *serv)
243 if (err < 0) 243 if (err < 0)
244 goto out_err; 244 goto out_err;
245 245
246#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
247 err = create_lockd_family(serv, PF_INET6); 246 err = create_lockd_family(serv, PF_INET6);
248 if (err < 0 && err != -EAFNOSUPPORT) 247 if (err < 0 && err != -EAFNOSUPPORT)
249 goto out_err; 248 goto out_err;
250#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */
251 249
252 warned = 0; 250 warned = 0;
253 return 0; 251 return 0;
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 73ab220354df..36dfdae95123 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -118,7 +118,6 @@ nfs4_callback_up(struct svc_serv *serv)
118 dprintk("NFS: Callback listener port = %u (af %u)\n", 118 dprintk("NFS: Callback listener port = %u (af %u)\n",
119 nfs_callback_tcpport, PF_INET); 119 nfs_callback_tcpport, PF_INET);
120 120
121#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
122 ret = svc_create_xprt(serv, "tcp", PF_INET6, 121 ret = svc_create_xprt(serv, "tcp", PF_INET6,
123 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); 122 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
124 if (ret > 0) { 123 if (ret > 0) {
@@ -129,7 +128,6 @@ nfs4_callback_up(struct svc_serv *serv)
129 ret = 0; 128 ret = 0;
130 else 129 else
131 goto out_err; 130 goto out_err;
132#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
133 131
134 return svc_prepare_thread(serv, &serv->sv_pools[0]); 132 return svc_prepare_thread(serv, &serv->sv_pools[0]);
135 133
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index c6eed2a3b093..4bc22c763de7 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -525,6 +525,8 @@ static struct rpc_cred *callback_cred;
525 525
526int set_callback_cred(void) 526int set_callback_cred(void)
527{ 527{
528 if (callback_cred)
529 return 0;
528 callback_cred = rpc_lookup_machine_cred(); 530 callback_cred = rpc_lookup_machine_cred();
529 if (!callback_cred) 531 if (!callback_cred)
530 return -ENOMEM; 532 return -ENOMEM;
@@ -542,7 +544,8 @@ void do_probe_callback(struct nfs4_client *clp)
542 }; 544 };
543 int status; 545 int status;
544 546
545 status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT, 547 status = rpc_call_async(cb->cb_client, &msg,
548 RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
546 &nfsd4_cb_probe_ops, (void *)clp); 549 &nfsd4_cb_probe_ops, (void *)clp);
547 if (status) { 550 if (status) {
548 warn_no_callback_path(clp, status); 551 warn_no_callback_path(clp, status);
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 5a754f7b71ed..98fb98e330b4 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -119,9 +119,7 @@ out_no_tfm:
119static void 119static void
120nfsd4_sync_rec_dir(void) 120nfsd4_sync_rec_dir(void)
121{ 121{
122 mutex_lock(&rec_dir.dentry->d_inode->i_mutex); 122 vfs_fsync(NULL, rec_dir.dentry, 0);
123 nfsd_sync_dir(rec_dir.dentry);
124 mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
125} 123}
126 124
127int 125int
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index fcafe6087f69..c97fddbd17db 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2482,8 +2482,10 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
2482 } 2482 }
2483 memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); 2483 memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));
2484 2484
2485 if (nfsd4_has_session(&resp->cstate)) 2485 if (nfsd4_has_session(&resp->cstate)) {
2486 open->op_stateowner->so_confirmed = 1; 2486 open->op_stateowner->so_confirmed = 1;
2487 nfsd4_create_clid_dir(open->op_stateowner->so_client);
2488 }
2487 2489
2488 /* 2490 /*
2489 * Attempt to hand out a delegation. No error return, because the 2491 * Attempt to hand out a delegation. No error return, because the
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index bbf72d8f9fc0..78c7e24e5129 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1434,7 +1434,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1434 } 1434 }
1435 op->opnum = ntohl(*argp->p++); 1435 op->opnum = ntohl(*argp->p++);
1436 1436
1437 if (op->opnum >= OP_ACCESS && op->opnum < ops->nops) 1437 if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP)
1438 op->status = ops->decoders[op->opnum](argp, &op->u); 1438 op->status = ops->decoders[op->opnum](argp, &op->u);
1439 else { 1439 else {
1440 op->opnum = OP_ILLEGAL; 1440 op->opnum = OP_ILLEGAL;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 2604c3e70ea5..0f0e77f2012f 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -988,6 +988,7 @@ static ssize_t __write_ports_delfd(char *buf)
988static ssize_t __write_ports_addxprt(char *buf) 988static ssize_t __write_ports_addxprt(char *buf)
989{ 989{
990 char transport[16]; 990 char transport[16];
991 struct svc_xprt *xprt;
991 int port, err; 992 int port, err;
992 993
993 if (sscanf(buf, "%15s %4u", transport, &port) != 2) 994 if (sscanf(buf, "%15s %4u", transport, &port) != 2)
@@ -1002,13 +1003,24 @@ static ssize_t __write_ports_addxprt(char *buf)
1002 1003
1003 err = svc_create_xprt(nfsd_serv, transport, 1004 err = svc_create_xprt(nfsd_serv, transport,
1004 PF_INET, port, SVC_SOCK_ANONYMOUS); 1005 PF_INET, port, SVC_SOCK_ANONYMOUS);
1005 if (err < 0) { 1006 if (err < 0)
1006 /* Give a reasonable perror msg for bad transport string */ 1007 goto out_err;
1007 if (err == -ENOENT) 1008
1008 err = -EPROTONOSUPPORT; 1009 err = svc_create_xprt(nfsd_serv, transport,
1009 return err; 1010 PF_INET6, port, SVC_SOCK_ANONYMOUS);
1010 } 1011 if (err < 0 && err != -EAFNOSUPPORT)
1012 goto out_close;
1011 return 0; 1013 return 0;
1014out_close:
1015 xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
1016 if (xprt != NULL) {
1017 svc_close_xprt(xprt);
1018 svc_xprt_put(xprt);
1019 }
1020out_err:
1021 /* Decrease the count, but don't shut down the service */
1022 nfsd_serv->sv_nrthreads--;
1023 return err;
1012} 1024}
1013 1025
1014/* 1026/*
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 8eca17df4f63..a11b0e8678ee 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -26,6 +26,8 @@
26#include <linux/jhash.h> 26#include <linux/jhash.h>
27#include <linux/ima.h> 27#include <linux/ima.h>
28#include <asm/uaccess.h> 28#include <asm/uaccess.h>
29#include <linux/exportfs.h>
30#include <linux/writeback.h>
29 31
30#ifdef CONFIG_NFSD_V3 32#ifdef CONFIG_NFSD_V3
31#include "xdr3.h" 33#include "xdr3.h"
@@ -270,6 +272,32 @@ out:
270 return err; 272 return err;
271} 273}
272 274
275/*
276 * Commit metadata changes to stable storage.
277 */
278static int
279commit_metadata(struct svc_fh *fhp)
280{
281 struct inode *inode = fhp->fh_dentry->d_inode;
282 const struct export_operations *export_ops = inode->i_sb->s_export_op;
283 int error = 0;
284
285 if (!EX_ISSYNC(fhp->fh_export))
286 return 0;
287
288 if (export_ops->commit_metadata) {
289 error = export_ops->commit_metadata(inode);
290 } else {
291 struct writeback_control wbc = {
292 .sync_mode = WB_SYNC_ALL,
293 .nr_to_write = 0, /* metadata only */
294 };
295
296 error = sync_inode(inode, &wbc);
297 }
298
299 return error;
300}
273 301
274/* 302/*
275 * Set various file attributes. 303 * Set various file attributes.
@@ -767,43 +795,6 @@ nfsd_close(struct file *filp)
767} 795}
768 796
769/* 797/*
770 * Sync a file
771 * As this calls fsync (not fdatasync) there is no need for a write_inode
772 * after it.
773 */
774static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
775 const struct file_operations *fop)
776{
777 struct inode *inode = dp->d_inode;
778 int (*fsync) (struct file *, struct dentry *, int);
779 int err;
780
781 err = filemap_write_and_wait(inode->i_mapping);
782 if (err == 0 && fop && (fsync = fop->fsync))
783 err = fsync(filp, dp, 0);
784 return err;
785}
786
787static int
788nfsd_sync(struct file *filp)
789{
790 int err;
791 struct inode *inode = filp->f_path.dentry->d_inode;
792 dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name);
793 mutex_lock(&inode->i_mutex);
794 err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op);
795 mutex_unlock(&inode->i_mutex);
796
797 return err;
798}
799
800int
801nfsd_sync_dir(struct dentry *dp)
802{
803 return nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
804}
805
806/*
807 * Obtain the readahead parameters for the file 798 * Obtain the readahead parameters for the file
808 * specified by (dev, ino). 799 * specified by (dev, ino).
809 */ 800 */
@@ -1006,7 +997,7 @@ static int wait_for_concurrent_writes(struct file *file)
1006 997
1007 if (inode->i_state & I_DIRTY) { 998 if (inode->i_state & I_DIRTY) {
1008 dprintk("nfsd: write sync %d\n", task_pid_nr(current)); 999 dprintk("nfsd: write sync %d\n", task_pid_nr(current));
1009 err = nfsd_sync(file); 1000 err = vfs_fsync(file, file->f_path.dentry, 0);
1010 } 1001 }
1011 last_ino = inode->i_ino; 1002 last_ino = inode->i_ino;
1012 last_dev = inode->i_sb->s_dev; 1003 last_dev = inode->i_sb->s_dev;
@@ -1154,8 +1145,9 @@ out:
1154#ifdef CONFIG_NFSD_V3 1145#ifdef CONFIG_NFSD_V3
1155/* 1146/*
1156 * Commit all pending writes to stable storage. 1147 * Commit all pending writes to stable storage.
1157 * Strictly speaking, we could sync just the indicated file region here, 1148 *
1158 * but there's currently no way we can ask the VFS to do so. 1149 * Note: we only guarantee that data that lies within the range specified
1150 * by the 'offset' and 'count' parameters will be synced.
1159 * 1151 *
1160 * Unfortunately we cannot lock the file to make sure we return full WCC 1152 * Unfortunately we cannot lock the file to make sure we return full WCC
1161 * data to the client, as locking happens lower down in the filesystem. 1153 * data to the client, as locking happens lower down in the filesystem.
@@ -1165,23 +1157,32 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
1165 loff_t offset, unsigned long count) 1157 loff_t offset, unsigned long count)
1166{ 1158{
1167 struct file *file; 1159 struct file *file;
1168 __be32 err; 1160 loff_t end = LLONG_MAX;
1161 __be32 err = nfserr_inval;
1169 1162
1170 if ((u64)count > ~(u64)offset) 1163 if (offset < 0)
1171 return nfserr_inval; 1164 goto out;
1165 if (count != 0) {
1166 end = offset + (loff_t)count - 1;
1167 if (end < offset)
1168 goto out;
1169 }
1172 1170
1173 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); 1171 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file);
1174 if (err) 1172 if (err)
1175 return err; 1173 goto out;
1176 if (EX_ISSYNC(fhp->fh_export)) { 1174 if (EX_ISSYNC(fhp->fh_export)) {
1177 if (file->f_op && file->f_op->fsync) { 1175 int err2 = vfs_fsync_range(file, file->f_path.dentry,
1178 err = nfserrno(nfsd_sync(file)); 1176 offset, end, 0);
1179 } else { 1177
1178 if (err2 != -EINVAL)
1179 err = nfserrno(err2);
1180 else
1180 err = nfserr_notsupp; 1181 err = nfserr_notsupp;
1181 }
1182 } 1182 }
1183 1183
1184 nfsd_close(file); 1184 nfsd_close(file);
1185out:
1185 return err; 1186 return err;
1186} 1187}
1187#endif /* CONFIG_NFSD_V3 */ 1188#endif /* CONFIG_NFSD_V3 */
@@ -1334,12 +1335,14 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
1334 goto out_nfserr; 1335 goto out_nfserr;
1335 } 1336 }
1336 1337
1337 if (EX_ISSYNC(fhp->fh_export)) { 1338 err = nfsd_create_setattr(rqstp, resfhp, iap);
1338 err = nfserrno(nfsd_sync_dir(dentry));
1339 write_inode_now(dchild->d_inode, 1);
1340 }
1341 1339
1342 err2 = nfsd_create_setattr(rqstp, resfhp, iap); 1340 /*
1341 * nfsd_setattr already committed the child. Transactional filesystems
1342 * had a chance to commit changes for both parent and child
1343 * simultaneously making the following commit_metadata a noop.
1344 */
1345 err2 = nfserrno(commit_metadata(fhp));
1343 if (err2) 1346 if (err2)
1344 err = err2; 1347 err = err2;
1345 mnt_drop_write(fhp->fh_export->ex_path.mnt); 1348 mnt_drop_write(fhp->fh_export->ex_path.mnt);
@@ -1371,7 +1374,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1371 struct dentry *dentry, *dchild = NULL; 1374 struct dentry *dentry, *dchild = NULL;
1372 struct inode *dirp; 1375 struct inode *dirp;
1373 __be32 err; 1376 __be32 err;
1374 __be32 err2;
1375 int host_err; 1377 int host_err;
1376 __u32 v_mtime=0, v_atime=0; 1378 __u32 v_mtime=0, v_atime=0;
1377 1379
@@ -1466,11 +1468,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1466 if (created) 1468 if (created)
1467 *created = 1; 1469 *created = 1;
1468 1470
1469 if (EX_ISSYNC(fhp->fh_export)) {
1470 err = nfserrno(nfsd_sync_dir(dentry));
1471 /* setattr will sync the child (or not) */
1472 }
1473
1474 nfsd_check_ignore_resizing(iap); 1471 nfsd_check_ignore_resizing(iap);
1475 1472
1476 if (createmode == NFS3_CREATE_EXCLUSIVE) { 1473 if (createmode == NFS3_CREATE_EXCLUSIVE) {
@@ -1485,9 +1482,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1485 } 1482 }
1486 1483
1487 set_attr: 1484 set_attr:
1488 err2 = nfsd_create_setattr(rqstp, resfhp, iap); 1485 err = nfsd_create_setattr(rqstp, resfhp, iap);
1489 if (err2) 1486
1490 err = err2; 1487 /*
1488 * nfsd_setattr already committed the child (and possibly also the parent).
1489 */
1490 if (!err)
1491 err = nfserrno(commit_metadata(fhp));
1491 1492
1492 mnt_drop_write(fhp->fh_export->ex_path.mnt); 1493 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1493 /* 1494 /*
@@ -1602,12 +1603,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
1602 } 1603 }
1603 } else 1604 } else
1604 host_err = vfs_symlink(dentry->d_inode, dnew, path); 1605 host_err = vfs_symlink(dentry->d_inode, dnew, path);
1605
1606 if (!host_err) {
1607 if (EX_ISSYNC(fhp->fh_export))
1608 host_err = nfsd_sync_dir(dentry);
1609 }
1610 err = nfserrno(host_err); 1606 err = nfserrno(host_err);
1607 if (!err)
1608 err = nfserrno(commit_metadata(fhp));
1611 fh_unlock(fhp); 1609 fh_unlock(fhp);
1612 1610
1613 mnt_drop_write(fhp->fh_export->ex_path.mnt); 1611 mnt_drop_write(fhp->fh_export->ex_path.mnt);
@@ -1669,11 +1667,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
1669 } 1667 }
1670 host_err = vfs_link(dold, dirp, dnew); 1668 host_err = vfs_link(dold, dirp, dnew);
1671 if (!host_err) { 1669 if (!host_err) {
1672 if (EX_ISSYNC(ffhp->fh_export)) { 1670 err = nfserrno(commit_metadata(ffhp));
1673 err = nfserrno(nfsd_sync_dir(ddir)); 1671 if (!err)
1674 write_inode_now(dest, 1); 1672 err = nfserrno(commit_metadata(tfhp));
1675 }
1676 err = 0;
1677 } else { 1673 } else {
1678 if (host_err == -EXDEV && rqstp->rq_vers == 2) 1674 if (host_err == -EXDEV && rqstp->rq_vers == 2)
1679 err = nfserr_acces; 1675 err = nfserr_acces;
@@ -1769,10 +1765,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
1769 goto out_dput_new; 1765 goto out_dput_new;
1770 1766
1771 host_err = vfs_rename(fdir, odentry, tdir, ndentry); 1767 host_err = vfs_rename(fdir, odentry, tdir, ndentry);
1772 if (!host_err && EX_ISSYNC(tfhp->fh_export)) { 1768 if (!host_err) {
1773 host_err = nfsd_sync_dir(tdentry); 1769 host_err = commit_metadata(tfhp);
1774 if (!host_err) 1770 if (!host_err)
1775 host_err = nfsd_sync_dir(fdentry); 1771 host_err = commit_metadata(ffhp);
1776 } 1772 }
1777 1773
1778 mnt_drop_write(ffhp->fh_export->ex_path.mnt); 1774 mnt_drop_write(ffhp->fh_export->ex_path.mnt);
@@ -1853,12 +1849,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
1853 1849
1854 dput(rdentry); 1850 dput(rdentry);
1855 1851
1856 if (host_err) 1852 if (!host_err)
1857 goto out_drop; 1853 host_err = commit_metadata(fhp);
1858 if (EX_ISSYNC(fhp->fh_export))
1859 host_err = nfsd_sync_dir(dentry);
1860 1854
1861out_drop:
1862 mnt_drop_write(fhp->fh_export->ex_path.mnt); 1855 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1863out_nfserr: 1856out_nfserr:
1864 err = nfserrno(host_err); 1857 err = nfserrno(host_err);
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
index 87b8cbd23d4b..846b75aeb2ab 100644
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/linux-2.6/xfs_export.c
@@ -29,6 +29,7 @@
29#include "xfs_vnodeops.h" 29#include "xfs_vnodeops.h"
30#include "xfs_bmap_btree.h" 30#include "xfs_bmap_btree.h"
31#include "xfs_inode.h" 31#include "xfs_inode.h"
32#include "xfs_inode_item.h"
32 33
33/* 34/*
34 * Note that we only accept fileids which are long enough rather than allow 35 * Note that we only accept fileids which are long enough rather than allow
@@ -215,9 +216,28 @@ xfs_fs_get_parent(
215 return d_obtain_alias(VFS_I(cip)); 216 return d_obtain_alias(VFS_I(cip));
216} 217}
217 218
219STATIC int
220xfs_fs_nfs_commit_metadata(
221 struct inode *inode)
222{
223 struct xfs_inode *ip = XFS_I(inode);
224 struct xfs_mount *mp = ip->i_mount;
225 int error = 0;
226
227 xfs_ilock(ip, XFS_ILOCK_SHARED);
228 if (xfs_ipincount(ip)) {
229 error = _xfs_log_force_lsn(mp, ip->i_itemp->ili_last_lsn,
230 XFS_LOG_SYNC, NULL);
231 }
232 xfs_iunlock(ip, XFS_ILOCK_SHARED);
233
234 return error;
235}
236
218const struct export_operations xfs_export_operations = { 237const struct export_operations xfs_export_operations = {
219 .encode_fh = xfs_fs_encode_fh, 238 .encode_fh = xfs_fs_encode_fh,
220 .fh_to_dentry = xfs_fs_fh_to_dentry, 239 .fh_to_dentry = xfs_fs_fh_to_dentry,
221 .fh_to_parent = xfs_fs_fh_to_parent, 240 .fh_to_parent = xfs_fs_fh_to_parent,
222 .get_parent = xfs_fs_get_parent, 241 .get_parent = xfs_fs_get_parent,
242 .commit_metadata = xfs_fs_nfs_commit_metadata,
223}; 243};
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index dc12f416a49f..a9cd507f8cd2 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -96,6 +96,7 @@ struct fid {
96 * @fh_to_parent: find the implied object's parent and get a dentry for it 96 * @fh_to_parent: find the implied object's parent and get a dentry for it
97 * @get_name: find the name for a given inode in a given directory 97 * @get_name: find the name for a given inode in a given directory
98 * @get_parent: find the parent of a given directory 98 * @get_parent: find the parent of a given directory
99 * @commit_metadata: commit metadata changes to stable storage
99 * 100 *
100 * See Documentation/filesystems/nfs/Exporting for details on how to use 101 * See Documentation/filesystems/nfs/Exporting for details on how to use
101 * this interface correctly. 102 * this interface correctly.
@@ -137,6 +138,9 @@ struct fid {
137 * is also a directory. In the event that it cannot be found, or storage 138 * is also a directory. In the event that it cannot be found, or storage
138 * space cannot be allocated, a %ERR_PTR should be returned. 139 * space cannot be allocated, a %ERR_PTR should be returned.
139 * 140 *
141 * commit_metadata:
142 * @commit_metadata should commit metadata changes to stable storage.
143 *
140 * Locking rules: 144 * Locking rules:
141 * get_parent is called with child->d_inode->i_mutex down 145 * get_parent is called with child->d_inode->i_mutex down
142 * get_name is not (which is possibly inconsistent) 146 * get_name is not (which is possibly inconsistent)
@@ -152,6 +156,7 @@ struct export_operations {
152 int (*get_name)(struct dentry *parent, char *name, 156 int (*get_name)(struct dentry *parent, char *name,
153 struct dentry *child); 157 struct dentry *child);
154 struct dentry * (*get_parent)(struct dentry *child); 158 struct dentry * (*get_parent)(struct dentry *child);
159 int (*commit_metadata)(struct inode *inode);
155}; 160};
156 161
157extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, 162extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 7d1f9e928f69..8f0f1fb3dc52 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -173,11 +173,13 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
173 .sin_addr.s_addr = htonl(INADDR_ANY), 173 .sin_addr.s_addr = htonl(INADDR_ANY),
174 .sin_port = htons(port), 174 .sin_port = htons(port),
175 }; 175 };
176#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
176 struct sockaddr_in6 sin6 = { 177 struct sockaddr_in6 sin6 = {
177 .sin6_family = AF_INET6, 178 .sin6_family = AF_INET6,
178 .sin6_addr = IN6ADDR_ANY_INIT, 179 .sin6_addr = IN6ADDR_ANY_INIT,
179 .sin6_port = htons(port), 180 .sin6_port = htons(port),
180 }; 181 };
182#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
181 struct sockaddr *sap; 183 struct sockaddr *sap;
182 size_t len; 184 size_t len;
183 185
@@ -186,10 +188,12 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
186 sap = (struct sockaddr *)&sin; 188 sap = (struct sockaddr *)&sin;
187 len = sizeof(sin); 189 len = sizeof(sin);
188 break; 190 break;
191#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
189 case PF_INET6: 192 case PF_INET6:
190 sap = (struct sockaddr *)&sin6; 193 sap = (struct sockaddr *)&sin6;
191 len = sizeof(sin6); 194 len = sizeof(sin6);
192 break; 195 break;
196#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
193 default: 197 default:
194 return ERR_PTR(-EAFNOSUPPORT); 198 return ERR_PTR(-EAFNOSUPPORT);
195 } 199 }
@@ -231,7 +235,10 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
231 err: 235 err:
232 spin_unlock(&svc_xprt_class_lock); 236 spin_unlock(&svc_xprt_class_lock);
233 dprintk("svc: transport %s not found\n", xprt_name); 237 dprintk("svc: transport %s not found\n", xprt_name);
234 return -ENOENT; 238
239 /* This errno is exposed to user space. Provide a reasonable
240 * perror msg for a bad transport. */
241 return -EPROTONOSUPPORT;
235} 242}
236EXPORT_SYMBOL_GPL(svc_create_xprt); 243EXPORT_SYMBOL_GPL(svc_create_xprt);
237 244
@@ -699,8 +706,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
699 spin_unlock_bh(&pool->sp_lock); 706 spin_unlock_bh(&pool->sp_lock);
700 707
701 len = 0; 708 len = 0;
702 if (test_bit(XPT_LISTENER, &xprt->xpt_flags) && 709 if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
703 !test_bit(XPT_CLOSE, &xprt->xpt_flags)) { 710 dprintk("svc_recv: found XPT_CLOSE\n");
711 svc_delete_xprt(xprt);
712 } else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
704 struct svc_xprt *newxpt; 713 struct svc_xprt *newxpt;
705 newxpt = xprt->xpt_ops->xpo_accept(xprt); 714 newxpt = xprt->xpt_ops->xpo_accept(xprt);
706 if (newxpt) { 715 if (newxpt) {
@@ -726,7 +735,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
726 svc_xprt_received(newxpt); 735 svc_xprt_received(newxpt);
727 } 736 }
728 svc_xprt_received(xprt); 737 svc_xprt_received(xprt);
729 } else if (!test_bit(XPT_CLOSE, &xprt->xpt_flags)) { 738 } else {
730 dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", 739 dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
731 rqstp, pool->sp_id, xprt, 740 rqstp, pool->sp_id, xprt,
732 atomic_read(&xprt->xpt_ref.refcount)); 741 atomic_read(&xprt->xpt_ref.refcount));
@@ -739,11 +748,6 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
739 dprintk("svc: got len=%d\n", len); 748 dprintk("svc: got len=%d\n", len);
740 } 749 }
741 750
742 if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
743 dprintk("svc_recv: found XPT_CLOSE\n");
744 svc_delete_xprt(xprt);
745 }
746
747 /* No data, incomplete (TCP) read, or accept() */ 751 /* No data, incomplete (TCP) read, or accept() */
748 if (len == 0 || len == -EAGAIN) { 752 if (len == 0 || len == -EAGAIN) {
749 rqstp->rq_res.len = 0; 753 rqstp->rq_res.len = 0;
@@ -889,11 +893,8 @@ void svc_delete_xprt(struct svc_xprt *xprt)
889 if (test_bit(XPT_TEMP, &xprt->xpt_flags)) 893 if (test_bit(XPT_TEMP, &xprt->xpt_flags))
890 serv->sv_tmpcnt--; 894 serv->sv_tmpcnt--;
891 895
892 for (dr = svc_deferred_dequeue(xprt); dr; 896 while ((dr = svc_deferred_dequeue(xprt)) != NULL)
893 dr = svc_deferred_dequeue(xprt)) {
894 svc_xprt_put(xprt);
895 kfree(dr); 897 kfree(dr);
896 }
897 898
898 svc_xprt_put(xprt); 899 svc_xprt_put(xprt);
899 spin_unlock_bh(&serv->sv_lock); 900 spin_unlock_bh(&serv->sv_lock);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index d8c041114497..afdcb0459a83 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -15,6 +15,7 @@
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#define RPCDBG_FACILITY RPCDBG_AUTH 16#define RPCDBG_FACILITY RPCDBG_AUTH
17 17
18#include <linux/sunrpc/clnt.h>
18 19
19/* 20/*
20 * AUTHUNIX and AUTHNULL credentials are both handled here. 21 * AUTHUNIX and AUTHNULL credentials are both handled here.
@@ -187,10 +188,13 @@ static int ip_map_parse(struct cache_detail *cd,
187 * for scratch: */ 188 * for scratch: */
188 char *buf = mesg; 189 char *buf = mesg;
189 int len; 190 int len;
190 int b1, b2, b3, b4, b5, b6, b7, b8;
191 char c;
192 char class[8]; 191 char class[8];
193 struct in6_addr addr; 192 union {
193 struct sockaddr sa;
194 struct sockaddr_in s4;
195 struct sockaddr_in6 s6;
196 } address;
197 struct sockaddr_in6 sin6;
194 int err; 198 int err;
195 199
196 struct ip_map *ipmp; 200 struct ip_map *ipmp;
@@ -209,24 +213,24 @@ static int ip_map_parse(struct cache_detail *cd,
209 len = qword_get(&mesg, buf, mlen); 213 len = qword_get(&mesg, buf, mlen);
210 if (len <= 0) return -EINVAL; 214 if (len <= 0) return -EINVAL;
211 215
212 if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) == 4) { 216 if (rpc_pton(buf, len, &address.sa, sizeof(address)) == 0)
213 addr.s6_addr32[0] = 0;
214 addr.s6_addr32[1] = 0;
215 addr.s6_addr32[2] = htonl(0xffff);
216 addr.s6_addr32[3] =
217 htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
218 } else if (sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x%c",
219 &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
220 addr.s6_addr16[0] = htons(b1);
221 addr.s6_addr16[1] = htons(b2);
222 addr.s6_addr16[2] = htons(b3);
223 addr.s6_addr16[3] = htons(b4);
224 addr.s6_addr16[4] = htons(b5);
225 addr.s6_addr16[5] = htons(b6);
226 addr.s6_addr16[6] = htons(b7);
227 addr.s6_addr16[7] = htons(b8);
228 } else
229 return -EINVAL; 217 return -EINVAL;
218 switch (address.sa.sa_family) {
219 case AF_INET:
220 /* Form a mapped IPv4 address in sin6 */
221 memset(&sin6, 0, sizeof(sin6));
222 sin6.sin6_family = AF_INET6;
223 sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
224 sin6.sin6_addr.s6_addr32[3] = address.s4.sin_addr.s_addr;
225 break;
226#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
227 case AF_INET6:
228 memcpy(&sin6, &address.s6, sizeof(sin6));
229 break;
230#endif
231 default:
232 return -EINVAL;
233 }
230 234
231 expiry = get_expiry(&mesg); 235 expiry = get_expiry(&mesg);
232 if (expiry ==0) 236 if (expiry ==0)
@@ -243,7 +247,8 @@ static int ip_map_parse(struct cache_detail *cd,
243 } else 247 } else
244 dom = NULL; 248 dom = NULL;
245 249
246 ipmp = ip_map_lookup(class, &addr); 250 /* IPv6 scope IDs are ignored for now */
251 ipmp = ip_map_lookup(class, &sin6.sin6_addr);
247 if (ipmp) { 252 if (ipmp) {
248 err = ip_map_update(ipmp, 253 err = ip_map_update(ipmp,
249 container_of(dom, struct unix_domain, h), 254 container_of(dom, struct unix_domain, h),
@@ -619,7 +624,7 @@ static int unix_gid_show(struct seq_file *m,
619 else 624 else
620 glen = 0; 625 glen = 0;
621 626
622 seq_printf(m, "%d %d:", ug->uid, glen); 627 seq_printf(m, "%u %d:", ug->uid, glen);
623 for (i = 0; i < glen; i++) 628 for (i = 0; i < glen; i++)
624 seq_printf(m, " %d", GROUP_AT(ug->gi, i)); 629 seq_printf(m, " %d", GROUP_AT(ug->gi, i));
625 seq_printf(m, "\n"); 630 seq_printf(m, "\n");
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 870929e08e5d..a29f259204e6 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -968,6 +968,7 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
968 return len; 968 return len;
969 err_delete: 969 err_delete:
970 set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); 970 set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
971 svc_xprt_received(&svsk->sk_xprt);
971 err_again: 972 err_again:
972 return -EAGAIN; 973 return -EAGAIN;
973} 974}
@@ -1357,7 +1358,7 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
1357 1358
1358 if (!so) 1359 if (!so)
1359 return err; 1360 return err;
1360 if (so->sk->sk_family != AF_INET) 1361 if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6))
1361 err = -EAFNOSUPPORT; 1362 err = -EAFNOSUPPORT;
1362 else if (so->sk->sk_protocol != IPPROTO_TCP && 1363 else if (so->sk->sk_protocol != IPPROTO_TCP &&
1363 so->sk->sk_protocol != IPPROTO_UDP) 1364 so->sk->sk_protocol != IPPROTO_UDP)