Commit 2300fd67 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 86ec090e 7bf97bc2
...@@ -1429,7 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry ...@@ -1429,7 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
} }
open_flags = nd->intent.open.flags; open_flags = nd->intent.open.flags;
attr.ia_valid = 0; attr.ia_valid = ATTR_OPEN;
ctx = create_nfs_open_context(dentry, open_flags); ctx = create_nfs_open_context(dentry, open_flags);
res = ERR_CAST(ctx); res = ERR_CAST(ctx);
...@@ -1536,7 +1536,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -1536,7 +1536,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
if (IS_ERR(ctx)) if (IS_ERR(ctx))
goto out; goto out;
attr.ia_valid = 0; attr.ia_valid = ATTR_OPEN;
if (openflags & O_TRUNC) { if (openflags & O_TRUNC) {
attr.ia_valid |= ATTR_SIZE; attr.ia_valid |= ATTR_SIZE;
attr.ia_size = 0; attr.ia_size = 0;
......
...@@ -59,6 +59,7 @@ struct nfs_unique_id { ...@@ -59,6 +59,7 @@ struct nfs_unique_id {
#define NFS_SEQID_CONFIRMED 1 #define NFS_SEQID_CONFIRMED 1
struct nfs_seqid_counter { struct nfs_seqid_counter {
ktime_t create_time;
int owner_id; int owner_id;
int flags; int flags;
u32 counter; u32 counter;
......
...@@ -838,7 +838,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, ...@@ -838,7 +838,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
p->o_arg.open_flags = flags; p->o_arg.open_flags = flags;
p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
p->o_arg.clientid = server->nfs_client->cl_clientid; 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.name = &dentry->d_name;
p->o_arg.server = server; p->o_arg.server = server;
p->o_arg.bitmask = server->attr_bitmask; p->o_arg.bitmask = server->attr_bitmask;
...@@ -1466,8 +1467,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) ...@@ -1466,8 +1467,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
goto unlock_no_action; goto unlock_no_action;
rcu_read_unlock(); rcu_read_unlock();
} }
/* Update sequence id. */ /* Update client id. */
data->o_arg.id = sp->so_seqid.owner_id;
data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid; data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; 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, ...@@ -1954,10 +1954,19 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
}; };
int err; int err;
do { do {
err = nfs4_handle_exception(server, err = _nfs4_do_setattr(inode, cred, fattr, sattr, state);
_nfs4_do_setattr(inode, cred, fattr, sattr, state), switch (err) {
&exception); 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); } while (exception.retry);
out:
return err; return err;
} }
...@@ -4558,7 +4567,9 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f ...@@ -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) static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
{ {
struct nfs_server *server = NFS_SERVER(state->inode); struct nfs_server *server = NFS_SERVER(state->inode);
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.inode = state->inode,
};
int err; int err;
do { do {
...@@ -4576,7 +4587,9 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request ...@@ -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) static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request)
{ {
struct nfs_server *server = NFS_SERVER(state->inode); struct nfs_server *server = NFS_SERVER(state->inode);
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.inode = state->inode,
};
int err; int err;
err = nfs4_set_lock_state(state, request); 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 * ...@@ -4676,6 +4689,7 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
{ {
struct nfs4_exception exception = { struct nfs4_exception exception = {
.state = state, .state = state,
.inode = state->inode,
}; };
int err; int err;
...@@ -4721,6 +4735,20 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) ...@@ -4721,6 +4735,20 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
if (state == NULL) if (state == NULL)
return -ENOLCK; 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 { do {
status = nfs4_proc_setlk(state, cmd, request); status = nfs4_proc_setlk(state, cmd, request);
if ((status != -EAGAIN) || IS_SETLK(cmd)) if ((status != -EAGAIN) || IS_SETLK(cmd))
......
...@@ -393,6 +393,7 @@ nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp) ...@@ -393,6 +393,7 @@ nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
static void static void
nfs4_init_seqid_counter(struct nfs_seqid_counter *sc) nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
{ {
sc->create_time = ktime_get();
sc->flags = 0; sc->flags = 0;
sc->counter = 0; sc->counter = 0;
spin_lock_init(&sc->lock); spin_lock_init(&sc->lock);
...@@ -434,13 +435,17 @@ nfs4_alloc_state_owner(struct nfs_server *server, ...@@ -434,13 +435,17 @@ nfs4_alloc_state_owner(struct nfs_server *server,
static void static void
nfs4_drop_state_owner(struct nfs4_state_owner *sp) 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_server *server = sp->so_server;
struct nfs_client *clp = server->nfs_client; struct nfs_client *clp = server->nfs_client;
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
rb_erase(&sp->so_server_node, &server->state_owners); if (!RB_EMPTY_NODE(rb_node)) {
RB_CLEAR_NODE(&sp->so_server_node); rb_erase(rb_node, &server->state_owners);
RB_CLEAR_NODE(rb_node);
}
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
} }
} }
...@@ -516,6 +521,14 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, ...@@ -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 * nfs4_put_state_owner - Release a nfs4_state_owner
* @sp: state owner data to release * @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) void nfs4_put_state_owner(struct nfs4_state_owner *sp)
{ {
...@@ -525,15 +538,9 @@ 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)) if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
return; return;
if (!RB_EMPTY_NODE(&sp->so_server_node)) { sp->so_expires = jiffies;
sp->so_expires = jiffies; list_add_tail(&sp->so_lru, &server->state_owners_lru);
list_add_tail(&sp->so_lru, &server->state_owners_lru); spin_unlock(&clp->cl_lock);
spin_unlock(&clp->cl_lock);
} else {
nfs4_remove_state_owner_locked(sp);
spin_unlock(&clp->cl_lock);
nfs4_free_state_owner(sp);
}
} }
/** /**
......
...@@ -74,7 +74,7 @@ static int nfs4_stat_to_errno(int); ...@@ -74,7 +74,7 @@ static int nfs4_stat_to_errno(int);
/* lock,open owner id: /* lock,open owner id:
* we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2) * 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 lock_owner_id_maxsz (1 + 1 + 4)
#define decode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) #define decode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
#define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) #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 ...@@ -1340,12 +1340,13 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
*/ */
encode_nfs4_seqid(xdr, arg->seqid); encode_nfs4_seqid(xdr, arg->seqid);
encode_share_access(xdr, arg->fmode); encode_share_access(xdr, arg->fmode);
p = reserve_space(xdr, 32); p = reserve_space(xdr, 36);
p = xdr_encode_hyper(p, arg->clientid); 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 = xdr_encode_opaque_fixed(p, "open id:", 8);
*p++ = cpu_to_be32(arg->server->s_dev); *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) 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 ...@@ -322,7 +322,7 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head
while (!list_empty(res)) { while (!list_empty(res)) {
data = list_entry(res->next, struct nfs_read_data, list); data = list_entry(res->next, struct nfs_read_data, list);
list_del(&data->list); list_del(&data->list);
nfs_readdata_free(data); nfs_readdata_release(data);
} }
nfs_readpage_release(req); nfs_readpage_release(req);
return -ENOMEM; return -ENOMEM;
......
...@@ -2767,11 +2767,15 @@ static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, ...@@ -2767,11 +2767,15 @@ static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
char *root_devname; char *root_devname;
size_t len; size_t len;
len = strlen(hostname) + 3; len = strlen(hostname) + 5;
root_devname = kmalloc(len, GFP_KERNEL); root_devname = kmalloc(len, GFP_KERNEL);
if (root_devname == NULL) if (root_devname == NULL)
return ERR_PTR(-ENOMEM); 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); root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data);
kfree(root_devname); kfree(root_devname);
return root_mnt; return root_mnt;
......
...@@ -682,7 +682,8 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode, ...@@ -682,7 +682,8 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
req->wb_bytes = rqend - req->wb_offset; req->wb_bytes = rqend - req->wb_offset;
out_unlock: out_unlock:
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
nfs_clear_request_commit(req); if (req)
nfs_clear_request_commit(req);
return req; return req;
out_flushme: out_flushme:
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
...@@ -1018,7 +1019,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head ...@@ -1018,7 +1019,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head
while (!list_empty(res)) { while (!list_empty(res)) {
data = list_entry(res->next, struct nfs_write_data, list); data = list_entry(res->next, struct nfs_write_data, list);
list_del(&data->list); list_del(&data->list);
nfs_writedata_free(data); nfs_writedata_release(data);
} }
nfs_redirty_request(req); nfs_redirty_request(req);
return -ENOMEM; return -ENOMEM;
......
...@@ -312,6 +312,11 @@ struct nfs4_layoutreturn { ...@@ -312,6 +312,11 @@ struct nfs4_layoutreturn {
int rpc_status; int rpc_status;
}; };
struct stateowner_id {
__u64 create_time;
__u32 uniquifier;
};
/* /*
* Arguments to the open call. * Arguments to the open call.
*/ */
...@@ -321,7 +326,7 @@ struct nfs_openargs { ...@@ -321,7 +326,7 @@ struct nfs_openargs {
int open_flags; int open_flags;
fmode_t fmode; fmode_t fmode;
__u64 clientid; __u64 clientid;
__u64 id; struct stateowner_id id;
union { union {
struct { struct {
struct iattr * attrs; /* UNCHECKED, GUARDED */ struct iattr * attrs; /* UNCHECKED, GUARDED */
......
...@@ -75,19 +75,20 @@ static struct pernet_operations sunrpc_net_ops = { ...@@ -75,19 +75,20 @@ static struct pernet_operations sunrpc_net_ops = {
static int __init static int __init
init_sunrpc(void) init_sunrpc(void)
{ {
int err = register_rpc_pipefs(); int err = rpc_init_mempool();
if (err) if (err)
goto out; goto out;
err = rpc_init_mempool();
if (err)
goto out2;
err = rpcauth_init_module(); err = rpcauth_init_module();
if (err) if (err)
goto out3; goto out2;
cache_initialize(); cache_initialize();
err = register_pernet_subsys(&sunrpc_net_ops); err = register_pernet_subsys(&sunrpc_net_ops);
if (err)
goto out3;
err = register_rpc_pipefs();
if (err) if (err)
goto out4; goto out4;
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
...@@ -98,11 +99,11 @@ init_sunrpc(void) ...@@ -98,11 +99,11 @@ init_sunrpc(void)
return 0; return 0;
out4: out4:
rpcauth_remove_module(); unregister_pernet_subsys(&sunrpc_net_ops);
out3: out3:
rpc_destroy_mempool(); rpcauth_remove_module();
out2: out2:
unregister_rpc_pipefs(); rpc_destroy_mempool();
out: out:
return err; return err;
} }
......
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