diff options
Diffstat (limited to 'fs/nfs')
| -rw-r--r-- | fs/nfs/dir.c | 4 | ||||
| -rw-r--r-- | fs/nfs/nfs4_fs.h | 1 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 44 | ||||
| -rw-r--r-- | fs/nfs/nfs4state.c | 31 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 9 | ||||
| -rw-r--r-- | fs/nfs/read.c | 2 | ||||
| -rw-r--r-- | fs/nfs/super.c | 8 | ||||
| -rw-r--r-- | fs/nfs/write.c | 5 | 
8 files changed, 73 insertions, 31 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 4aaf0316d76..8789210c690 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -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; diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 97ecc863dd7..b6db9e33fb7 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -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; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f82bde005a8..60d5f4c26dd 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -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)) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0f43414eb25..7f0fcfc1fe9 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -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 @@ out:  /**   * 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);  }  /** diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index c74fdb114b4..77fc5f959c4 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -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) diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 9a0e8ef4a40..0a4be28c2ea 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -322,7 +322,7 @@ out_bad:  	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; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 37412f706b3..1e6715f0616 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -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; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 2c68818f68a..c07462320f6 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -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 @@ out_bad:  	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;  |