Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2300fd67 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -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)
	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;
+1 −0
Original line number Original line Diff line number Diff line
@@ -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;
+36 −8
Original line number Original line Diff line number Diff line
@@ -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)
			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,
	};
	};
	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
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
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 *
{
{
	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)


	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))
+19 −12
Original line number Original line Diff line number Diff line
@@ -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,
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,
/**
/**
 * 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)
	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);
	}
}
}


/**
/**
+5 −4
Original line number Original line Diff line number Diff line
@@ -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
 */
 */
	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)
Loading