Skip to content
Snippets Groups Projects
nfs4xdr.c 175 KiB
Newer Older
  • Learn to ignore specific revisions
  • out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*change = 0;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, change);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_CHANGE;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    	dprintk("%s: change attribute=%Lu\n", __func__,
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			(unsigned long long)*change);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*size = 0;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, size);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_SIZE;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    	dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*res = 0;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		*res = be32_to_cpup(p);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT;
    	}
    
    	dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true");
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return 0;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*res = 0;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		*res = be32_to_cpup(p);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT;
    	}
    
    	dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true");
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return 0;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	fsid->major = 0;
    	fsid->minor = 0;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_FSID)) {
    
    		p = xdr_inline_decode(xdr, 16);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		p = xdr_decode_hyper(p, &fsid->major);
    
    		xdr_decode_hyper(p, &fsid->minor);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_FSID;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    	dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			(unsigned long long)fsid->major,
    			(unsigned long long)fsid->minor);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*res = 60;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		*res = be32_to_cpup(p);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
    	}
    
    	dprintk("%s: file size=%u\n", __func__, (unsigned int)*res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return 0;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap, int32_t *res)
    
    {
    	__be32 *p;
    
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_RDATTR_ERROR - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_RDATTR_ERROR)) {
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    		bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
    
    		*res = -be32_to_cpup(p);
    
    	}
    	return 0;
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    }
    
    static int decode_attr_filehandle(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fh *fh)
    {
    	__be32 *p;
    	int len;
    
    
    
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEHANDLE - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_FILEHANDLE)) {
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    		len = be32_to_cpup(p);
    		if (len > NFS4_FHSIZE)
    			return -EIO;
    		p = xdr_inline_decode(xdr, len);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		if (fh != NULL) {
    			memcpy(fh->data, p, len);
    			fh->size = len;
    		}
    
    		bitmap[0] &= ~FATTR4_WORD0_FILEHANDLE;
    	}
    	return 0;
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    }
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		*res = be32_to_cpup(p);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
    	}
    
    	dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return 0;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*fileid = 0;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, fileid);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_FILEID;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    
    	*fileid = 0;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, fileid);
    
    		bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
    
    		ret = NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
    
    	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status = 0;
    
    	*res = 0;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL;
    	}
    
    	dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status = 0;
    
    	*res = 0;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_FILES_FREE;
    	}
    
    	dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status = 0;
    
    	*res = 0;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL;
    	}
    
    	dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    	p = xdr_inline_decode(xdr, 4);
    	if (unlikely(!p))
    		goto out_overflow;
    
    	n = be32_to_cpup(p);
    
    	if (n == 0)
    		goto root_path;
    
    	dprintk("path ");
    	path->ncomponents = 0;
    	while (path->ncomponents < n) {
    		struct nfs4_string *component = &path->components[path->ncomponents];
    		status = decode_opaque_inline(xdr, &component->len, &component->data);
    		if (unlikely(status != 0))
    			goto out_eio;
    		if (path->ncomponents != n)
    			dprintk("/");
    		dprintk("%s", component->data);
    		if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
    			path->ncomponents++;
    		else {
    			dprintk("cannot parse %d components in path\n", n);
    			goto out_eio;
    		}
    	}
    out:
    	dprintk("\n");
    	return status;
    
    root_path:
    /* a root pathname is sent as a zero component4 */
    	path->ncomponents = 1;
    	path->components[0].len=0;
    	path->components[0].data=NULL;
    	dprintk("path /\n");
    	goto out;
    
    out_eio:
    	dprintk(" status %d", status);
    	status = -EIO;
    	goto out;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    }
    
    static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    	int status = -EIO;
    
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
    		goto out;
    	status = 0;
    	if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
    		goto out;
    
    	dprintk("%s: fsroot ", __func__);
    
    	status = decode_pathname(xdr, &res->fs_path);
    
    	if (unlikely(status != 0))
    		goto out;
    
    	p = xdr_inline_decode(xdr, 4);
    	if (unlikely(!p))
    		goto out_overflow;
    
    	n = be32_to_cpup(p);
    
    	if (n <= 0)
    		goto out_eio;
    	res->nlocations = 0;
    	while (res->nlocations < n) {
    
    		struct nfs4_fs_location *loc = &res->locations[res->nlocations];
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		m = be32_to_cpup(p);
    
    		dprintk("%s: servers ", __func__);
    
    		while (loc->nservers < m) {
    			struct nfs4_string *server = &loc->servers[loc->nservers];
    			status = decode_opaque_inline(xdr, &server->len, &server->data);
    			if (unlikely(status != 0))
    				goto out_eio;
    			dprintk("%s ", server->data);
    			if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
    				loc->nservers++;
    			else {
    
    				unsigned int i;
    				dprintk("%s: using first %u of %u servers "
    					"returned for location %u\n",
    
    						NFS4_FS_LOCATION_MAXSERVERS,
    						m, res->nlocations);
    
    				for (i = loc->nservers; i < m; i++) {
    
    					unsigned int len;
    
    					char *data;
    					status = decode_opaque_inline(xdr, &len, &data);
    					if (unlikely(status != 0))
    						goto out_eio;
    				}
    			}
    		}
    		status = decode_pathname(xdr, &loc->rootpath);
    
    		if (unlikely(status != 0))
    			goto out_eio;
    
    		if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
    
    	if (res->nlocations != 0)
    		status = NFS_ATTR_FATTR_V4_REFERRAL;
    
    	dprintk("%s: fs_locations done, error = %d\n", __func__, status);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status = 0;
    
    	*res = 0;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE;
    	}
    
    	dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status = 0;
    
    	*maxlink = 1;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		*maxlink = be32_to_cpup(p);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_MAXLINK;
    	}
    
    	dprintk("%s: maxlink=%u\n", __func__, *maxlink);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status = 0;
    
    	*maxname = 1024;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		*maxname = be32_to_cpup(p);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[0] &= ~FATTR4_WORD0_MAXNAME;
    	}
    
    	dprintk("%s: maxname=%u\n", __func__, *maxname);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status = 0;
    
    	*res = 1024;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXREAD - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) {
    		uint64_t maxread;
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, &maxread);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		if (maxread > 0x7FFFFFFF)
    			maxread = 0x7FFFFFFF;
    		*res = (uint32_t)maxread;
    		bitmap[0] &= ~FATTR4_WORD0_MAXREAD;
    	}
    
    	dprintk("%s: maxread=%lu\n", __func__, (unsigned long)*res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status = 0;
    
    	*res = 1024;
    	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXWRITE - 1U)))
    		return -EIO;
    	if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) {
    		uint64_t maxwrite;
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, &maxwrite);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		if (maxwrite > 0x7FFFFFFF)
    			maxwrite = 0x7FFFFFFF;
    		*res = (uint32_t)maxwrite;
    		bitmap[0] &= ~FATTR4_WORD0_MAXWRITE;
    	}
    
    	dprintk("%s: maxwrite=%lu\n", __func__, (unsigned long)*res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*mode = 0;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		tmp = be32_to_cpup(p);
    
    		*mode = tmp & ~S_IFMT;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[1] &= ~FATTR4_WORD1_MODE;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    	dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*nlink = 1;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		*nlink = be32_to_cpup(p);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    	dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
    
    		const struct nfs_server *server, uint32_t *uid, int may_sleep)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Al Viro's avatar
    Al Viro committed
    	uint32_t len;
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*uid = -2;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		len = be32_to_cpup(p);
    
    		p = xdr_inline_decode(xdr, len);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		if (!may_sleep) {
    			/* do nothing */
    		} else if (len < XDR_MAX_NETOBJ) {
    
    			if (nfs_map_name_to_uid(server, (char *)p, len, uid) == 0)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				dprintk("%s: nfs_map_name_to_uid failed!\n",
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		} else
    
    			dprintk("%s: name too long (%u)!\n",
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[1] &= ~FATTR4_WORD1_OWNER;
    	}
    
    	dprintk("%s: uid=%d\n", __func__, (int)*uid);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
    
    		const struct nfs_server *server, uint32_t *gid, int may_sleep)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Al Viro's avatar
    Al Viro committed
    	uint32_t len;
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*gid = -2;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		len = be32_to_cpup(p);
    
    		p = xdr_inline_decode(xdr, len);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		if (!may_sleep) {
    			/* do nothing */
    		} else if (len < XDR_MAX_NETOBJ) {
    
    			if (nfs_map_group_to_gid(server, (char *)p, len, gid) == 0)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				dprintk("%s: nfs_map_group_to_gid failed!\n",
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		} else
    
    			dprintk("%s: name too long (%u)!\n",
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
    	}
    
    	dprintk("%s: gid=%d\n", __func__, (int)*gid);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
    {
    
    Al Viro's avatar
    Al Viro committed
    	uint32_t major = 0, minor = 0;
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*rdev = MKDEV(0,0);
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) {
    		dev_t tmp;
    
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		major = be32_to_cpup(p++);
    
    		minor = be32_to_cpup(p);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		tmp = MKDEV(major, minor);
    		if (MAJOR(tmp) == major && MINOR(tmp) == minor)
    			*rdev = tmp;
    		bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    	dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status = 0;
    
    	*res = 0;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL;
    	}
    
    	dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status = 0;
    
    	*res = 0;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE;
    	}
    
    	dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status = 0;
    
    	*res = 0;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL;
    	}
    
    	dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	*used = 0;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) {
    
    		p = xdr_inline_decode(xdr, 8);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		xdr_decode_hyper(p, used);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    	dprintk("%s: space used=%Lu\n", __func__,
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			(unsigned long long)*used);
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	uint64_t sec;
    	uint32_t nsec;
    
    
    	p = xdr_inline_decode(xdr, 12);
    	if (unlikely(!p))
    		goto out_overflow;
    
    	p = xdr_decode_hyper(p, &sec);
    
    	nsec = be32_to_cpup(p);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	time->tv_sec = (time_t)sec;
    	time->tv_nsec = (long)nsec;
    	return 0;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
    {
    	int status = 0;
    
    	time->tv_sec = 0;
    	time->tv_nsec = 0;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_ACCESS - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
    		status = decode_attr_time(xdr, time);
    
    		if (status == 0)
    			status = NFS_ATTR_FATTR_ATIME;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
    	}
    
    	dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    }
    
    static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
    {
    	int status = 0;
    
    	time->tv_sec = 0;
    	time->tv_nsec = 0;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
    		status = decode_attr_time(xdr, time);
    
    		if (status == 0)
    			status = NFS_ATTR_FATTR_CTIME;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
    	}
    
    	dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    }
    
    
    static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
    				  struct timespec *time)
    {
    	int status = 0;
    
    	time->tv_sec = 0;
    	time->tv_nsec = 0;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_DELTA - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_TIME_DELTA)) {
    		status = decode_attr_time(xdr, time);
    		bitmap[1] &= ~FATTR4_WORD1_TIME_DELTA;
    	}
    	dprintk("%s: time_delta=%ld %ld\n", __func__, (long)time->tv_sec,
    		(long)time->tv_nsec);
    	return status;
    }
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
    {
    	int status = 0;
    
    	time->tv_sec = 0;
    	time->tv_nsec = 0;
    	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U)))
    		return -EIO;
    	if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
    		status = decode_attr_time(xdr, time);
    
    		if (status == 0)
    			status = NFS_ATTR_FATTR_MTIME;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
    	}
    
    	dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return status;
    }
    
    
    Al Viro's avatar
    Al Viro committed
    static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	unsigned int attrwords = XDR_QUADLEN(attrlen);
    	unsigned int nwords = xdr->p - savep;
    
    	if (unlikely(attrwords != nwords)) {
    
    		dprintk("%s: server returned incorrect attribute length: "
    			"%u %c %u\n",
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				attrwords << 2,
    				(attrwords < nwords) ? '<' : '>',
    				nwords << 2);
    		return -EIO;
    	}
    	return 0;
    }
    
    static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	p = xdr_inline_decode(xdr, 20);
    	if (unlikely(!p))
    		goto out_overflow;
    
    	cinfo->atomic = be32_to_cpup(p++);
    
    	p = xdr_decode_hyper(p, &cinfo->before);
    
    	xdr_decode_hyper(p, &cinfo->after);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return 0;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	uint32_t supp, acc;
    	int status;
    
    	status = decode_op_hdr(xdr, OP_ACCESS);
    	if (status)
    		return status;
    
    	p = xdr_inline_decode(xdr, 8);
    	if (unlikely(!p))
    		goto out_overflow;
    
    	supp = be32_to_cpup(p++);
    
    	acc = be32_to_cpup(p);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	access->supported = supp;
    	access->access = acc;
    	return 0;
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    
    static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    
    	p = xdr_inline_decode(xdr, len);
    	if (likely(p)) {
    		memcpy(buf, p, len);
    		return 0;
    	}
    	print_overflow_msg(__func__, xdr);
    	return -EIO;
    }
    
    static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
    {
    	return decode_opaque_fixed(xdr, stateid->data, NFS4_STATEID_SIZE);
    }
    
    static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
    {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int status;
    
    	status = decode_op_hdr(xdr, OP_CLOSE);
    
    	if (status != -EIO)
    		nfs_increment_open_seqid(status, res->seqid);
    
    	if (!status)
    		status = decode_stateid(xdr, &res->stateid);
    	return status;
    
    static int decode_verifier(struct xdr_stream *xdr, void *verifier)
    {
    	return decode_opaque_fixed(xdr, verifier, 8);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
    {
    	int status;
    
    	status = decode_op_hdr(xdr, OP_COMMIT);
    
    	if (!status)
    		status = decode_verifier(xdr, res->verf->verifier);