Commit message: NFSv4: Convert the open and close ops to use fmode

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
CVE: CVE-2011-4324
CWE: CWE-703
Vulnerability description: The encode_share_access function in fs/nfs/nfs4xdr.c in the Linux kernel before 2.6.29 allows local users to cause a denial of service (BUG and system crash) by using the mknod system call with a pathname on an NFSv4 filesystem.

Project: linux
File: inode.c

static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred)
{
	struct nfs_open_context *ctx;

	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
	if (ctx != NULL) {
		ctx->path.dentry = dget(dentry);
		ctx->path.mnt = mntget(mnt);
		ctx->cred = get_rpccred(cred);
		ctx->state = NULL;
		ctx->lockowner = current->files;
		ctx->flags = 0;
		ctx->error = 0;
		ctx->dir_cookie = 0;
		atomic_set(&ctx->count, 1);
	}
	return ctx;
}

Project: linux
File: inode.c

int nfs_attribute_timeout(struct inode *inode)
{
	struct nfs_inode *nfsi = NFS_I(inode);

	if (nfs_have_delegation(inode, FMODE_READ))
		return 0;
	/*
	 * Special case: if the attribute timeout is set to 0, then always
	 * 		 treat the cache as having expired (unless holding
	 * 		 a delegation).
	 */
	if (nfsi->attrtimeo == 0)
		return 1;
	return !time_in_range(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
}

Project: linux
File: inode.c

int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
{
	int status;

	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
		return 0;
	spin_lock(&inode->i_lock);
	status = nfs_refresh_inode_locked(inode, fattr);
	spin_unlock(&inode->i_lock);
	return status;
}

Project: linux
File: inode.c

int nfs_sync_mapping(struct address_space *mapping)
{
	int ret;

	if (mapping->nrpages == 0)
		return 0;
	unmap_mapping_range(mapping, 0, 0, 0);
	ret = filemap_write_and_wait(mapping);
	if (ret != 0)
		goto out;
	ret = nfs_wb_all(mapping->host);
out:
	return ret;
}

Project: linux
File: inode.c

static int nfs_vmtruncate(struct inode * inode, loff_t offset)
{
	if (i_size_read(inode) < offset) {
		unsigned long limit;

		limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
		if (limit != RLIM_INFINITY && offset > limit)
			goto out_sig;
		if (offset > inode->i_sb->s_maxbytes)
			goto out_big;
		spin_lock(&inode->i_lock);
		i_size_write(inode, offset);
		spin_unlock(&inode->i_lock);
	} else {
		struct address_space *mapping = inode->i_mapping;

		/*
		 * truncation of in-use swapfiles is disallowed - it would
		 * cause subsequent swapout to scribble on the now-freed
		 * blocks.
		 */
		if (IS_SWAPFILE(inode))
			return -ETXTBSY;
		spin_lock(&inode->i_lock);
		i_size_write(inode, offset);
		spin_unlock(&inode->i_lock);

		/*
		 * unmap_mapping_range is called twice, first simply for
		 * efficiency so that truncate_inode_pages does fewer
		 * single-page unmaps.  However after this first call, and
		 * before truncate_inode_pages finishes, it is possible for
		 * private pages to be COWed, which remain after
		 * truncate_inode_pages finishes, hence the second
		 * unmap_mapping_range call must be made for correctness.
		 */
		unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
		truncate_inode_pages(mapping, offset);
		unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
	}
	return 0;
out_sig:
	send_sig(SIGXFSZ, current, 0);
out_big:
	return -EFBIG;
}

Project: linux
File: inode.c

void nfs_zap_caches(struct inode *inode)
{
	spin_lock(&inode->i_lock);
	nfs_zap_caches_locked(inode);
	spin_unlock(&inode->i_lock);
}

Project: linux
File: nfs4proc.c

static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
{
	struct nfs4_opendata *opendata;
	int ret;

	opendata = nfs4_open_recoverdata_alloc(ctx, state);
	if (IS_ERR(opendata))
		return PTR_ERR(opendata);
	opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;
	memcpy(opendata->o_arg.u.delegation.data, stateid->data,
			sizeof(opendata->o_arg.u.delegation.data));
	ret = nfs4_open_recover(opendata, state);
	nfs4_opendata_put(opendata);
	return ret;
}

Project: linux
File: nfs4proc.c

static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
{
	struct nfs_server *server = NFS_SERVER(state->inode);
	struct nfs4_exception exception = { };
	int err;

	do {
		err = _nfs4_open_expired(ctx, state);
		if (err == -NFS4ERR_DELAY)
			nfs4_handle_exception(server, err, &exception);
	} while (exception.retry);
	return err;
}

Project: linux
File: nfs4proc.c

static void nfs4_free_closedata(void *data)
{
	struct nfs4_closedata *calldata = data;
	struct nfs4_state_owner *sp = calldata->state->owner;

	nfs4_put_open_state(calldata->state);
	nfs_free_seqid(calldata->arg.seqid);
	nfs4_put_state_owner(sp);
	path_put(&calldata->path);
	kfree(calldata);
}

Project: linux
File: nfs4proc.c

ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf,
		size_t buflen)
{
	struct inode *inode = dentry->d_inode;

	if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
		return -EOPNOTSUPP;

	return nfs4_proc_get_acl(inode, buf, buflen);
}

Project: linux
File: nfs4proc.c

ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
{
	size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1;

	if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode)))
		return 0;
	if (buf && buflen < len)
		return -ERANGE;
	if (buf)
		memcpy(buf, XATTR_NAME_NFSV4_ACL, len);
	return len;
}

Project: linux
File: nfs4proc.c

int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
{
	struct nfs_server *server = NFS_SERVER(state->inode);
	struct nfs4_exception exception = { };
	int err;

	err = nfs4_set_lock_state(state, fl);
	if (err != 0)
		goto out;
	do {
		err = _nfs4_do_setlk(state, F_SETLK, fl, 0);
		if (err != -NFS4ERR_DELAY)
			break;
		err = nfs4_handle_exception(server, err, &exception);
	} while (exception.retry);
out:
	return err;
}

Project: linux
File: nfs4proc.c

static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
{
	struct nfs4_lockdata *data = calldata;
	struct nfs4_state *state = data->lsp->ls_state;

	dprintk("%s: begin!\n", __func__);
	if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
		return;
	/* Do we need to do an open_to_lock_owner? */
	if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
		if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0)
			return;
		data->arg.open_stateid = &state->stateid;
		data->arg.new_lock_owner = 1;
		data->res.open_seqid = data->arg.open_seqid;
	} else
		data->arg.new_lock_owner = 0;
	data->timestamp = jiffies;
	rpc_call_start(task);
	dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
}

Project: linux
File: nfs4proc.c

int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred)
{
	struct rpc_message msg = {
		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_RENEW],
		.rpc_argp	= clp,
		.rpc_cred	= cred,
	};

	return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT,
			&nfs4_renew_ops, (void *)jiffies);
}

Project: linux
File: nfs4proc.c

static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
		struct iattr *sattr)
{
	struct nfs4_exception exception = { };
	int err;
	do {
		err = nfs4_handle_exception(NFS_SERVER(dir),
				_nfs4_proc_mkdir(dir, dentry, sattr),
				&exception);
	} while (exception.retry);
	return err;
}

Project: linux
File: nfs4proc.c

static int nfs4_wait_clnt_recover(struct nfs_client *clp)
{
	int res;

	might_sleep();

	res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
			nfs4_wait_bit_killable, TASK_KILLABLE);
	return res;
}

Project: linux
File: nfs4proc.c

static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
{
	struct inode *inode = data->inode;
	
	if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
		rpc_restart_call(task);
		return -EAGAIN;
	}
	if (task->tk_status >= 0) {
		renew_lease(NFS_SERVER(inode), data->timestamp);
		nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
	}
	return 0;
}

Project: linux
File: nfs4state.c

static void nfs4_clear_machine_cred(struct nfs_client *clp)
{
	struct rpc_cred *cred;

	spin_lock(&clp->cl_lock);
	cred = clp->cl_machine_cred;
	clp->cl_machine_cred = NULL;
	spin_unlock(&clp->cl_lock);
	if (cred != NULL)
		put_rpccred(cred);
}

Project: linux
File: nfs4state.c

struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
{
	struct nfs4_state_owner *sp;
	struct rb_node *pos;
	struct rpc_cred *cred = NULL;

	for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
		if (list_empty(&sp->so_states))
			continue;
		cred = get_rpccred(sp->so_cred);
		break;
	}
	return cred;
}

Project: linux
File: nfs4state.c

static void nfs4_state_manager(struct nfs_client *clp)
{
	int status = 0;

	/* Ensure exclusive access to NFSv4 state */
	for(;;) {
		if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
			/* We're going to have to re-establish a clientid */
			status = nfs4_reclaim_lease(clp);
			if (status) {
				set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
				if (status == -EAGAIN)
					continue;
				goto out_error;
			}
			clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
		}

		if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
			status = nfs4_check_lease(clp);
			if (status != 0)
				continue;
		}

		/* First recover reboot state... */
		if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
			status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops);
			if (status == -NFS4ERR_STALE_CLIENTID)
				continue;
			nfs4_state_end_reclaim_reboot(clp);
			continue;
		}

		/* Now recover expired state... */
		if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
			status = nfs4_do_reclaim(clp, &nfs4_nograce_recovery_ops);
			if (status < 0) {
				set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
				if (status == -NFS4ERR_STALE_CLIENTID)
					continue;
				if (status == -NFS4ERR_EXPIRED)
					continue;
				goto out_error;
			} else
				nfs4_state_end_reclaim_nograce(clp);
			continue;
		}

		if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
			nfs_client_return_marked_delegations(clp);
			continue;
		}

		nfs4_clear_state_manager_bit(clp);
		/* Did we race with an attempt to give us more work? */
		if (clp->cl_state == 0)
			break;
		if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
			break;
	}
	return;
out_error:
	printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
			" with error %d\n", clp->cl_hostname, -status);
	if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
		nfs4_state_end_reclaim_reboot(clp);
	nfs4_clear_state_manager_bit(clp);
}

Project: linux
File: nfs4state.c

static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp, int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
{
	struct nfs4_state_owner *sp;
	struct rb_node *pos;
	struct nfs4_state *state;

	/* Reset all sequence ids to zero */
	for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
		sp->so_seqid.flags = 0;
		spin_lock(&sp->so_lock);
		list_for_each_entry(state, &sp->so_states, open_states) {
			if (mark_reclaim(clp, state))
				nfs4_clear_open_state(state);
		}
		spin_unlock(&sp->so_lock);
	}
}

Project: linux
File: nfs4state.c

static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new,
		__u64 minval, int maxbits)
{
	struct rb_node **p, *parent;
	struct nfs_unique_id *pos;
	__u64 mask = ~0ULL;

	if (maxbits < 64)
		mask = (1ULL << maxbits) - 1ULL;

	/* Ensure distribution is more or less flat */
	get_random_bytes(&new->id, sizeof(new->id));
	new->id &= mask;
	if (new->id < minval)
		new->id += minval;
retry:
	p = &root->rb_node;
	parent = NULL;

	while (*p != NULL) {
		parent = *p;
		pos = rb_entry(parent, struct nfs_unique_id, rb_node);

		if (new->id < pos->id)
			p = &(*p)->rb_left;
		else if (new->id > pos->id)
			p = &(*p)->rb_right;
		else
			goto id_exists;
	}
	rb_link_node(&new->rb_node, parent, p);
	rb_insert_color(&new->rb_node, root);
	return;
id_exists:
	for (;;) {
		new->id++;
		if (new->id < minval || (new->id & mask) != new->id) {
			new->id = minval;
			break;
		}
		parent = rb_next(parent);
		if (parent == NULL)
			break;
		pos = rb_entry(parent, struct nfs_unique_id, rb_node);
		if (new->id < pos->id)
			break;
	}
	goto retry;
}

Project: linux
File: nfs4state.c

void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
{
	nfs_increment_seqid(status, seqid);
}

Project: linux
File: nfs4xdr.c

static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
{
	__be32 *p;

	*change = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
		READ_BUF(8);
		READ64(*change);
		bitmap[0] &= ~FATTR4_WORD0_CHANGE;
	}
	dprintk("%s: change attribute=%Lu\n", __func__,
			(unsigned long long)*change);
	return 0;
}

Project: linux
File: nfs4xdr.c

static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
	__be32 *p;

	READ_BUF(8);
	READ32(hdr->status);
	READ32(hdr->taglen);
	
	READ_BUF(hdr->taglen + 4);
	hdr->tag = (char *)p;
	p += XDR_QUADLEN(hdr->taglen);
	READ32(hdr->nops);
	return 0;
}

Project: linux
File: nfs4xdr.c

static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
		size_t *acl_len)
{
	__be32 *savep;
	uint32_t attrlen,
		 bitmap[2] = {0};
	struct kvec *iov = req->rq_rcv_buf.head;
	int status;

	*acl_len = 0;
	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto out;
	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
		goto out;
	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
		goto out;

	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
		size_t hdrlen;
		u32 recvd;

		/* We ignore &savep and don't do consistency checks on
		 * the attr length.  Let userspace figure it out.... */
		hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
		recvd = req->rq_rcv_buf.len - hdrlen;
		if (attrlen > recvd) {
			dprintk("NFS: server cheating in getattr"
					" acl reply: attrlen %u > recvd %u\n",
					attrlen, recvd);
			return -EINVAL;
		}
		xdr_read_pages(xdr, attrlen);
		*acl_len = attrlen;
	} else
		status = -EOPNOTSUPP;

out:
	return status;
}

Project: linux
File: nfs4xdr.c

static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
{
	__be32 *p;
	int status;

	status = decode_op_hdr(xdr, OP_LOCK);
	if (status == -EIO)
		goto out;
	if (status == 0) {
		READ_BUF(NFS4_STATEID_SIZE);
		COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
	} else if (status == -NFS4ERR_DENIED)
		status = decode_lock_denied(xdr, NULL);
	if (res->open_seqid != NULL)
		nfs_increment_open_seqid(status, res->open_seqid);
	nfs_increment_lock_seqid(status, res->lock_seqid);
out:
	return status;
}

Project: linux
File: nfs4xdr.c

static int decode_putfh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_PUTFH);
}

Project: linux
File: nfs4xdr.c

static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
{
	__be32 *p;
	uint32_t opnum;
	int32_t nfserr;

	READ_BUF(8);
	READ32(opnum);
	if (opnum != OP_SETCLIENTID) {
		dprintk("nfs: decode_setclientid: Server returned operation"
			       	" %d\n", opnum);
		return -EIO;
	}
	READ32(nfserr);
	if (nfserr == NFS_OK) {
		READ_BUF(8 + NFS4_VERIFIER_SIZE);
		READ64(clp->cl_clientid);
		COPYMEM(clp->cl_confirm.data, NFS4_VERIFIER_SIZE);
	} else if (nfserr == NFSERR_CLID_INUSE) {
		uint32_t len;

		/* skip netid string */
		READ_BUF(4);
		READ32(len);
		READ_BUF(len);

		/* skip uaddr string */
		READ_BUF(4);
		READ32(len);
		READ_BUF(len);
		return -NFSERR_CLID_INUSE;
	} else
		return nfs4_stat_to_errno(nfserr);

	return 0;
}

Project: linux
File: nfs4xdr.c

static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
{
        __be32 *p;
	uint32_t limit_type, nblocks, blocksize;

	READ_BUF(12);
	READ32(limit_type);
	switch (limit_type) {
		case 1:
			READ64(*maxsize);
			break;
		case 2:
			READ32(nblocks);
			READ32(blocksize);
			*maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
	}
	return 0;
}

Project: linux
File: nfs4xdr.c

static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
{
	__be32 *p;
	int status;

	status = decode_op_hdr(xdr, OP_WRITE);
	if (status)
		return status;

	READ_BUF(16);
	READ32(res->count);
	READ32(res->verf->committed);
	COPYMEM(res->verf->verifier, 8);
	return 0;
}

Project: linux
File: nfs4xdr.c

static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type)
{
	__be32 *p;

	RESERVE_SPACE(4);
	WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
	encode_delegation_type(xdr, type);
}

Project: linux
File: nfs4xdr.c

static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
	__be32 *p;

	dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
	BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
	RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2));
	WRITE32(hdr->taglen);
	WRITEMEM(hdr->tag, hdr->taglen);
	WRITE32(NFS4_MINOR_VERSION);
	WRITE32(hdr->nops);
	return 0;
}

Project: linux
File: nfs4xdr.c

static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid)
{
	__be32 *p;

	RESERVE_SPACE(4+NFS4_STATEID_SIZE);

	WRITE32(OP_DELEGRETURN);
	WRITEMEM(stateid->data, NFS4_STATEID_SIZE);
	return 0;

}

Project: linux
File: nfs4xdr.c

static int encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask)
{
	return encode_getattr_two(xdr,
				  bitmask[0] & nfs4_fs_locations_bitmap[0],
				  bitmask[1] & nfs4_fs_locations_bitmap[1]);
}

Project: linux
File: nfs4xdr.c

static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask)
{
	return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
			bitmask[1] & nfs4_fsinfo_bitmap[1]);
}

Project: linux
File: nfs4xdr.c

static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
{
	__be32 *p;

	RESERVE_SPACE(32);
	WRITE32(OP_LOCK);
	WRITE32(nfs4_lock_type(args->fl, args->block));
	WRITE32(args->reclaim);
	WRITE64(args->fl->fl_start);
	WRITE64(nfs4_lock_length(args->fl));
	WRITE32(args->new_lock_owner);
	if (args->new_lock_owner){
		RESERVE_SPACE(4+NFS4_STATEID_SIZE+32);
		WRITE32(args->open_seqid->sequence->counter);
		WRITEMEM(args->open_stateid->data, NFS4_STATEID_SIZE);
		WRITE32(args->lock_seqid->sequence->counter);
		WRITE64(args->lock_owner.clientid);
		WRITE32(16);
		WRITEMEM("lock id:", 8);
		WRITE64(args->lock_owner.id);
	}
	else {
		RESERVE_SPACE(NFS4_STATEID_SIZE+4);
		WRITEMEM(args->lock_stateid->data, NFS4_STATEID_SIZE);
		WRITE32(args->lock_seqid->sequence->counter);
	}

	return 0;
}

Project: linux
File: nfs4xdr.c

static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req)
{
	uint32_t attrs[2] = {
		FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
		FATTR4_WORD1_MOUNTED_ON_FILEID,
	};
	__be32 *p;

	RESERVE_SPACE(12+NFS4_VERIFIER_SIZE+20);
	WRITE32(OP_READDIR);
	WRITE64(readdir->cookie);
	WRITEMEM(readdir->verifier.data, NFS4_VERIFIER_SIZE);
	WRITE32(readdir->count >> 1);  /* We're not doing readdirplus */
	WRITE32(readdir->count);
	WRITE32(2);
	/* Switch to mounted_on_fileid if the server supports it */
	if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
		attrs[0] &= ~FATTR4_WORD0_FILEID;
	else
		attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
	WRITE32(attrs[0] & readdir->bitmask[0]);
	WRITE32(attrs[1] & readdir->bitmask[1]);
	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
			__func__,
			(unsigned long long)readdir->cookie,
			((u32 *)readdir->verifier.data)[0],
			((u32 *)readdir->verifier.data)[1],
			attrs[0] & readdir->bitmask[0],
			attrs[1] & readdir->bitmask[1]);

	return 0;
}

Project: linux
File: nfs4xdr.c

static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
{
	__be32 *p;

	RESERVE_SPACE(8 + name->len);
	WRITE32(OP_REMOVE);
	WRITE32(name->len);
	WRITEMEM(name->name, name->len);

	return 0;
}

Project: linux
File: nfs4xdr.c

static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
{
	nfs4_stateid stateid;
	__be32 *p;

	RESERVE_SPACE(NFS4_STATEID_SIZE);
	if (ctx->state != NULL) {
		nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner);
		WRITEMEM(stateid.data, NFS4_STATEID_SIZE);
	} else
		WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE);
}

Project: linux
File: nfs4xdr.c

static inline int nfs4_lock_type(struct file_lock *fl, int block)
{
	if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK)
		return block ? NFS4_READW_LT : NFS4_READ_LT;
	return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
}

Project: linux
File: nfs4xdr.c

static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_commit(&xdr, res);
	if (status)
		goto out;
	decode_getfattr(&xdr, res->fattr, res->server);
out:
	return status;
}

Project: linux
File: nfs4xdr.c

static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (!status)
		status = decode_putfh(&xdr);
	if (!status)
		status = decode_pathconf(&xdr, pathconf);
	return status;
}

Project: linux
File: nfs4xdr.c

static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
		.nops = 3,
	};
	int status;

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
	encode_compound_hdr(&xdr, &hdr);
	status = encode_putfh(&xdr, args->fh);
	if (status != 0)
		goto out;
	status = encode_access(&xdr, args->access);
	if (status != 0)
		goto out;
	status = encode_getfattr(&xdr, args->bitmask);
out:
	return status;
}

Project: linux
File: nfs4xdr.c

static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
		.nops = 3,
	};
	int status;

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
	encode_compound_hdr(&xdr, &hdr);
	status = encode_putfh(&xdr, args->fh);
	if (status)
		goto out;
	status = encode_commit(&xdr, args);
	if (status)
		goto out;
	status = encode_getfattr(&xdr, args->bitmask);
out:
	return status;
}

Project: linux
File: nfs4xdr.c

static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
		.nops = 3,
	};
	int status;

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
	encode_compound_hdr(&xdr, &hdr);
	if ((status = encode_putfh(&xdr, args->fh)) != 0)
		goto out;
	if ((status = encode_remove(&xdr, &args->name)) != 0)
		goto out;
	status = encode_getfattr(&xdr, args->bitmask);
out:
	return status;
}

Project: linux
File: nfs4xdr.c

static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
{
	return nfs4_xdr_enc_create(req, p, args);
}