Commit 1f84603c authored by Trond Myklebust's avatar Trond Myklebust

Merge branch 'devel-for-2.6.31' into for-2.6.31

Conflicts:
	fs/nfs/client.c
	fs/nfs/super.c
parents 301933a0 4bf259e3
...@@ -126,7 +126,6 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) ...@@ -126,7 +126,6 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
struct nlm_lock *lock = &argp->lock; struct nlm_lock *lock = &argp->lock;
nlmclnt_next_cookie(&argp->cookie); nlmclnt_next_cookie(&argp->cookie);
argp->state = nsm_local_state;
memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh)); memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh));
lock->caller = utsname()->nodename; lock->caller = utsname()->nodename;
lock->oh.data = req->a_owner; lock->oh.data = req->a_owner;
...@@ -165,6 +164,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) ...@@ -165,6 +164,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
/* Set up the argument struct */ /* Set up the argument struct */
nlmclnt_setlockargs(call, fl); nlmclnt_setlockargs(call, fl);
lock_kernel();
if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
if (fl->fl_type != F_UNLCK) { if (fl->fl_type != F_UNLCK) {
call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; call->a_args.block = IS_SETLKW(cmd) ? 1 : 0;
...@@ -178,6 +178,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) ...@@ -178,6 +178,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
fl->fl_ops->fl_release_private(fl); fl->fl_ops->fl_release_private(fl);
fl->fl_ops = NULL; fl->fl_ops = NULL;
unlock_kernel();
dprintk("lockd: clnt proc returns %d\n", status); dprintk("lockd: clnt proc returns %d\n", status);
return status; return status;
...@@ -519,6 +520,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) ...@@ -519,6 +520,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
if (nsm_monitor(host) < 0) if (nsm_monitor(host) < 0)
goto out; goto out;
req->a_args.state = nsm_local_state;
fl->fl_flags |= FL_ACCESS; fl->fl_flags |= FL_ACCESS;
status = do_vfs_lock(fl); status = do_vfs_lock(fl);
......
...@@ -53,7 +53,7 @@ static DEFINE_SPINLOCK(nsm_lock); ...@@ -53,7 +53,7 @@ static DEFINE_SPINLOCK(nsm_lock);
/* /*
* Local NSM state * Local NSM state
*/ */
int __read_mostly nsm_local_state; u32 __read_mostly nsm_local_state;
int __read_mostly nsm_use_hostnames; int __read_mostly nsm_use_hostnames;
static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)
...@@ -112,6 +112,7 @@ static struct rpc_clnt *nsm_create(void) ...@@ -112,6 +112,7 @@ static struct rpc_clnt *nsm_create(void)
.program = &nsm_program, .program = &nsm_program,
.version = NSM_VERSION, .version = NSM_VERSION,
.authflavor = RPC_AUTH_NULL, .authflavor = RPC_AUTH_NULL,
.flags = RPC_CLNT_CREATE_NOPING,
}; };
return rpc_create(&args); return rpc_create(&args);
...@@ -184,13 +185,19 @@ int nsm_monitor(const struct nlm_host *host) ...@@ -184,13 +185,19 @@ int nsm_monitor(const struct nlm_host *host)
nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
status = nsm_mon_unmon(nsm, NSMPROC_MON, &res); status = nsm_mon_unmon(nsm, NSMPROC_MON, &res);
if (res.status != 0) if (unlikely(res.status != 0))
status = -EIO; status = -EIO;
if (status < 0) if (unlikely(status < 0)) {
printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name);
else return status;
nsm->sm_monitored = 1; }
return status;
nsm->sm_monitored = 1;
if (unlikely(nsm_local_state != res.state)) {
nsm_local_state = res.state;
dprintk("lockd: NSM state changed to %d\n", nsm_local_state);
}
return 0;
} }
/** /**
......
...@@ -123,7 +123,9 @@ nfs4_callback_up(struct svc_serv *serv) ...@@ -123,7 +123,9 @@ nfs4_callback_up(struct svc_serv *serv)
nfs_callback_tcpport6 = ret; nfs_callback_tcpport6 = ret;
dprintk("NFS: Callback listener port = %u (af %u)\n", dprintk("NFS: Callback listener port = %u (af %u)\n",
nfs_callback_tcpport6, PF_INET6); nfs_callback_tcpport6, PF_INET6);
} else if (ret != -EAFNOSUPPORT) } else if (ret == -EAFNOSUPPORT)
ret = 0;
else
goto out_err; goto out_err;
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
......
...@@ -116,6 +116,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ ...@@ -116,6 +116,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
{ {
struct nfs_client *clp; struct nfs_client *clp;
struct rpc_cred *cred; struct rpc_cred *cred;
int err = -ENOMEM;
if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
goto error_0; goto error_0;
...@@ -129,6 +130,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ ...@@ -129,6 +130,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
clp->cl_addrlen = cl_init->addrlen; clp->cl_addrlen = cl_init->addrlen;
if (cl_init->hostname) { if (cl_init->hostname) {
err = -ENOMEM;
clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL);
if (!clp->cl_hostname) if (!clp->cl_hostname)
goto error_cleanup; goto error_cleanup;
...@@ -159,7 +161,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ ...@@ -159,7 +161,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
error_cleanup: error_cleanup:
kfree(clp); kfree(clp);
error_0: error_0:
return NULL; return ERR_PTR(err);
} }
static void nfs4_shutdown_client(struct nfs_client *clp) static void nfs4_shutdown_client(struct nfs_client *clp)
...@@ -480,9 +482,10 @@ static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_in ...@@ -480,9 +482,10 @@ static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_in
spin_unlock(&nfs_client_lock); spin_unlock(&nfs_client_lock);
new = nfs_alloc_client(cl_init); new = nfs_alloc_client(cl_init);
} while (new); } while (!IS_ERR(new));
return ERR_PTR(-ENOMEM); dprintk("--> nfs_get_client() = %ld [failed]\n", PTR_ERR(new));
return new;
/* install a new client and return with it unready */ /* install a new client and return with it unready */
install_client: install_client:
......
...@@ -68,29 +68,26 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ ...@@ -68,29 +68,26 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
{ {
struct inode *inode = state->inode; struct inode *inode = state->inode;
struct file_lock *fl; struct file_lock *fl;
int status; int status = 0;
if (inode->i_flock == NULL)
goto out;
/* Protect inode->i_flock using the BKL */
lock_kernel();
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
continue; continue;
if (nfs_file_open_context(fl->fl_file) != ctx) if (nfs_file_open_context(fl->fl_file) != ctx)
continue; continue;
unlock_kernel();
status = nfs4_lock_delegation_recall(state, fl); status = nfs4_lock_delegation_recall(state, fl);
if (status >= 0) if (status < 0)
continue; goto out;
switch (status) { lock_kernel();
default:
printk(KERN_ERR "%s: unhandled error %d.\n",
__func__, status);
case -NFS4ERR_EXPIRED:
/* kill_proc(fl->fl_pid, SIGLOST, 1); */
case -NFS4ERR_STALE_CLIENTID:
nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs_client);
goto out_err;
}
} }
return 0; unlock_kernel();
out_err: out:
return status; return status;
} }
...@@ -268,7 +265,10 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat ...@@ -268,7 +265,10 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
nfs_msync_inode(inode); nfs_msync_inode(inode);
/* Guard against new delegated open calls */ /*
* Guard against new delegated open/lock/unlock calls and against
* state recovery
*/
down_write(&nfsi->rwsem); down_write(&nfsi->rwsem);
nfs_delegation_claim_opens(inode, &delegation->stateid); nfs_delegation_claim_opens(inode, &delegation->stateid);
up_write(&nfsi->rwsem); up_write(&nfsi->rwsem);
......
...@@ -48,6 +48,9 @@ static ssize_t nfs_file_splice_read(struct file *filp, loff_t *ppos, ...@@ -48,6 +48,9 @@ static ssize_t nfs_file_splice_read(struct file *filp, loff_t *ppos,
size_t count, unsigned int flags); size_t count, unsigned int flags);
static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov, static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov,
unsigned long nr_segs, loff_t pos); unsigned long nr_segs, loff_t pos);
static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
struct file *filp, loff_t *ppos,
size_t count, unsigned int flags);
static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
unsigned long nr_segs, loff_t pos); unsigned long nr_segs, loff_t pos);
static int nfs_file_flush(struct file *, fl_owner_t id); static int nfs_file_flush(struct file *, fl_owner_t id);
...@@ -73,6 +76,7 @@ const struct file_operations nfs_file_operations = { ...@@ -73,6 +76,7 @@ const struct file_operations nfs_file_operations = {
.lock = nfs_lock, .lock = nfs_lock,
.flock = nfs_flock, .flock = nfs_flock,
.splice_read = nfs_file_splice_read, .splice_read = nfs_file_splice_read,
.splice_write = nfs_file_splice_write,
.check_flags = nfs_check_flags, .check_flags = nfs_check_flags,
.setlease = nfs_setlease, .setlease = nfs_setlease,
}; };
...@@ -587,12 +591,38 @@ out_swapfile: ...@@ -587,12 +591,38 @@ out_swapfile:
goto out; goto out;
} }
static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
struct file *filp, loff_t *ppos,
size_t count, unsigned int flags)
{
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
ssize_t ret;
dprintk("NFS splice_write(%s/%s, %lu@%llu)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(unsigned long) count, (unsigned long long) *ppos);
/*
* The combination of splice and an O_APPEND destination is disallowed.
*/
nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count);
ret = generic_file_splice_write(pipe, filp, ppos, count, flags);
if (ret >= 0 && nfs_need_sync_write(filp, inode)) {
int err = nfs_do_fsync(nfs_file_open_context(filp), inode);
if (err < 0)
ret = err;
}
return ret;
}
static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
{ {
struct inode *inode = filp->f_mapping->host; struct inode *inode = filp->f_mapping->host;
int status = 0; int status = 0;
lock_kernel();
/* Try local locking first */ /* Try local locking first */
posix_test_lock(filp, fl); posix_test_lock(filp, fl);
if (fl->fl_type != F_UNLCK) { if (fl->fl_type != F_UNLCK) {
...@@ -608,7 +638,6 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) ...@@ -608,7 +638,6 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
status = NFS_PROTO(inode)->lock(filp, cmd, fl); status = NFS_PROTO(inode)->lock(filp, cmd, fl);
out: out:
unlock_kernel();
return status; return status;
out_noconflict: out_noconflict:
fl->fl_type = F_UNLCK; fl->fl_type = F_UNLCK;
...@@ -650,13 +679,11 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) ...@@ -650,13 +679,11 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
* If we're signalled while cleaning up locks on process exit, we * If we're signalled while cleaning up locks on process exit, we
* still need to complete the unlock. * still need to complete the unlock.
*/ */
lock_kernel();
/* Use local locking if mounted with "-onolock" */ /* Use local locking if mounted with "-onolock" */
if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
status = NFS_PROTO(inode)->lock(filp, cmd, fl); status = NFS_PROTO(inode)->lock(filp, cmd, fl);
else else
status = do_vfs_lock(filp, fl); status = do_vfs_lock(filp, fl);
unlock_kernel();
return status; return status;
} }
...@@ -673,13 +700,11 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) ...@@ -673,13 +700,11 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
if (status != 0) if (status != 0)
goto out; goto out;
lock_kernel();
/* Use local locking if mounted with "-onolock" */ /* Use local locking if mounted with "-onolock" */
if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
status = NFS_PROTO(inode)->lock(filp, cmd, fl); status = NFS_PROTO(inode)->lock(filp, cmd, fl);
else else
status = do_vfs_lock(filp, fl); status = do_vfs_lock(filp, fl);
unlock_kernel();
if (status < 0) if (status < 0)
goto out; goto out;
/* /*
......
...@@ -42,6 +42,12 @@ struct nfs_clone_mount { ...@@ -42,6 +42,12 @@ struct nfs_clone_mount {
rpc_authflavor_t authflavor; rpc_authflavor_t authflavor;
}; };
/*
* Note: RFC 1813 doesn't limit the number of auth flavors that
* a server can return, so make something up.
*/
#define NFS_MAX_SECFLAVORS (12)
/* /*
* In-kernel mount arguments * In-kernel mount arguments
*/ */
...@@ -91,6 +97,8 @@ struct nfs_mount_request { ...@@ -91,6 +97,8 @@ struct nfs_mount_request {
unsigned short protocol; unsigned short protocol;
struct nfs_fh *fh; struct nfs_fh *fh;
int noresvport; int noresvport;
unsigned int *auth_flav_len;
rpc_authflavor_t *auth_flavs;
}; };
extern int nfs_mount(struct nfs_mount_request *info); extern int nfs_mount(struct nfs_mount_request *info);
......
...@@ -20,8 +20,116 @@ ...@@ -20,8 +20,116 @@
# define NFSDBG_FACILITY NFSDBG_MOUNT # define NFSDBG_FACILITY NFSDBG_MOUNT
#endif #endif
/*
* Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4
*/
#define MNTPATHLEN (1024)
/*
* XDR data type sizes
*/
#define encode_dirpath_sz (1 + XDR_QUADLEN(MNTPATHLEN))
#define MNT_status_sz (1)
#define MNT_fhs_status_sz (1)
#define MNT_fhandle_sz XDR_QUADLEN(NFS2_FHSIZE)
#define MNT_fhandle3_sz (1 + XDR_QUADLEN(NFS3_FHSIZE))
#define MNT_authflav3_sz (1 + NFS_MAX_SECFLAVORS)
/*
* XDR argument and result sizes
*/
#define MNT_enc_dirpath_sz encode_dirpath_sz
#define MNT_dec_mountres_sz (MNT_status_sz + MNT_fhandle_sz)
#define MNT_dec_mountres3_sz (MNT_status_sz + MNT_fhandle_sz + \
MNT_authflav3_sz)
/*
* Defined by RFC 1094, section A.5
*/
enum {
MOUNTPROC_NULL = 0,
MOUNTPROC_MNT = 1,
MOUNTPROC_DUMP = 2,
MOUNTPROC_UMNT = 3,
MOUNTPROC_UMNTALL = 4,
MOUNTPROC_EXPORT = 5,
};
/*
* Defined by RFC 1813, section 5.2
*/
enum {
MOUNTPROC3_NULL = 0,
MOUNTPROC3_MNT = 1,
MOUNTPROC3_DUMP = 2,
MOUNTPROC3_UMNT = 3,
MOUNTPROC3_UMNTALL = 4,
MOUNTPROC3_EXPORT = 5,
};
static struct rpc_program mnt_program; static struct rpc_program mnt_program;
/*
* Defined by OpenGroup XNFS Version 3W, chapter 8
*/
enum mountstat {
MNT_OK = 0,
MNT_EPERM = 1,
MNT_ENOENT = 2,
MNT_EACCES = 13,
MNT_EINVAL = 22,
};
static struct {
u32 status;
int errno;
} mnt_errtbl[] = {
{ .status = MNT_OK, .errno = 0, },
{ .status = MNT_EPERM, .errno = -EPERM, },
{ .status = MNT_ENOENT, .errno = -ENOENT, },
{ .status = MNT_EACCES, .errno = -EACCES, },
{ .status = MNT_EINVAL, .errno = -EINVAL, },
};
/*
* Defined by RFC 1813, section 5.1.5
*/
enum mountstat3 {
MNT3_OK = 0, /* no error */
MNT3ERR_PERM = 1, /* Not owner */
MNT3ERR_NOENT = 2, /* No such file or directory */
MNT3ERR_IO = 5, /* I/O error */
MNT3ERR_ACCES = 13, /* Permission denied */
MNT3ERR_NOTDIR = 20, /* Not a directory */
MNT3ERR_INVAL = 22, /* Invalid argument */
MNT3ERR_NAMETOOLONG = 63, /* Filename too long */
MNT3ERR_NOTSUPP = 10004, /* Operation not supported */
MNT3ERR_SERVERFAULT = 10006, /* A failure on the server */
};
static struct {
u32 status;
int errno;
} mnt3_errtbl[] = {
{ .status = MNT3_OK, .errno = 0, },
{ .status = MNT3ERR_PERM, .errno = -EPERM, },
{ .status = MNT3ERR_NOENT, .errno = -ENOENT, },
{ .status = MNT3ERR_IO, .errno = -EIO, },
{ .status = MNT3ERR_ACCES, .errno = -EACCES, },
{ .status = MNT3ERR_NOTDIR, .errno = -ENOTDIR, },
{ .status = MNT3ERR_INVAL, .errno = -EINVAL, },
{ .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, },
{ .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, },
{ .status = MNT3ERR_SERVERFAULT, .errno = -ESERVERFAULT, },
};
struct mountres {
int errno;
struct nfs_fh *fh;
unsigned int *auth_count;
rpc_authflavor_t *auth_flavors;
};
struct mnt_fhstatus { struct mnt_fhstatus {
u32 status; u32 status;
struct nfs_fh *fh; struct nfs_fh *fh;
...@@ -35,8 +143,10 @@ struct mnt_fhstatus { ...@@ -35,8 +143,10 @@ struct mnt_fhstatus {
*/ */
int nfs_mount(struct nfs_mount_request *info) int nfs_mount(struct nfs_mount_request *info)
{ {
struct mnt_fhstatus result = { struct mountres result = {
.fh = info->fh .fh = info->fh,
.auth_count = info->auth_flav_len,
.auth_flavors = info->auth_flavs,
}; };
struct rpc_message msg = { struct rpc_message msg = {
.rpc_argp = info->dirpath, .rpc_argp = info->dirpath,
...@@ -68,14 +178,14 @@ int nfs_mount(struct nfs_mount_request *info) ...@@ -68,14 +178,14 @@ int nfs_mount(struct nfs_mount_request *info)
if (info->version == NFS_MNT3_VERSION) if (info->version == NFS_MNT3_VERSION)
msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
else else
msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
status = rpc_call_sync(mnt_clnt, &msg, 0); status = rpc_call_sync(mnt_clnt, &msg, 0);
rpc_shutdown_client(mnt_clnt); rpc_shutdown_client(mnt_clnt);
if (status < 0) if (status < 0)
goto out_call_err; goto out_call_err;
if (result.status != 0) if (result.errno != 0)
goto out_mnt_err; goto out_mnt_err;
dprintk("NFS: MNT request succeeded\n"); dprintk("NFS: MNT request succeeded\n");
...@@ -86,72 +196,215 @@ out: ...@@ -86,72 +196,215 @@ out:
out_clnt_err: out_clnt_err:
status = PTR_ERR(mnt_clnt); status = PTR_ERR(mnt_clnt);
dprintk("NFS: failed to create RPC client, status=%d\n", status); dprintk("NFS: failed to create MNT RPC client, status=%d\n", status);
goto out; goto out;
out_call_err: out_call_err:
dprintk("NFS: failed to start MNT request, status=%d\n", status); dprintk("NFS: MNT request failed, status=%d\n", status);
goto out; goto out;
out_mnt_err: out_mnt_err:
dprintk("NFS: MNT server returned result %d\n", result.status); dprintk("NFS: MNT server returned result %d\n", result.errno);
status = nfs_stat_to_errno(result.status); status = result.errno;
goto out; goto out;
} }
/* /*
* XDR encode/decode functions for MOUNT * XDR encode/decode functions for MOUNT
*/ */
static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p,
const char *path) static int encode_mntdirpath(struct xdr_stream *xdr, const char *pathname)
{
const u32 pathname_len = strlen(pathname);
__be32 *p;
if (unlikely(pathname_len > MNTPATHLEN))
return -EIO;
p = xdr_reserve_space(xdr, sizeof(u32) + pathname_len);
if (unlikely(p == NULL))
return -EIO;
xdr_encode_opaque(p, pathname, pathname_len);
return 0;
}
static int mnt_enc_dirpath(struct rpc_rqst *req, __be32 *p,
const char *dirpath)
{
struct xdr_stream xdr;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
return encode_mntdirpath(&xdr, dirpath);
}
/*
* RFC 1094: "A non-zero status indicates some sort of error. In this
* case, the status is a UNIX error number." This can be problematic
* if the server and client use different errno values for the same
* error.
*
* However, the OpenGroup XNFS spec provides a simple mapping that is
* independent of local errno values on the server and the client.
*/
static int decode_status(struct xdr_stream *xdr, struct mountres *res)
{ {
p = xdr_encode_string(p, path); unsigned int i;
u32 status;
__be32 *p;
p = xdr_inline_decode(xdr, sizeof(status));
if (unlikely(p == NULL))
return -EIO;
status = ntohl(*p);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); for (i = 0; i <= ARRAY_SIZE(mnt_errtbl); i++) {
if (mnt_errtbl[i].status == status) {
res->errno = mnt_errtbl[i].errno;
return 0;
}
}
dprintk("NFS: unrecognized MNT status code: %u\n", status);
res->errno = -EACCES;
return 0; return 0;
} }
static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res)
struct mnt_fhstatus *res)
{ {
struct nfs_fh *fh = res->fh; struct nfs_fh *fh = res->fh;
__be32 *p;
p = xdr_inline_decode(xdr, NFS2_FHSIZE);
if (unlikely(p == NULL))
return -EIO;
fh->size = NFS2_FHSIZE;
memcpy(fh->data, p, NFS2_FHSIZE);
return 0;
}
static int mnt_dec_mountres(struct rpc_rqst *req, __be32 *p,
struct mountres *res)
{
struct xdr_stream xdr;
int status;
xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
status = decode_status(&xdr, res);
if (unlikely(status != 0 || res->errno != 0))
return status;
return decode_fhandle(&xdr, res);
}
static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res)
{
unsigned int i;
u32 status;
__be32 *p;
if ((res->status = ntohl(*p++)) == 0) { p = xdr_inline_decode(xdr, sizeof(status));
fh->size = NFS2_FHSIZE; if (unlikely(p == NULL))
memcpy(fh->data, p, NFS2_FHSIZE); return -EIO;
status = ntohl(*p);
for (i = 0; i <= ARRAY_SIZE(mnt3_errtbl); i++) {
if (mnt3_errtbl[i].status == status) {
res->errno = mnt3_errtbl[i].errno;
return 0;
}
} }
dprintk("NFS: unrecognized MNT3 status code: %u\n", status);
res->errno = -EACCES;
return 0; return 0;
} }
static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, static int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res)
struct mnt_fhstatus *res)
{ {
struct nfs_fh *fh = res->fh; struct nfs_fh *fh = res->fh;
unsigned size; u32 size;
__be32 *p;
if ((res->status = ntohl(*p++)) == 0) {
size = ntohl(*p++); p = xdr_inline_decode(xdr, sizeof(size));
if (size <= NFS3_FHSIZE && size != 0) { if (unlikely(p == NULL))
fh->size = size; return -EIO;
memcpy(fh->data, p, size);
} else size = ntohl(*p++);
res->status = -EBADHANDLE; if (size > NFS3_FHSIZE || size == 0)
return -EIO;
p = xdr_inline_decode(xdr, size);
if (unlikely(p == NULL))
return -EIO;
fh->size = size;
memcpy(fh->data, p, size);
return 0;
}
static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res)
{
rpc_authflavor_t *flavors = res->auth_flavors;
unsigned int *count = res->auth_count;
u32 entries, i;
__be32 *p;
if (*count == 0)
return 0;
p = xdr_inline_decode(xdr, sizeof(entries));
if (unlikely(p == NULL))
return -EIO;
entries = ntohl(*p);
dprintk("NFS: received %u auth flavors\n", entries);
if (entries > NFS_MAX_SECFLAVORS)
entries = NFS_MAX_SECFLAVORS;
p = xdr_inline_decode(xdr, sizeof(u32) * entries);
if (unlikely(p == NULL))
return -EIO;
if (entries > *count)
entries = *count;
for (i = 0; i < entries; i++) {
flavors[i] = ntohl(*p++);
dprintk("NFS:\tflavor %u: %d\n", i, flavors[i]);
} }
*count = i;
return 0; return 0;
} }
#define MNT_dirpath_sz (1 + 256) static int mnt_dec_mountres3(struct rpc_rqst *req, __be32 *p,
#define MNT_fhstatus_sz (1 + 8) struct mountres *res)
#define MNT_fhstatus3_sz (1 + 16) {
struct xdr_stream xdr;
int status;
xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
status = decode_fhs_status(&xdr, res);
if (unlikely(status != 0 || res->errno != 0))
return status;
status = decode_fhandle3(&xdr, res);
if (unlikely(status != 0)) {
res->errno = -EBADHANDLE;
return 0;
}
return decode_auth_flavors(&xdr, res);
}
static struct rpc_procinfo mnt_procedures[] = { static struct rpc_procinfo mnt_procedures[] = {
[MNTPROC_MNT] = { [MOUNTPROC_MNT] = {
.p_proc = MNTPROC_MNT, .p_proc = MOUNTPROC_MNT,
.p_encode = (kxdrproc_t) xdr_encode_dirpath, .p_encode = (kxdrproc_t)mnt_enc_dirpath,
.p_decode = (kxdrproc_t) xdr_decode_fhstatus, .p_decode = (kxdrproc_t)mnt_dec_mountres,
.p_arglen = MNT_dirpath_sz, .p_arglen = MNT_enc_dirpath_sz,
.p_replen = MNT_fhstatus_sz, .p_replen = MNT_dec_mountres_sz,
.p_statidx = MNTPROC_MNT, .p_statidx = MOUNTPROC_MNT,
.p_name = "MOUNT", .p_name = "MOUNT",
}, },
}; };
...@@ -159,10 +412,10 @@ static struct rpc_procinfo mnt_procedures[] = { ...@@ -159,10 +412,10 @@ static struct rpc_procinfo mnt_procedures[] = {
static struct rpc_procinfo mnt3_procedures[] = { static struct rpc_procinfo mnt3_procedures[] = {
[MOUNTPROC3_MNT] = { [MOUNTPROC3_MNT] = {
.p_proc = MOUNTPROC3_MNT, .p_proc = MOUNTPROC3_MNT,
.p_encode = (kxdrproc_t) xdr_encode_dirpath, .p_encode = (kxdrproc_t)mnt_enc_dirpath,
.p_decode = (kxdrproc_t) xdr_decode_fhstatus3, .p_decode = (kxdrproc_t)mnt_dec_mountres3,
.p_arglen = MNT_dirpath_sz, .p_arglen = MNT_enc_dirpath_sz,
.p_replen = MNT_fhstatus3_sz, .p_replen = MNT_dec_mountres3_sz,
.p_statidx = MOUNTPROC3_MNT, .p_statidx = MOUNTPROC3_MNT,
.p_name = "MOUNT", .p_name = "MOUNT",
}, },
......
...@@ -207,8 +207,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) ...@@ -207,8 +207,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
status = nfs_revalidate_inode(server, inode); status = nfs_revalidate_inode(server, inode);
if (status < 0) if (status < 0)
return ERR_PTR(status); return ERR_PTR(status);
if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
nfs_zap_acl_cache(inode);
acl = nfs3_get_cached_acl(inode, type); acl = nfs3_get_cached_acl(inode, type);
if (acl != ERR_PTR(-EAGAIN)) if (acl != ERR_PTR(-EAGAIN))
return acl; return acl;
......
...@@ -1173,16 +1173,30 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state ...@@ -1173,16 +1173,30 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
err = _nfs4_open_delegation_recall(ctx, state, stateid); err = _nfs4_open_delegation_recall(ctx, state, stateid);
switch (err) { switch (err) {
case 0: case 0:
return err; case -ENOENT:
case -ESTALE:
goto out;
case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_STALE_STATEID: case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_EXPIRED: case -NFS4ERR_EXPIRED:
/* Don't recall a delegation if it was lost */ /* Don't recall a delegation if it was lost */
nfs4_schedule_state_recovery(server->nfs_client); nfs4_schedule_state_recovery(server->nfs_client);
return err; goto out;
case -ERESTARTSYS:
/*
* The show must go on: exit, but mark the
* stateid as needing recovery.
*/
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_BAD_STATEID:
nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
case -ENOMEM:
err = 0;
goto out;
} }
err = nfs4_handle_exception(server, err, &exception); err = nfs4_handle_exception(server, err, &exception);
} while (exception.retry); } while (exception.retry);
out:
return err; return err;
} }
...@@ -3238,8 +3252,6 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) ...@@ -3238,8 +3252,6 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
ret = nfs_revalidate_inode(server, inode); ret = nfs_revalidate_inode(server, inode);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
nfs_zap_acl_cache(inode);
ret = nfs4_read_cached_acl(inode, buf, buflen); ret = nfs4_read_cached_acl(inode, buf, buflen);
if (ret != -ENOENT) if (ret != -ENOENT)
return ret; return ret;
...@@ -3977,8 +3989,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f ...@@ -3977,8 +3989,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
ret = nfs4_wait_for_completion_rpc_task(task); ret = nfs4_wait_for_completion_rpc_task(task);
if (ret == 0) { if (ret == 0) {
ret = data->rpc_status; ret = data->rpc_status;
if (ret == -NFS4ERR_DENIED)
ret = -EAGAIN;
} else } else
data->cancelled = 1; data->cancelled = 1;
rpc_put_task(task); rpc_put_task(task);
...@@ -4066,9 +4076,11 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock * ...@@ -4066,9 +4076,11 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
int err; int err;
do { do {
err = _nfs4_proc_setlk(state, cmd, request);
if (err == -NFS4ERR_DENIED)
err = -EAGAIN;
err = nfs4_handle_exception(NFS_SERVER(state->inode), err = nfs4_handle_exception(NFS_SERVER(state->inode),
_nfs4_proc_setlk(state, cmd, request), err, &exception);
&exception);
} while (exception.retry); } while (exception.retry);
return err; return err;
} }
...@@ -4120,8 +4132,37 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) ...@@ -4120,8 +4132,37 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
goto out; goto out;
do { do {
err = _nfs4_do_setlk(state, F_SETLK, fl, 0); err = _nfs4_do_setlk(state, F_SETLK, fl, 0);
if (err != -NFS4ERR_DELAY) switch (err) {
break; default:
printk(KERN_ERR "%s: unhandled error %d.\n",
__func__, err);
case 0:
case -ESTALE:
goto out;
case -NFS4ERR_EXPIRED:
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_STALE_STATEID:
nfs4_schedule_state_recovery(server->nfs_client);
goto out;
case -ERESTARTSYS:
/*
* The show must go on: exit, but mark the
* stateid as needing recovery.
*/
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_BAD_STATEID:
case -NFS4ERR_OPENMODE:
nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
err = 0;
goto out;
case -ENOMEM:
case -NFS4ERR_DENIED:
/* kill_proc(fl->fl_pid, SIGLOST, 1); */
err = 0;
goto out;
case -NFS4ERR_DELAY:
break;
}
err = nfs4_handle_exception(server, err, &exception); err = nfs4_handle_exception(server, err, &exception);
} while (exception.retry); } while (exception.retry);
out: out:
......
...@@ -853,32 +853,45 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ ...@@ -853,32 +853,45 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
struct file_lock *fl; struct file_lock *fl;
int status = 0; int status = 0;
if (inode->i_flock == NULL)
return 0;
/* Guard against delegation returns and new lock/unlock calls */
down_write(&nfsi->rwsem); down_write(&nfsi->rwsem);
/* Protect inode->i_flock using the BKL */
lock_kernel();
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
continue; continue;
if (nfs_file_open_context(fl->fl_file)->state != state) if (nfs_file_open_context(fl->fl_file)->state != state)
continue; continue;
unlock_kernel();
status = ops->recover_lock(state, fl); status = ops->recover_lock(state, fl);
if (status >= 0)
continue;
switch (status) { switch (status) {
case 0:
break;
case -ESTALE:
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_BAD_STATEID:
case -NFS4ERR_EXPIRED:
case -NFS4ERR_NO_GRACE:
case -NFS4ERR_STALE_CLIENTID:
goto out;
default: default:
printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
__func__, status); __func__, status);
case -NFS4ERR_EXPIRED: case -ENOMEM:
case -NFS4ERR_NO_GRACE: case -NFS4ERR_DENIED:
case -NFS4ERR_RECLAIM_BAD: case -NFS4ERR_RECLAIM_BAD:
case -NFS4ERR_RECLAIM_CONFLICT: case -NFS4ERR_RECLAIM_CONFLICT:
/* kill_proc(fl->fl_pid, SIGLOST, 1); */ /* kill_proc(fl->fl_pid, SIGLOST, 1); */
break; status = 0;
case -NFS4ERR_STALE_CLIENTID:
goto out_err;
} }
lock_kernel();
} }
up_write(&nfsi->rwsem); unlock_kernel();
return 0; out:
out_err:
up_write(&nfsi->rwsem); up_write(&nfsi->rwsem);
return status; return status;
} }
...@@ -924,6 +937,7 @@ restart: ...@@ -924,6 +937,7 @@ restart:
printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
__func__, status); __func__, status);
case -ENOENT: case -ENOENT:
case -ENOMEM:
case -ESTALE: case -ESTALE:
/* /*
* Open state on this file cannot be recovered * Open state on this file cannot be recovered
...@@ -934,6 +948,9 @@ restart: ...@@ -934,6 +948,9 @@ restart:
/* Mark the file as being 'closed' */ /* Mark the file as being 'closed' */
state->state = 0; state->state = 0;
break; break;
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_BAD_STATEID:
case -NFS4ERR_RECLAIM_BAD: case -NFS4ERR_RECLAIM_BAD:
case -NFS4ERR_RECLAIM_CONFLICT: case -NFS4ERR_RECLAIM_CONFLICT:
nfs4_state_mark_reclaim_nograce(sp->so_client, state); nfs4_state_mark_reclaim_nograce(sp->so_client, state);
......
...@@ -92,6 +92,9 @@ ...@@ -92,6 +92,9 @@
#undef NFSROOT_DEBUG #undef NFSROOT_DEBUG
#define NFSDBG_FACILITY NFSDBG_ROOT #define NFSDBG_FACILITY NFSDBG_ROOT
/* Default port to use if server is not running a portmapper */
#define NFS_MNT_PORT 627
/* Default path we try to mount. "%s" gets replaced by our IP address */ /* Default path we try to mount. "%s" gets replaced by our IP address */
#define NFS_ROOT "/tftpboot/%s" #define NFS_ROOT "/tftpboot/%s"
...@@ -487,6 +490,7 @@ static int __init root_nfs_get_handle(void) ...@@ -487,6 +490,7 @@ static int __init root_nfs_get_handle(void)
{ {
struct nfs_fh fh; struct nfs_fh fh;
struct sockaddr_in sin; struct sockaddr_in sin;
unsigned int auth_flav_len = 0;
struct nfs_mount_request request = { struct nfs_mount_request request = {
.sap = (struct sockaddr *)&sin, .sap = (struct sockaddr *)&sin,
.salen = sizeof(sin), .salen = sizeof(sin),
...@@ -496,6 +500,7 @@ static int __init root_nfs_get_handle(void) ...@@ -496,6 +500,7 @@ static int __init root_nfs_get_handle(void)
.protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP,
.fh = &fh, .fh = &fh,
.auth_flav_len = &auth_flav_len,
}; };
int status; int status;
......
...@@ -140,22 +140,22 @@ static const match_table_t nfs_mount_option_tokens = { ...@@ -140,22 +140,22 @@ static const match_table_t nfs_mount_option_tokens = {
{ Opt_fscache_uniq, "fsc=%s" }, { Opt_fscache_uniq, "fsc=%s" },
{ Opt_nofscache, "nofsc" }, { Opt_nofscache, "nofsc" },
{ Opt_port, "port=%u" }, { Opt_port, "port=%s" },
{ Opt_rsize, "rsize=%u" }, { Opt_rsize, "rsize=%s" },
{ Opt_wsize, "wsize=%u" }, { Opt_wsize, "wsize=%s" },
{ Opt_bsize, "bsize=%u" }, { Opt_bsize, "bsize=%s" },
{ Opt_timeo, "timeo=%u" }, { Opt_timeo, "timeo=%s" },
{ Opt_retrans, "retrans=%u" }, { Opt_retrans, "retrans=%s" },
{ Opt_acregmin, "acregmin=%u" }, { Opt_acregmin, "acregmin=%s" },
{ Opt_acregmax, "acregmax=%u" }, { Opt_acregmax, "acregmax=%s" },
{ Opt_acdirmin, "acdirmin=%u" }, { Opt_acdirmin, "acdirmin=%s" },
{ Opt_acdirmax, "acdirmax=%u" }, { Opt_acdirmax, "acdirmax=%s" },
{ Opt_actimeo, "actimeo=%u" }, { Opt_actimeo, "actimeo=%s" },
{ Opt_namelen, "namlen=%u" }, { Opt_namelen, "namlen=%s" },
{ Opt_mountport, "mountport=%u" }, { Opt_mountport, "mountport=%s" },
{ Opt_mountvers, "mountvers=%u" }, { Opt_mountvers, "mountvers=%s" },
{ Opt_nfsvers, "nfsvers=%u" }, { Opt_nfsvers, "nfsvers=%s" },
{ Opt_nfsvers, "vers=%u" }, { Opt_nfsvers, "vers=%s" },
{ Opt_minorversion, "minorversion=%u" }, { Opt_minorversion, "minorversion=%u" },
{ Opt_sec, "sec=%s" }, { Opt_sec, "sec=%s" },
...@@ -516,7 +516,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, ...@@ -516,7 +516,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
const char *nostr; const char *nostr;
} nfs_info[] = { } nfs_info[] = {
{ NFS_MOUNT_SOFT, ",soft", ",hard" }, { NFS_MOUNT_SOFT, ",soft", ",hard" },
{ NFS_MOUNT_INTR, ",intr", ",nointr" },
{ NFS_MOUNT_POSIX, ",posix", "" }, { NFS_MOUNT_POSIX, ",posix", "" },
{ NFS_MOUNT_NOCTO, ",nocto", "" }, { NFS_MOUNT_NOCTO, ",nocto", "" },
{ NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NOAC, ",noac", "" },
...@@ -945,11 +944,6 @@ static int nfs_parse_security_flavors(char *value, ...@@ -945,11 +944,6 @@ static int nfs_parse_security_flavors(char *value,
return 1; return 1;
} }
static void nfs_parse_invalid_value(const char *option)
{
dfprintk(MOUNT, "NFS: bad value specified for %s option\n", option);
}
/* /*
* Error-check and convert a string of mount options from user space into * Error-check and convert a string of mount options from user space into
* a data structure. The whole mount string is processed; bad options are * a data structure. The whole mount string is processed; bad options are
...@@ -960,7 +954,7 @@ static int nfs_parse_mount_options(char *raw, ...@@ -960,7 +954,7 @@ static int nfs_parse_mount_options(char *raw,
struct nfs_parsed_mount_data *mnt) struct nfs_parsed_mount_data *mnt)
{ {
char *p, *string, *secdata; char *p, *string, *secdata;
int rc, sloppy = 0, errors = 0; int rc, sloppy = 0, invalid_option = 0;
if (!raw) { if (!raw) {
dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
...@@ -984,7 +978,9 @@ static int nfs_parse_mount_options(char *raw, ...@@ -984,7 +978,9 @@ static int nfs_parse_mount_options(char *raw,
while ((p = strsep(&raw, ",")) != NULL) { while ((p = strsep(&raw, ",")) != NULL) {
substring_t args[MAX_OPT_ARGS]; substring_t args[MAX_OPT_ARGS];
int option, token; unsigned long option;
int int_option;
int token;
if (!*p) if (!*p)
continue; continue;
...@@ -1093,114 +1089,156 @@ static int nfs_parse_mount_options(char *raw, ...@@ -1093,114 +1089,156 @@ static int nfs_parse_mount_options(char *raw,
* options that take numeric values * options that take numeric values
*/ */
case Opt_port: case Opt_port:
if (match_int(args, &option) || string = match_strdup(args);
option < 0 || option > USHORT_MAX) { if (string == NULL)
errors++; goto out_nomem;
nfs_parse_invalid_value("port"); rc = strict_strtoul(string, 10, &option);
} else kfree(string);
mnt->nfs_server.port = option; if (rc != 0 || option > USHORT_MAX)
goto out_invalid_value;
mnt->nfs_server.port = option;
break; break;
case Opt_rsize: case Opt_rsize:
if (match_int(args, &option) || option < 0) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("rsize"); goto out_nomem;
} else rc = strict_strtoul(string, 10, &option);
mnt->rsize = option; kfree(string);
if (rc != 0)
goto out_invalid_value;
mnt->rsize = option;
break; break;
case Opt_wsize: case Opt_wsize:
if (match_int(args, &option) || option < 0) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("wsize"); goto out_nomem;
} else rc = strict_strtoul(string, 10, &option);
mnt->wsize = option; kfree(string);
if (rc != 0)
goto out_invalid_value;
mnt->wsize = option;
break; break;
case Opt_bsize: case Opt_bsize:
if (match_int(args, &option) || option < 0) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("bsize"); goto out_nomem;
} else rc = strict_strtoul(string, 10, &option);
mnt->bsize = option; kfree(string);
if (rc != 0)
goto out_invalid_value;
mnt->bsize = option;
break; break;
case Opt_timeo: case Opt_timeo:
if (match_int(args, &option) || option <= 0) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("timeo"); goto out_nomem;
} else rc = strict_strtoul(string, 10, &option);
mnt->timeo = option; kfree(string);
if (rc != 0 || option == 0)
goto out_invalid_value;
mnt->timeo = option;
break; break;
case Opt_retrans: case Opt_retrans:
if (match_int(args, &option) || option <= 0) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("retrans"); goto out_nomem;
} else rc = strict_strtoul(string, 10, &option);
mnt->retrans = option; kfree(string);
if (rc != 0 || option == 0)
goto out_invalid_value;
mnt->retrans = option;
break; break;
case Opt_acregmin: case Opt_acregmin:
if (match_int(args, &option) || option < 0) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("acregmin"); goto out_nomem;
} else rc = strict_strtoul(string, 10, &option);
mnt->acregmin = option; kfree(string);
if (rc != 0)
goto out_invalid_value;
mnt->acregmin = option;
break; break;
case Opt_acregmax: case Opt_acregmax:
if (match_int(args, &option) || option < 0) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("acregmax"); goto out_nomem;
} else rc = strict_strtoul(string, 10, &option);
mnt->acregmax = option; kfree(string);
if (rc != 0)
goto out_invalid_value;
mnt->acregmax = option;
break; break;
case Opt_acdirmin: case Opt_acdirmin:
if (match_int(args, &option) || option < 0) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("acdirmin"); goto out_nomem;
} else rc = strict_strtoul(string, 10, &option);
mnt->acdirmin = option; kfree(string);
if (rc != 0)
goto out_invalid_value;
mnt->acdirmin = option;
break; break;
case Opt_acdirmax: case Opt_acdirmax:
if (match_int(args, &option) || option < 0) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("acdirmax"); goto out_nomem;
} else rc = strict_strtoul(string, 10, &option);
mnt->acdirmax = option; kfree(string);
if (rc != 0)
goto out_invalid_value;
mnt->acdirmax = option;
break; break;
case Opt_actimeo: case Opt_actimeo:
if (match_int(args, &option) || option < 0) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("actimeo"); goto out_nomem;
} else rc = strict_strtoul(string, 10, &option);
mnt->acregmin = mnt->acregmax = kfree(string);
mnt->acdirmin = mnt->acdirmax = option; if (rc != 0)
goto out_invalid_value;
mnt->acregmin = mnt->acregmax =
mnt->acdirmin = mnt->acdirmax = option;
break; break;
case Opt_namelen: case Opt_namelen:
if (match_int(args, &option) || option < 0) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("namlen"); goto out_nomem;
} else rc = strict_strtoul(string, 10, &option);
mnt->namlen = option; kfree(string);
if (rc != 0)
goto out_invalid_value;
mnt->namlen = option;
break; break;
case Opt_mountport: case Opt_mountport:
if (match_int(args, &option) || string = match_strdup(args);
option < 0 || option > USHORT_MAX) { if (string == NULL)
errors++; goto out_nomem;
nfs_parse_invalid_value("mountport"); rc = strict_strtoul(string, 10, &option);
} else kfree(string);
mnt->mount_server.port = option; if (rc != 0 || option > USHORT_MAX)
goto out_invalid_value;
mnt->mount_server.port = option;
break; break;
case Opt_mountvers: case Opt_mountvers:
if (match_int(args, &option) || string = match_strdup(args);
if (string == NULL)
goto out_nomem;
rc = strict_strtoul(string, 10, &option);
kfree(string);
if (rc != 0 ||
option < NFS_MNT_VERSION || option < NFS_MNT_VERSION ||
option > NFS_MNT3_VERSION) { option > NFS_MNT3_VERSION)
errors++; goto out_invalid_value;
nfs_parse_invalid_value("mountvers"); mnt->mount_server.version = option;
} else
mnt->mount_server.version = option;
break; break;
case Opt_nfsvers: case Opt_nfsvers:
if (match_int(args, &option)) { string = match_strdup(args);
errors++; if (string == NULL)
nfs_parse_invalid_value("nfsvers"); goto out_nomem;
break; rc = strict_strtoul(string, 10, &option);
} kfree(string);
if (rc != 0)
goto out_invalid_value;
switch (option) { switch (option) {
case NFS2_VERSION: case NFS2_VERSION:
mnt->flags &= ~NFS_MOUNT_VER3; mnt->flags &= ~NFS_MOUNT_VER3;
...@@ -1209,16 +1247,15 @@ static int nfs_parse_mount_options(char *raw, ...@@ -1209,16 +1247,15 @@ static int nfs_parse_mount_options(char *raw,
mnt->flags |= NFS_MOUNT_VER3; mnt->flags |= NFS_MOUNT_VER3;
break; break;
default: default:
errors++; goto out_invalid_value;
nfs_parse_invalid_value("nfsvers");
} }
break; break;
case Opt_minorversion: case Opt_minorversion:
if (match_int(args, &option)) if (match_int(args, &int_option))
return 0; return 0;
if (option < 0 || option > NFS4_MAX_MINOR_VERSION) if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION)
return 0; return 0;
mnt->minorversion = option; mnt->minorversion = int_option;
break; break;
/* /*
...@@ -1231,9 +1268,9 @@ static int nfs_parse_mount_options(char *raw, ...@@ -1231,9 +1268,9 @@ static int nfs_parse_mount_options(char *raw,
rc = nfs_parse_security_flavors(string, mnt); rc = nfs_parse_security_flavors(string, mnt);
kfree(string); kfree(string);
if (!rc) { if (!rc) {
errors++;
dfprintk(MOUNT, "NFS: unrecognized " dfprintk(MOUNT, "NFS: unrecognized "
"security flavor\n"); "security flavor\n");
return 0;
} }
break; break;
case Opt_proto: case Opt_proto:
...@@ -1247,23 +1284,25 @@ static int nfs_parse_mount_options(char *raw, ...@@ -1247,23 +1284,25 @@ static int nfs_parse_mount_options(char *raw,
case Opt_xprt_udp: case Opt_xprt_udp:
mnt->flags &= ~NFS_MOUNT_TCP; mnt->flags &= ~NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
kfree(string);
break; break;
case Opt_xprt_tcp: case Opt_xprt_tcp:
mnt->flags |= NFS_MOUNT_TCP; mnt->flags |= NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
kfree(string);
break; break;
case Opt_xprt_rdma: case Opt_xprt_rdma:
/* vector side protocols to TCP */ /* vector side protocols to TCP */
mnt->flags |= NFS_MOUNT_TCP; mnt->flags |= NFS_MOUNT_TCP;
mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
xprt_load_transport(string); xprt_load_transport(string);
kfree(string);
break; break;
default: default:
errors++;
dfprintk(MOUNT, "NFS: unrecognized " dfprintk(MOUNT, "NFS: unrecognized "
"transport protocol\n"); "transport protocol\n");
return 0;
} }
kfree(string);
break; break;
case Opt_mountproto: case Opt_mountproto:
string = match_strdup(args); string = match_strdup(args);
...@@ -1282,9 +1321,9 @@ static int nfs_parse_mount_options(char *raw, ...@@ -1282,9 +1321,9 @@ static int nfs_parse_mount_options(char *raw,
break; break;
case Opt_xprt_rdma: /* not used for side protocols */ case Opt_xprt_rdma: /* not used for side protocols */
default: default:
errors++;
dfprintk(MOUNT, "NFS: unrecognized " dfprintk(MOUNT, "NFS: unrecognized "
"transport protocol\n"); "transport protocol\n");
return 0;
} }
break; break;
case Opt_addr: case Opt_addr:
...@@ -1340,9 +1379,9 @@ static int nfs_parse_mount_options(char *raw, ...@@ -1340,9 +1379,9 @@ static int nfs_parse_mount_options(char *raw,
mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
break; break;
default: default:
errors++;
dfprintk(MOUNT, "NFS: invalid " dfprintk(MOUNT, "NFS: invalid "
"lookupcache argument\n"); "lookupcache argument\n");
return 0;
}; };
break; break;
...@@ -1360,20 +1399,20 @@ static int nfs_parse_mount_options(char *raw, ...@@ -1360,20 +1399,20 @@ static int nfs_parse_mount_options(char *raw,
break; break;
default: default:
errors++; invalid_option = 1;
dfprintk(MOUNT, "NFS: unrecognized mount option " dfprintk(MOUNT, "NFS: unrecognized mount option "
"'%s'\n", p); "'%s'\n", p);
} }
} }
if (errors > 0) { if (!sloppy && invalid_option)
dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n", return 0;
errors, (errors == 1 ? "" : "s"));
if (!sloppy)
return 0;
}
return 1; return 1;
out_invalid_value:
printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p);
return 0;
out_nomem: out_nomem:
printk(KERN_INFO "NFS: not enough memory to parse option\n"); printk(KERN_INFO "NFS: not enough memory to parse option\n");
return 0; return 0;
...@@ -1390,6 +1429,7 @@ out_security_failure: ...@@ -1390,6 +1429,7 @@ out_security_failure:
static int nfs_try_mount(struct nfs_parsed_mount_data *args, static int nfs_try_mount(struct nfs_parsed_mount_data *args,
struct nfs_fh *root_fh) struct nfs_fh *root_fh)
{ {
unsigned int auth_flavor_len = 0;
struct nfs_mount_request request = { struct nfs_mount_request request = {
.sap = (struct sockaddr *) .sap = (struct sockaddr *)
&args->mount_server.address, &args->mount_server.address,
...@@ -1397,6 +1437,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, ...@@ -1397,6 +1437,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
.protocol = args->mount_server.protocol, .protocol = args->mount_server.protocol,
.fh = root_fh, .fh = root_fh,
.noresvport = args->flags & NFS_MOUNT_NORESVPORT, .noresvport = args->flags & NFS_MOUNT_NORESVPORT,
.auth_flav_len = &auth_flavor_len,
}; };
int status; int status;
...@@ -2249,6 +2290,11 @@ static void nfs4_fill_super(struct super_block *sb) ...@@ -2249,6 +2290,11 @@ static void nfs4_fill_super(struct super_block *sb)
nfs_initialise_sb(sb); nfs_initialise_sb(sb);
} }
static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
{
args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3);
}
/* /*
* Validate NFSv4 mount options * Validate NFSv4 mount options
*/ */
...@@ -2346,6 +2392,8 @@ static int nfs4_validate_mount_data(void *options, ...@@ -2346,6 +2392,8 @@ static int nfs4_validate_mount_data(void *options,
nfs_validate_transport_protocol(args); nfs_validate_transport_protocol(args);
nfs4_validate_mount_flags(args);
if (args->auth_flavor_len > 1) if (args->auth_flavor_len > 1)
goto out_inval_auth; goto out_inval_auth;
......
...@@ -195,7 +195,7 @@ extern struct svc_procedure nlmsvc_procedures4[]; ...@@ -195,7 +195,7 @@ extern struct svc_procedure nlmsvc_procedures4[];
extern int nlmsvc_grace_period; extern int nlmsvc_grace_period;
extern unsigned long nlmsvc_timeout; extern unsigned long nlmsvc_timeout;
extern int nsm_use_hostnames; extern int nsm_use_hostnames;
extern int nsm_local_state; extern u32 nsm_local_state;
/* /*
* Lockd client functions * Lockd client functions
......
...@@ -25,8 +25,9 @@ ...@@ -25,8 +25,9 @@
#define NFSMODE_SOCK 0140000 #define NFSMODE_SOCK 0140000
#define NFSMODE_FIFO 0010000 #define NFSMODE_FIFO 0010000
#define NFS_MNT_PROGRAM 100005 #define NFS_MNT_PROGRAM 100005
#define NFS_MNT_PORT 627 #define NFS_MNT_VERSION 1
#define NFS_MNT3_VERSION 3
/* /*
* NFS stats. The good thing with these values is that NFSv3 errors are * NFS stats. The good thing with these values is that NFSv3 errors are
......
...@@ -64,11 +64,4 @@ struct nfs2_fh { ...@@ -64,11 +64,4 @@ struct nfs2_fh {
#define NFSPROC_READDIR 16 #define NFSPROC_READDIR 16
#define NFSPROC_STATFS 17 #define NFSPROC_STATFS 17
#define NFS_MNT_PROGRAM 100005
#define NFS_MNT_VERSION 1
#define MNTPROC_NULL 0
#define MNTPROC_MNT 1
#define MNTPROC_UMNT 3
#define MNTPROC_UMNTALL 4
#endif /* _LINUX_NFS2_H */ #endif /* _LINUX_NFS2_H */
...@@ -88,12 +88,7 @@ struct nfs3_fh { ...@@ -88,12 +88,7 @@ struct nfs3_fh {
#define NFS3PROC_PATHCONF 20 #define NFS3PROC_PATHCONF 20
#define NFS3PROC_COMMIT 21 #define NFS3PROC_COMMIT 21
#define NFS_MNT3_PROGRAM 100005
#define NFS_MNT3_VERSION 3 #define NFS_MNT3_VERSION 3
#define MOUNTPROC3_NULL 0
#define MOUNTPROC3_MNT 1
#define MOUNTPROC3_UMNT 3
#define MOUNTPROC3_UMNTALL 4
#if defined(__KERNEL__) #if defined(__KERNEL__)
......
...@@ -1965,6 +1965,7 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt, ...@@ -1965,6 +1965,7 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
*/ */
set_bit(XPRT_CONNECTION_CLOSE, &xprt->state); set_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
xprt_force_disconnect(xprt); xprt_force_disconnect(xprt);
break;
case -ECONNREFUSED: case -ECONNREFUSED:
case -ECONNRESET: case -ECONNRESET:
case -ENETUNREACH: case -ENETUNREACH:
......
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