Commit 05c5cb31 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-2.6.34' of git://linux-nfs.org/~bfields/linux

* 'for-2.6.34' of git://linux-nfs.org/~bfields/linux: (22 commits)
  nfsd4: fix minor memory leak
  svcrpc: treat uid's as unsigned
  nfsd: ensure sockets are closed on error
  Revert "sunrpc: move the close processing after do recvfrom method"
  Revert "sunrpc: fix peername failed on closed listener"
  sunrpc: remove unnecessary svc_xprt_put
  NFSD: NFSv4 callback client should use RPC_TASK_SOFTCONN
  xfs_export_operations.commit_metadata
  commit_metadata export operation replacing nfsd_sync_dir
  lockd: don't clear sm_monitored on nsm_reboot_lookup
  lockd: release reference to nsm_handle in nlm_host_rebooted
  nfsd: Use vfs_fsync_range() in nfsd_commit
  NFSD: Create PF_INET6 listener in write_ports
  SUNRPC: NFS kernel APIs shouldn't return ENOENT for "transport not found"
  SUNRPC: Bury "#ifdef IPV6" in svc_create_xprt()
  NFSD: Support AF_INET6 in svc_addsock() function
  SUNRPC: Use rpc_pton() in ip_map_parse()
  nfsd: 4.1 has an rfc number
  nfsd41: Create the recovery entry for the NFSv4.1 client
  nfsd: use vfs_fsync for non-directories
  ...
parents 4582a30c 4ea41e2d
...@@ -17,8 +17,7 @@ kernels must turn 4.1 on or off *before* turning support for version 4 ...@@ -17,8 +17,7 @@ kernels must turn 4.1 on or off *before* turning support for version 4
on or off; rpc.nfsd does this correctly.) on or off; rpc.nfsd does this correctly.)
The NFSv4 minorversion 1 (NFSv4.1) implementation in nfsd is based The NFSv4 minorversion 1 (NFSv4.1) implementation in nfsd is based
on the latest NFSv4.1 Internet Draft: on RFC 5661.
http://tools.ietf.org/html/draft-ietf-nfsv4-minorversion1-29
From the many new features in NFSv4.1 the current implementation From the many new features in NFSv4.1 the current implementation
focuses on the mandatory-to-implement NFSv4.1 Sessions, providing focuses on the mandatory-to-implement NFSv4.1 Sessions, providing
...@@ -44,7 +43,7 @@ interoperability problems with future clients. Known issues: ...@@ -44,7 +43,7 @@ interoperability problems with future clients. Known issues:
trunking, but this is a mandatory feature, and its use is trunking, but this is a mandatory feature, and its use is
recommended to clients in a number of places. (E.g. to ensure recommended to clients in a number of places. (E.g. to ensure
timely renewal in case an existing connection's retry timeouts timely renewal in case an existing connection's retry timeouts
have gotten too long; see section 8.3 of the draft.) have gotten too long; see section 8.3 of the RFC.)
Therefore, lack of this feature may cause future clients to Therefore, lack of this feature may cause future clients to
fail. fail.
- Incomplete backchannel support: incomplete backchannel gss - Incomplete backchannel support: incomplete backchannel gss
......
...@@ -479,8 +479,8 @@ again: mutex_lock(&nlm_host_mutex); ...@@ -479,8 +479,8 @@ again: mutex_lock(&nlm_host_mutex);
} }
} }
} }
mutex_unlock(&nlm_host_mutex); mutex_unlock(&nlm_host_mutex);
nsm_release(nsm);
} }
/* /*
......
...@@ -349,9 +349,9 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap, ...@@ -349,9 +349,9 @@ struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
* nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle
* @info: pointer to NLMPROC_SM_NOTIFY arguments * @info: pointer to NLMPROC_SM_NOTIFY arguments
* *
* Returns a matching nsm_handle if found in the nsm cache; the returned * Returns a matching nsm_handle if found in the nsm cache. The returned
* nsm_handle's reference count is bumped and sm_monitored is cleared. * nsm_handle's reference count is bumped. Otherwise returns NULL if some
* Otherwise returns NULL if some error occurred. * error occurred.
*/ */
struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info) struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
{ {
...@@ -370,12 +370,6 @@ struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info) ...@@ -370,12 +370,6 @@ struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
atomic_inc(&cached->sm_count); atomic_inc(&cached->sm_count);
spin_unlock(&nsm_lock); spin_unlock(&nsm_lock);
/*
* During subsequent lock activity, force a fresh
* notification to be set up for this host.
*/
cached->sm_monitored = 0;
dprintk("lockd: host %s (%s) rebooted, cnt %d\n", dprintk("lockd: host %s (%s) rebooted, cnt %d\n",
cached->sm_name, cached->sm_addrbuf, cached->sm_name, cached->sm_addrbuf,
atomic_read(&cached->sm_count)); atomic_read(&cached->sm_count));
......
...@@ -243,11 +243,9 @@ static int make_socks(struct svc_serv *serv) ...@@ -243,11 +243,9 @@ static int make_socks(struct svc_serv *serv)
if (err < 0) if (err < 0)
goto out_err; goto out_err;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
err = create_lockd_family(serv, PF_INET6); err = create_lockd_family(serv, PF_INET6);
if (err < 0 && err != -EAFNOSUPPORT) if (err < 0 && err != -EAFNOSUPPORT)
goto out_err; goto out_err;
#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */
warned = 0; warned = 0;
return 0; return 0;
......
...@@ -118,7 +118,6 @@ nfs4_callback_up(struct svc_serv *serv) ...@@ -118,7 +118,6 @@ nfs4_callback_up(struct svc_serv *serv)
dprintk("NFS: Callback listener port = %u (af %u)\n", dprintk("NFS: Callback listener port = %u (af %u)\n",
nfs_callback_tcpport, PF_INET); nfs_callback_tcpport, PF_INET);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
ret = svc_create_xprt(serv, "tcp", PF_INET6, ret = svc_create_xprt(serv, "tcp", PF_INET6,
nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
if (ret > 0) { if (ret > 0) {
...@@ -129,7 +128,6 @@ nfs4_callback_up(struct svc_serv *serv) ...@@ -129,7 +128,6 @@ nfs4_callback_up(struct svc_serv *serv)
ret = 0; ret = 0;
else else
goto out_err; goto out_err;
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
return svc_prepare_thread(serv, &serv->sv_pools[0]); return svc_prepare_thread(serv, &serv->sv_pools[0]);
......
...@@ -525,6 +525,8 @@ static struct rpc_cred *callback_cred; ...@@ -525,6 +525,8 @@ static struct rpc_cred *callback_cred;
int set_callback_cred(void) int set_callback_cred(void)
{ {
if (callback_cred)
return 0;
callback_cred = rpc_lookup_machine_cred(); callback_cred = rpc_lookup_machine_cred();
if (!callback_cred) if (!callback_cred)
return -ENOMEM; return -ENOMEM;
...@@ -542,7 +544,8 @@ void do_probe_callback(struct nfs4_client *clp) ...@@ -542,7 +544,8 @@ void do_probe_callback(struct nfs4_client *clp)
}; };
int status; int status;
status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT, status = rpc_call_async(cb->cb_client, &msg,
RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
&nfsd4_cb_probe_ops, (void *)clp); &nfsd4_cb_probe_ops, (void *)clp);
if (status) { if (status) {
warn_no_callback_path(clp, status); warn_no_callback_path(clp, status);
......
...@@ -119,9 +119,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) ...@@ -119,9 +119,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
static void static void
nfsd4_sync_rec_dir(void) nfsd4_sync_rec_dir(void)
{ {
mutex_lock(&rec_dir.dentry->d_inode->i_mutex); vfs_fsync(NULL, rec_dir.dentry, 0);
nfsd_sync_dir(rec_dir.dentry);
mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
} }
int int
......
...@@ -2482,8 +2482,10 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf ...@@ -2482,8 +2482,10 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
} }
memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));
if (nfsd4_has_session(&resp->cstate)) if (nfsd4_has_session(&resp->cstate)) {
open->op_stateowner->so_confirmed = 1; open->op_stateowner->so_confirmed = 1;
nfsd4_create_clid_dir(open->op_stateowner->so_client);
}
/* /*
* Attempt to hand out a delegation. No error return, because the * Attempt to hand out a delegation. No error return, because the
......
...@@ -1434,7 +1434,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) ...@@ -1434,7 +1434,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
} }
op->opnum = ntohl(*argp->p++); op->opnum = ntohl(*argp->p++);
if (op->opnum >= OP_ACCESS && op->opnum < ops->nops) if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP)
op->status = ops->decoders[op->opnum](argp, &op->u); op->status = ops->decoders[op->opnum](argp, &op->u);
else { else {
op->opnum = OP_ILLEGAL; op->opnum = OP_ILLEGAL;
......
...@@ -988,6 +988,7 @@ static ssize_t __write_ports_delfd(char *buf) ...@@ -988,6 +988,7 @@ static ssize_t __write_ports_delfd(char *buf)
static ssize_t __write_ports_addxprt(char *buf) static ssize_t __write_ports_addxprt(char *buf)
{ {
char transport[16]; char transport[16];
struct svc_xprt *xprt;
int port, err; int port, err;
if (sscanf(buf, "%15s %4u", transport, &port) != 2) if (sscanf(buf, "%15s %4u", transport, &port) != 2)
...@@ -1002,13 +1003,24 @@ static ssize_t __write_ports_addxprt(char *buf) ...@@ -1002,13 +1003,24 @@ static ssize_t __write_ports_addxprt(char *buf)
err = svc_create_xprt(nfsd_serv, transport, err = svc_create_xprt(nfsd_serv, transport,
PF_INET, port, SVC_SOCK_ANONYMOUS); PF_INET, port, SVC_SOCK_ANONYMOUS);
if (err < 0) { if (err < 0)
/* Give a reasonable perror msg for bad transport string */ goto out_err;
if (err == -ENOENT)
err = -EPROTONOSUPPORT; err = svc_create_xprt(nfsd_serv, transport,
return err; PF_INET6, port, SVC_SOCK_ANONYMOUS);
} if (err < 0 && err != -EAFNOSUPPORT)
goto out_close;
return 0; return 0;
out_close:
xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port);
if (xprt != NULL) {
svc_close_xprt(xprt);
svc_xprt_put(xprt);
}
out_err:
/* Decrease the count, but don't shut down the service */
nfsd_serv->sv_nrthreads--;
return err;
} }
/* /*
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include <linux/jhash.h> #include <linux/jhash.h>
#include <linux/ima.h> #include <linux/ima.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/exportfs.h>
#include <linux/writeback.h>
#ifdef CONFIG_NFSD_V3 #ifdef CONFIG_NFSD_V3
#include "xdr3.h" #include "xdr3.h"
...@@ -270,6 +272,32 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, ...@@ -270,6 +272,32 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
return err; return err;
} }
/*
* Commit metadata changes to stable storage.
*/
static int
commit_metadata(struct svc_fh *fhp)
{
struct inode *inode = fhp->fh_dentry->d_inode;
const struct export_operations *export_ops = inode->i_sb->s_export_op;
int error = 0;
if (!EX_ISSYNC(fhp->fh_export))
return 0;
if (export_ops->commit_metadata) {
error = export_ops->commit_metadata(inode);
} else {
struct writeback_control wbc = {
.sync_mode = WB_SYNC_ALL,
.nr_to_write = 0, /* metadata only */
};
error = sync_inode(inode, &wbc);
}
return error;
}
/* /*
* Set various file attributes. * Set various file attributes.
...@@ -766,43 +794,6 @@ nfsd_close(struct file *filp) ...@@ -766,43 +794,6 @@ nfsd_close(struct file *filp)
fput(filp); fput(filp);
} }
/*
* Sync a file
* As this calls fsync (not fdatasync) there is no need for a write_inode
* after it.
*/
static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
const struct file_operations *fop)
{
struct inode *inode = dp->d_inode;
int (*fsync) (struct file *, struct dentry *, int);
int err;
err = filemap_write_and_wait(inode->i_mapping);
if (err == 0 && fop && (fsync = fop->fsync))
err = fsync(filp, dp, 0);
return err;
}
static int
nfsd_sync(struct file *filp)
{
int err;
struct inode *inode = filp->f_path.dentry->d_inode;
dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name);
mutex_lock(&inode->i_mutex);
err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op);
mutex_unlock(&inode->i_mutex);
return err;
}
int
nfsd_sync_dir(struct dentry *dp)
{
return nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
}
/* /*
* Obtain the readahead parameters for the file * Obtain the readahead parameters for the file
* specified by (dev, ino). * specified by (dev, ino).
...@@ -1006,7 +997,7 @@ static int wait_for_concurrent_writes(struct file *file) ...@@ -1006,7 +997,7 @@ static int wait_for_concurrent_writes(struct file *file)
if (inode->i_state & I_DIRTY) { if (inode->i_state & I_DIRTY) {
dprintk("nfsd: write sync %d\n", task_pid_nr(current)); dprintk("nfsd: write sync %d\n", task_pid_nr(current));
err = nfsd_sync(file); err = vfs_fsync(file, file->f_path.dentry, 0);
} }
last_ino = inode->i_ino; last_ino = inode->i_ino;
last_dev = inode->i_sb->s_dev; last_dev = inode->i_sb->s_dev;
...@@ -1154,8 +1145,9 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, ...@@ -1154,8 +1145,9 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
#ifdef CONFIG_NFSD_V3 #ifdef CONFIG_NFSD_V3
/* /*
* Commit all pending writes to stable storage. * Commit all pending writes to stable storage.
* Strictly speaking, we could sync just the indicated file region here, *
* but there's currently no way we can ask the VFS to do so. * Note: we only guarantee that data that lies within the range specified
* by the 'offset' and 'count' parameters will be synced.
* *
* Unfortunately we cannot lock the file to make sure we return full WCC * Unfortunately we cannot lock the file to make sure we return full WCC
* data to the client, as locking happens lower down in the filesystem. * 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,23 +1157,32 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
loff_t offset, unsigned long count) loff_t offset, unsigned long count)
{ {
struct file *file; struct file *file;
__be32 err; loff_t end = LLONG_MAX;
__be32 err = nfserr_inval;
if ((u64)count > ~(u64)offset) if (offset < 0)
return nfserr_inval; goto out;
if (count != 0) {
end = offset + (loff_t)count - 1;
if (end < offset)
goto out;
}
err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file);
if (err) if (err)
return err; goto out;
if (EX_ISSYNC(fhp->fh_export)) { if (EX_ISSYNC(fhp->fh_export)) {
if (file->f_op && file->f_op->fsync) { int err2 = vfs_fsync_range(file, file->f_path.dentry,
err = nfserrno(nfsd_sync(file)); offset, end, 0);
} else {
if (err2 != -EINVAL)
err = nfserrno(err2);
else
err = nfserr_notsupp; err = nfserr_notsupp;
}
} }
nfsd_close(file); nfsd_close(file);
out:
return err; return err;
} }
#endif /* CONFIG_NFSD_V3 */ #endif /* CONFIG_NFSD_V3 */
...@@ -1334,12 +1335,14 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1334,12 +1335,14 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
goto out_nfserr; goto out_nfserr;
} }
if (EX_ISSYNC(fhp->fh_export)) { err = nfsd_create_setattr(rqstp, resfhp, iap);
err = nfserrno(nfsd_sync_dir(dentry));
write_inode_now(dchild->d_inode, 1);
}
err2 = nfsd_create_setattr(rqstp, resfhp, iap); /*
* nfsd_setattr already committed the child. Transactional filesystems
* had a chance to commit changes for both parent and child
* simultaneously making the following commit_metadata a noop.
*/
err2 = nfserrno(commit_metadata(fhp));
if (err2) if (err2)
err = err2; err = err2;
mnt_drop_write(fhp->fh_export->ex_path.mnt); 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,7 +1374,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct dentry *dentry, *dchild = NULL; struct dentry *dentry, *dchild = NULL;
struct inode *dirp; struct inode *dirp;
__be32 err; __be32 err;
__be32 err2;
int host_err; int host_err;
__u32 v_mtime=0, v_atime=0; __u32 v_mtime=0, v_atime=0;
...@@ -1466,11 +1468,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1466,11 +1468,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (created) if (created)
*created = 1; *created = 1;
if (EX_ISSYNC(fhp->fh_export)) {
err = nfserrno(nfsd_sync_dir(dentry));
/* setattr will sync the child (or not) */
}
nfsd_check_ignore_resizing(iap); nfsd_check_ignore_resizing(iap);
if (createmode == NFS3_CREATE_EXCLUSIVE) { if (createmode == NFS3_CREATE_EXCLUSIVE) {
...@@ -1485,9 +1482,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1485,9 +1482,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
} }
set_attr: set_attr:
err2 = nfsd_create_setattr(rqstp, resfhp, iap); err = nfsd_create_setattr(rqstp, resfhp, iap);
if (err2)
err = err2; /*
* nfsd_setattr already committed the child (and possibly also the parent).
*/
if (!err)
err = nfserrno(commit_metadata(fhp));
mnt_drop_write(fhp->fh_export->ex_path.mnt); mnt_drop_write(fhp->fh_export->ex_path.mnt);
/* /*
...@@ -1602,12 +1603,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1602,12 +1603,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
} }
} else } else
host_err = vfs_symlink(dentry->d_inode, dnew, path); host_err = vfs_symlink(dentry->d_inode, dnew, path);
if (!host_err) {
if (EX_ISSYNC(fhp->fh_export))
host_err = nfsd_sync_dir(dentry);
}
err = nfserrno(host_err); err = nfserrno(host_err);
if (!err)
err = nfserrno(commit_metadata(fhp));
fh_unlock(fhp); fh_unlock(fhp);
mnt_drop_write(fhp->fh_export->ex_path.mnt); mnt_drop_write(fhp->fh_export->ex_path.mnt);
...@@ -1669,11 +1667,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, ...@@ -1669,11 +1667,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
} }
host_err = vfs_link(dold, dirp, dnew); host_err = vfs_link(dold, dirp, dnew);
if (!host_err) { if (!host_err) {
if (EX_ISSYNC(ffhp->fh_export)) { err = nfserrno(commit_metadata(ffhp));
err = nfserrno(nfsd_sync_dir(ddir)); if (!err)
write_inode_now(dest, 1); err = nfserrno(commit_metadata(tfhp));
}
err = 0;
} else { } else {
if (host_err == -EXDEV && rqstp->rq_vers == 2) if (host_err == -EXDEV && rqstp->rq_vers == 2)
err = nfserr_acces; err = nfserr_acces;
...@@ -1769,10 +1765,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, ...@@ -1769,10 +1765,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
goto out_dput_new; goto out_dput_new;
host_err = vfs_rename(fdir, odentry, tdir, ndentry); host_err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!host_err && EX_ISSYNC(tfhp->fh_export)) { if (!host_err) {
host_err = nfsd_sync_dir(tdentry); host_err = commit_metadata(tfhp);
if (!host_err) if (!host_err)
host_err = nfsd_sync_dir(fdentry); host_err = commit_metadata(ffhp);
} }
mnt_drop_write(ffhp->fh_export->ex_path.mnt); 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,12 +1849,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
dput(rdentry); dput(rdentry);
if (host_err) if (!host_err)
goto out_drop; host_err = commit_metadata(fhp);
if (EX_ISSYNC(fhp->fh_export))
host_err = nfsd_sync_dir(dentry);
out_drop:
mnt_drop_write(fhp->fh_export->ex_path.mnt); mnt_drop_write(fhp->fh_export->ex_path.mnt);
out_nfserr: out_nfserr:
err = nfserrno(host_err); err = nfserrno(host_err);
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "xfs_vnodeops.h" #include "xfs_vnodeops.h"
#include "xfs_bmap_btree.h" #include "xfs_bmap_btree.h"
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_inode_item.h"
/* /*
* Note that we only accept fileids which are long enough rather than allow * Note that we only accept fileids which are long enough rather than allow
...@@ -215,9 +216,28 @@ xfs_fs_get_parent( ...@@ -215,9 +216,28 @@ xfs_fs_get_parent(
return d_obtain_alias(VFS_I(cip)); return d_obtain_alias(VFS_I(cip));
} }
STATIC int
xfs_fs_nfs_commit_metadata(
struct inode *inode)
{
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
int error = 0;
xfs_ilock(ip, XFS_ILOCK_SHARED);
if (xfs_ipincount(ip)) {
error = _xfs_log_force_lsn(mp, ip->i_itemp->ili_last_lsn,
XFS_LOG_SYNC, NULL);
}
xfs_iunlock(ip, XFS_ILOCK_SHARED);
return error;
}
const struct export_operations xfs_export_operations = { const struct export_operations xfs_export_operations = {
.encode_fh = xfs_fs_encode_fh, .encode_fh = xfs_fs_encode_fh,
.fh_to_dentry = xfs_fs_fh_to_dentry, .fh_to_dentry = xfs_fs_fh_to_dentry,
.fh_to_parent = xfs_fs_fh_to_parent, .fh_to_parent = xfs_fs_fh_to_parent,
.get_parent = xfs_fs_get_parent, .get_parent = xfs_fs_get_parent,
.commit_metadata = xfs_fs_nfs_commit_metadata,
}; };
...@@ -96,6 +96,7 @@ struct fid { ...@@ -96,6 +96,7 @@ struct fid {
* @fh_to_parent: find the implied object's parent and get a dentry for it * @fh_to_parent: find the implied object's parent and get a dentry for it
* @get_name: find the name for a given inode in a given directory * @get_name: find the name for a given inode in a given directory
* @get_parent: find the parent of a given directory * @get_parent: find the parent of a given directory
* @commit_metadata: commit metadata changes to stable storage
* *
* See Documentation/filesystems/nfs/Exporting for details on how to use * See Documentation/filesystems/nfs/Exporting for details on how to use
* this interface correctly. * this interface correctly.
...@@ -137,6 +138,9 @@ struct fid { ...@@ -137,6 +138,9 @@ struct fid {
* is also a directory. In the event that it cannot be found, or storage * is also a directory. In the event that it cannot be found, or storage
* space cannot be allocated, a %ERR_PTR should be returned. * space cannot be allocated, a %ERR_PTR should be returned.
* *
* commit_metadata:
* @commit_metadata should commit metadata changes to stable storage.
*
* Locking rules: * Locking rules:
* get_parent is called with child->d_inode->i_mutex down * get_parent is called with child->d_inode->i_mutex down
* get_name is not (which is possibly inconsistent) * get_name is not (which is possibly inconsistent)
...@@ -152,6 +156,7 @@ struct export_operations { ...@@ -152,6 +156,7 @@ struct export_operations {
int (*get_name)(struct dentry *parent, char *name, int (*get_name)(struct dentry *parent, char *name,
struct dentry *child); struct dentry *child);
struct dentry * (*get_parent)(struct dentry *child); struct dentry * (*get_parent)(struct dentry *child);
int (*commit_metadata)(struct inode *inode);
}; };
extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid,
......
...@@ -173,11 +173,13 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, ...@@ -173,11 +173,13 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
.sin_addr.s_addr = htonl(INADDR_ANY), .sin_addr.s_addr = htonl(INADDR_ANY),
.sin_port = htons(port), .sin_port = htons(port),
}; };
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct sockaddr_in6 sin6 = { struct sockaddr_in6 sin6 = {
.sin6_family = AF_INET6, .sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_ANY_INIT, .sin6_addr = IN6ADDR_ANY_INIT,
.sin6_port = htons(port), .sin6_port = htons(port),
}; };
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
struct sockaddr *sap; struct sockaddr *sap;
size_t len; size_t len;
...@@ -186,10 +188,12 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, ...@@ -186,10 +188,12 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
sap = (struct sockaddr *)&sin; sap = (struct sockaddr *)&sin;
len = sizeof(sin); len = sizeof(sin);
break; break;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case PF_INET6: case PF_INET6:
sap = (struct sockaddr *)&sin6; sap = (struct sockaddr *)&sin6;
len = sizeof(sin6); len = sizeof(sin6);
break; break;
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
default: default:
return ERR_PTR(-EAFNOSUPPORT); return ERR_PTR(-EAFNOSUPPORT);
} }
...@@ -231,7 +235,10 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, ...@@ -231,7 +235,10 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
err: err:
spin_unlock(&svc_xprt_class_lock); spin_unlock(&svc_xprt_class_lock);
dprintk("svc: transport %s not found\n", xprt_name); dprintk("svc: transport %s not found\n", xprt_name);
return -ENOENT;
/* This errno is exposed to user space. Provide a reasonable
* perror msg for a bad transport. */
return -EPROTONOSUPPORT;
} }
EXPORT_SYMBOL_GPL(svc_create_xprt); EXPORT_SYMBOL_GPL(svc_create_xprt);
...@@ -699,8 +706,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) ...@@ -699,8 +706,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
spin_unlock_bh(&pool->sp_lock); spin_unlock_bh(&pool->sp_lock);
len = 0; len = 0;
if (test_bit(XPT_LISTENER, &xprt->xpt_flags) && if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
!test_bit(XPT_CLOSE, &xprt->xpt_flags)) { dprintk("svc_recv: found XPT_CLOSE\n");
svc_delete_xprt(xprt);
} else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
struct svc_xprt *newxpt; struct svc_xprt *newxpt;
newxpt = xprt->xpt_ops->xpo_accept(xprt); newxpt = xprt->xpt_ops->xpo_accept(xprt);
if (newxpt) { if (newxpt) {
...@@ -726,7 +735,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) ...@@ -726,7 +735,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
svc_xprt_received(newxpt); svc_xprt_received(newxpt);
} }
svc_xprt_received(xprt); svc_xprt_received(xprt);
} else if (!test_bit(XPT_CLOSE, &xprt->xpt_flags)) { } else {
dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
rqstp, pool->sp_id, xprt, rqstp, pool->sp_id, xprt,
atomic_read(&xprt->xpt_ref.refcount)); atomic_read(&xprt->xpt_ref.refcount));
...@@ -739,11 +748,6 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) ...@@ -739,11 +748,6 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
dprintk("svc: got len=%d\n", len); dprintk("svc: got len=%d\n", len);
} }
if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
dprintk("svc_recv: found XPT_CLOSE\n");
svc_delete_xprt(xprt);
}
/* No data, incomplete (TCP) read, or accept() */ /* No data, incomplete (TCP) read, or accept() */
if (len == 0 || len == -EAGAIN) { if (len == 0 || len == -EAGAIN) {
rqstp->rq_res.len = 0; rqstp->rq_res.len = 0;
...@@ -889,11 +893,8 @@ void svc_delete_xprt(struct svc_xprt *xprt) ...@@ -889,11 +893,8 @@ void svc_delete_xprt(struct svc_xprt *xprt)
if (test_bit(XPT_TEMP, &xprt->xpt_flags)) if (test_bit(XPT_TEMP, &xprt->xpt_flags))
serv->sv_tmpcnt--; serv->sv_tmpcnt--;
for (dr = svc_deferred_dequeue(xprt); dr; while ((dr = svc_deferred_dequeue(xprt)) != NULL)
dr = svc_deferred_dequeue(xprt)) {
svc_xprt_put(xprt);
kfree(dr); kfree(dr);
}
svc_xprt_put(xprt); svc_xprt_put(xprt);
spin_unlock_bh(&serv->sv_lock); spin_unlock_bh(&serv->sv_lock);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#define RPCDBG_FACILITY RPCDBG_AUTH #define RPCDBG_FACILITY RPCDBG_AUTH
#include <linux/sunrpc/clnt.h>
/* /*
* AUTHUNIX and AUTHNULL credentials are both handled here. * AUTHUNIX and AUTHNULL credentials are both handled here.
...@@ -187,10 +188,13 @@ static int ip_map_parse(struct cache_detail *cd, ...@@ -187,10 +188,13 @@ static int ip_map_parse(struct cache_detail *cd,
* for scratch: */ * for scratch: */
char *buf = mesg; char *buf = mesg;
int len; int len;
int b1, b2, b3, b4, b5, b6, b7, b8;
char c;
char class[8]; char class[8];
struct in6_addr addr; union {
struct sockaddr sa;
struct sockaddr_in s4;
struct sockaddr_in6 s6;
} address;
struct sockaddr_in6 sin6;
int err; int err;
struct ip_map *ipmp; struct ip_map *ipmp;
...@@ -209,24 +213,24 @@ static int ip_map_parse(struct cache_detail *cd, ...@@ -209,24 +213,24 @@ static int ip_map_parse(struct cache_detail *cd,
len = qword_get(&mesg, buf, mlen); len = qword_get(&mesg, buf, mlen);
if (len <= 0) return -EINVAL; if (len <= 0) return -EINVAL;
if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) == 4) { if (rpc_pton(buf, len, &address.sa, sizeof(address)) == 0)
addr.s6_addr32[0] = 0;
addr.s6_addr32[1] = 0;
addr.s6_addr32[2] = htonl(0xffff);
addr.s6_addr32[3] =
htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
} else if (sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x%c",
&b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) {
addr.s6_addr16[0] = htons(b1);
addr.s6_addr16[1] = htons(b2);
addr.s6_addr16[2] = htons(b3);
addr.s6_addr16[3] = htons(b4);
addr.s6_addr16[4] = htons(b5);
addr.s6_addr16[5] = htons(b6);
addr.s6_addr16[6] = htons(b7);
addr.s6_addr16[7] = htons(b8);
} else
return -EINVAL; return -EINVAL;
switch (address.sa.sa_family) {
case AF_INET:
/* Form a mapped IPv4 address in sin6 */
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
sin6.sin6_addr.s6_addr32[3] = address.s4.sin_addr.s_addr;
break;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case AF_INET6:
memcpy(&sin6, &address.s6, sizeof(sin6));
break;
#endif
default:
return -EINVAL;
}
expiry = get_expiry(&mesg); expiry = get_expiry(&mesg);
if (expiry ==0) if (expiry ==0)
...@@ -243,7 +247,8 @@ static int ip_map_parse(struct cache_detail *cd, ...@@ -243,7 +247,8 @@ static int ip_map_parse(struct cache_detail *cd,
} else } else
dom = NULL; dom = NULL;
ipmp = ip_map_lookup(class, &addr); /* IPv6 scope IDs are ignored for now */
ipmp = ip_map_lookup(class, &sin6.sin6_addr);
if (ipmp) { if (ipmp) {
err = ip_map_update(ipmp, err = ip_map_update(ipmp,
container_of(dom, struct unix_domain, h), container_of(dom, struct unix_domain, h),
...@@ -619,7 +624,7 @@ static int unix_gid_show(struct seq_file *m, ...@@ -619,7 +624,7 @@ static int unix_gid_show(struct seq_file *m,
else else
glen = 0; glen = 0;
seq_printf(m, "%d %d:", ug->uid, glen); seq_printf(m, "%u %d:", ug->uid, glen);
for (i = 0; i < glen; i++) for (i = 0; i < glen; i++)
seq_printf(m, " %d", GROUP_AT(ug->gi, i)); seq_printf(m, " %d", GROUP_AT(ug->gi, i));
seq_printf(m, "\n"); seq_printf(m, "\n");
......
...@@ -968,6 +968,7 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) ...@@ -968,6 +968,7 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
return len; return len;
err_delete: err_delete:
set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
svc_xprt_received(&svsk->sk_xprt);
err_again: err_again:
return -EAGAIN; return -EAGAIN;
} }
...@@ -1357,7 +1358,7 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, ...@@ -1357,7 +1358,7 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
if (!so) if (!so)
return err; return err;
if (so->sk->sk_family != AF_INET) if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6))
err = -EAFNOSUPPORT; err = -EAFNOSUPPORT;
else if (so->sk->sk_protocol != IPPROTO_TCP && else if (so->sk->sk_protocol != IPPROTO_TCP &&
so->sk->sk_protocol != IPPROTO_UDP) so->sk->sk_protocol != IPPROTO_UDP)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment