NFS client bugfixes for Linux 3.4
Highlights include: - Fix NFSv4 infinite loops on open(O_TRUNC) - Fix an Oops and an infinite loop in the NFSv4 flock code - Don't register the PipeFS filesystem until it has been set up - Fix an Oops in nfs_try_to_update_request - Don't reuse NFSv4 open owners: fixes a bad sequence id storm. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJPlbzwAAoJEGcL54qWCgDy24oQALZE67vBft7M2j0BiWhVbV15 YLbCf6x/h+0BJAkKWdrBaw7N6GX6OYBOX2SsmrBkzYf5mgHeju5+dH0CmRAR5xib 5d+Lwxif1l+rABfdzzJf8gY1L1THyJCnfmarKKyYEJ5OC1pJyulKLanXSPzPfzlm APV5Jf6NM2WRgkCqzP6zf61NG0HbDSR7C//HQ3k21Sdt9XDLf5qLHBSuPIQ+BlZY EvpbERTtJgp7rPJsLQv1F2dgasDUQNg8G+tmZatGcqEiNxVyQ2YqwshaldOVqftv 3Kocs6OW5C1ESj1dFJZmeMZ/+GSHjRJx8fpqHJjmCsh4kPGgFviQDdYwu4FDhhPI FZslC5nVi8JMTPNJAFmfvbwPQId/TSRPCWYO5PtW1LSfRT/+25b6M5duro1eGIbJ /FDoOCYQmepNOfobU9Q3roDWyNSLYFaUaMJUrccRcAuS3S2NEXisTAT49kmqa1Vm ZArOJBnXTgmGi30nKhqqLJ43P61ekhX0AQ6PycZAXkjeRlkQs7AAQbMJZMB2X0r9 KtRCDPiH2NuR0FwxNMkMP4BXdsaY7Sz/xiSZXLOUf1SeWBiBtYoDdrQ3z67SGOeG qxI3qXXl0KC2+l2jnezcWhBf4CDpxftGIBi+rKWJt8stoYzbemB/M1lkoTCwrVzq 8Gwyy0QTVzE9VkY77oVW =hQAK -----END PGP SIGNATURE----- Merge tag 'nfs-for-3.4-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client bugfixes from Trond Myklebust: - Fix NFSv4 infinite loops on open(O_TRUNC) - Fix an Oops and an infinite loop in the NFSv4 flock code - Don't register the PipeFS filesystem until it has been set up - Fix an Oops in nfs_try_to_update_request - Don't reuse NFSv4 open owners: fixes a bad sequence id storm. * tag 'nfs-for-3.4-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFSv4: Keep dropped state owners on the LRU list for a while NFSv4: Ensure that we don't drop a state owner more than once NFSv4: Ensure we do not reuse open owner names nfs: Enclose hostname in brackets when needed in nfs_do_root_mount NFS: put open context on error in nfs_flush_multi NFS: put open context on error in nfs_pagein_multi NFSv4: Fix open(O_TRUNC) and ftruncate() error handling NFSv4: Ensure that we check lock exclusive/shared type against open modes NFSv4: Ensure that the LOCK code sets exception->inode NFS: check for req==NULL in nfs_try_to_update_request cleanup SUNRPC: register PipeFS file system after pernet sybsystem
This commit is contained in:
commit
2300fd67b4
10 changed files with 88 additions and 40 deletions
|
@ -1429,7 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
|
|||
}
|
||||
|
||||
open_flags = nd->intent.open.flags;
|
||||
attr.ia_valid = 0;
|
||||
attr.ia_valid = ATTR_OPEN;
|
||||
|
||||
ctx = create_nfs_open_context(dentry, open_flags);
|
||||
res = ERR_CAST(ctx);
|
||||
|
@ -1536,7 +1536,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|||
if (IS_ERR(ctx))
|
||||
goto out;
|
||||
|
||||
attr.ia_valid = 0;
|
||||
attr.ia_valid = ATTR_OPEN;
|
||||
if (openflags & O_TRUNC) {
|
||||
attr.ia_valid |= ATTR_SIZE;
|
||||
attr.ia_size = 0;
|
||||
|
|
|
@ -59,6 +59,7 @@ struct nfs_unique_id {
|
|||
|
||||
#define NFS_SEQID_CONFIRMED 1
|
||||
struct nfs_seqid_counter {
|
||||
ktime_t create_time;
|
||||
int owner_id;
|
||||
int flags;
|
||||
u32 counter;
|
||||
|
|
|
@ -838,7 +838,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
|
|||
p->o_arg.open_flags = flags;
|
||||
p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
|
||||
p->o_arg.clientid = server->nfs_client->cl_clientid;
|
||||
p->o_arg.id = sp->so_seqid.owner_id;
|
||||
p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);
|
||||
p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
|
||||
p->o_arg.name = &dentry->d_name;
|
||||
p->o_arg.server = server;
|
||||
p->o_arg.bitmask = server->attr_bitmask;
|
||||
|
@ -1466,8 +1467,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
|
|||
goto unlock_no_action;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
/* Update sequence id. */
|
||||
data->o_arg.id = sp->so_seqid.owner_id;
|
||||
/* Update client id. */
|
||||
data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
|
||||
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
|
||||
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
|
||||
|
@ -1954,10 +1954,19 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
|||
};
|
||||
int err;
|
||||
do {
|
||||
err = nfs4_handle_exception(server,
|
||||
_nfs4_do_setattr(inode, cred, fattr, sattr, state),
|
||||
&exception);
|
||||
err = _nfs4_do_setattr(inode, cred, fattr, sattr, state);
|
||||
switch (err) {
|
||||
case -NFS4ERR_OPENMODE:
|
||||
if (state && !(state->state & FMODE_WRITE)) {
|
||||
err = -EBADF;
|
||||
if (sattr->ia_valid & ATTR_OPEN)
|
||||
err = -EACCES;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
err = nfs4_handle_exception(server, err, &exception);
|
||||
} while (exception.retry);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -4558,7 +4567,9 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
|
|||
static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(state->inode);
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.inode = state->inode,
|
||||
};
|
||||
int err;
|
||||
|
||||
do {
|
||||
|
@ -4576,7 +4587,9 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
|
|||
static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(state->inode);
|
||||
struct nfs4_exception exception = { };
|
||||
struct nfs4_exception exception = {
|
||||
.inode = state->inode,
|
||||
};
|
||||
int err;
|
||||
|
||||
err = nfs4_set_lock_state(state, request);
|
||||
|
@ -4676,6 +4689,7 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
|
|||
{
|
||||
struct nfs4_exception exception = {
|
||||
.state = state,
|
||||
.inode = state->inode,
|
||||
};
|
||||
int err;
|
||||
|
||||
|
@ -4721,6 +4735,20 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
|
|||
|
||||
if (state == NULL)
|
||||
return -ENOLCK;
|
||||
/*
|
||||
* Don't rely on the VFS having checked the file open mode,
|
||||
* since it won't do this for flock() locks.
|
||||
*/
|
||||
switch (request->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) {
|
||||
case F_RDLCK:
|
||||
if (!(filp->f_mode & FMODE_READ))
|
||||
return -EBADF;
|
||||
break;
|
||||
case F_WRLCK:
|
||||
if (!(filp->f_mode & FMODE_WRITE))
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
do {
|
||||
status = nfs4_proc_setlk(state, cmd, request);
|
||||
if ((status != -EAGAIN) || IS_SETLK(cmd))
|
||||
|
|
|
@ -393,6 +393,7 @@ nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
|
|||
static void
|
||||
nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
|
||||
{
|
||||
sc->create_time = ktime_get();
|
||||
sc->flags = 0;
|
||||
sc->counter = 0;
|
||||
spin_lock_init(&sc->lock);
|
||||
|
@ -434,13 +435,17 @@ nfs4_alloc_state_owner(struct nfs_server *server,
|
|||
static void
|
||||
nfs4_drop_state_owner(struct nfs4_state_owner *sp)
|
||||
{
|
||||
if (!RB_EMPTY_NODE(&sp->so_server_node)) {
|
||||
struct rb_node *rb_node = &sp->so_server_node;
|
||||
|
||||
if (!RB_EMPTY_NODE(rb_node)) {
|
||||
struct nfs_server *server = sp->so_server;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
rb_erase(&sp->so_server_node, &server->state_owners);
|
||||
RB_CLEAR_NODE(&sp->so_server_node);
|
||||
if (!RB_EMPTY_NODE(rb_node)) {
|
||||
rb_erase(rb_node, &server->state_owners);
|
||||
RB_CLEAR_NODE(rb_node);
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
}
|
||||
}
|
||||
|
@ -516,6 +521,14 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
|
|||
/**
|
||||
* nfs4_put_state_owner - Release a nfs4_state_owner
|
||||
* @sp: state owner data to release
|
||||
*
|
||||
* Note that we keep released state owners on an LRU
|
||||
* list.
|
||||
* This caches valid state owners so that they can be
|
||||
* reused, to avoid the OPEN_CONFIRM on minor version 0.
|
||||
* It also pins the uniquifier of dropped state owners for
|
||||
* a while, to ensure that those state owner names are
|
||||
* never reused.
|
||||
*/
|
||||
void nfs4_put_state_owner(struct nfs4_state_owner *sp)
|
||||
{
|
||||
|
@ -525,15 +538,9 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp)
|
|||
if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
|
||||
return;
|
||||
|
||||
if (!RB_EMPTY_NODE(&sp->so_server_node)) {
|
||||
sp->so_expires = jiffies;
|
||||
list_add_tail(&sp->so_lru, &server->state_owners_lru);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
} else {
|
||||
nfs4_remove_state_owner_locked(sp);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nfs4_free_state_owner(sp);
|
||||
}
|
||||
sp->so_expires = jiffies;
|
||||
list_add_tail(&sp->so_lru, &server->state_owners_lru);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -74,7 +74,7 @@ static int nfs4_stat_to_errno(int);
|
|||
/* lock,open owner id:
|
||||
* we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2)
|
||||
*/
|
||||
#define open_owner_id_maxsz (1 + 1 + 4)
|
||||
#define open_owner_id_maxsz (1 + 2 + 1 + 1 + 2)
|
||||
#define lock_owner_id_maxsz (1 + 1 + 4)
|
||||
#define decode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
|
||||
#define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2))
|
||||
|
@ -1340,12 +1340,13 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
|
|||
*/
|
||||
encode_nfs4_seqid(xdr, arg->seqid);
|
||||
encode_share_access(xdr, arg->fmode);
|
||||
p = reserve_space(xdr, 32);
|
||||
p = reserve_space(xdr, 36);
|
||||
p = xdr_encode_hyper(p, arg->clientid);
|
||||
*p++ = cpu_to_be32(20);
|
||||
*p++ = cpu_to_be32(24);
|
||||
p = xdr_encode_opaque_fixed(p, "open id:", 8);
|
||||
*p++ = cpu_to_be32(arg->server->s_dev);
|
||||
xdr_encode_hyper(p, arg->id);
|
||||
*p++ = cpu_to_be32(arg->id.uniquifier);
|
||||
xdr_encode_hyper(p, arg->id.create_time);
|
||||
}
|
||||
|
||||
static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
|
||||
|
|
|
@ -322,7 +322,7 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head
|
|||
while (!list_empty(res)) {
|
||||
data = list_entry(res->next, struct nfs_read_data, list);
|
||||
list_del(&data->list);
|
||||
nfs_readdata_free(data);
|
||||
nfs_readdata_release(data);
|
||||
}
|
||||
nfs_readpage_release(req);
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -2767,11 +2767,15 @@ static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
|
|||
char *root_devname;
|
||||
size_t len;
|
||||
|
||||
len = strlen(hostname) + 3;
|
||||
len = strlen(hostname) + 5;
|
||||
root_devname = kmalloc(len, GFP_KERNEL);
|
||||
if (root_devname == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
snprintf(root_devname, len, "%s:/", hostname);
|
||||
/* Does hostname needs to be enclosed in brackets? */
|
||||
if (strchr(hostname, ':'))
|
||||
snprintf(root_devname, len, "[%s]:/", hostname);
|
||||
else
|
||||
snprintf(root_devname, len, "%s:/", hostname);
|
||||
root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data);
|
||||
kfree(root_devname);
|
||||
return root_mnt;
|
||||
|
|
|
@ -682,7 +682,8 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
|
|||
req->wb_bytes = rqend - req->wb_offset;
|
||||
out_unlock:
|
||||
spin_unlock(&inode->i_lock);
|
||||
nfs_clear_request_commit(req);
|
||||
if (req)
|
||||
nfs_clear_request_commit(req);
|
||||
return req;
|
||||
out_flushme:
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
@ -1018,7 +1019,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head
|
|||
while (!list_empty(res)) {
|
||||
data = list_entry(res->next, struct nfs_write_data, list);
|
||||
list_del(&data->list);
|
||||
nfs_writedata_free(data);
|
||||
nfs_writedata_release(data);
|
||||
}
|
||||
nfs_redirty_request(req);
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -312,6 +312,11 @@ struct nfs4_layoutreturn {
|
|||
int rpc_status;
|
||||
};
|
||||
|
||||
struct stateowner_id {
|
||||
__u64 create_time;
|
||||
__u32 uniquifier;
|
||||
};
|
||||
|
||||
/*
|
||||
* Arguments to the open call.
|
||||
*/
|
||||
|
@ -321,7 +326,7 @@ struct nfs_openargs {
|
|||
int open_flags;
|
||||
fmode_t fmode;
|
||||
__u64 clientid;
|
||||
__u64 id;
|
||||
struct stateowner_id id;
|
||||
union {
|
||||
struct {
|
||||
struct iattr * attrs; /* UNCHECKED, GUARDED */
|
||||
|
|
|
@ -75,19 +75,20 @@ static struct pernet_operations sunrpc_net_ops = {
|
|||
static int __init
|
||||
init_sunrpc(void)
|
||||
{
|
||||
int err = register_rpc_pipefs();
|
||||
int err = rpc_init_mempool();
|
||||
if (err)
|
||||
goto out;
|
||||
err = rpc_init_mempool();
|
||||
if (err)
|
||||
goto out2;
|
||||
err = rpcauth_init_module();
|
||||
if (err)
|
||||
goto out3;
|
||||
goto out2;
|
||||
|
||||
cache_initialize();
|
||||
|
||||
err = register_pernet_subsys(&sunrpc_net_ops);
|
||||
if (err)
|
||||
goto out3;
|
||||
|
||||
err = register_rpc_pipefs();
|
||||
if (err)
|
||||
goto out4;
|
||||
#ifdef RPC_DEBUG
|
||||
|
@ -98,11 +99,11 @@ init_sunrpc(void)
|
|||
return 0;
|
||||
|
||||
out4:
|
||||
rpcauth_remove_module();
|
||||
unregister_pernet_subsys(&sunrpc_net_ops);
|
||||
out3:
|
||||
rpc_destroy_mempool();
|
||||
rpcauth_remove_module();
|
||||
out2:
|
||||
unregister_rpc_pipefs();
|
||||
rpc_destroy_mempool();
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue