Skip to content
Snippets Groups Projects
nfs4xdr.c 189 KiB
Newer Older
  • Learn to ignore specific revisions
  • Andy Adamson's avatar
    Andy Adamson committed
    }
    
    
    /*
     * Decode SECINFO_NO_NAME response
     */
    static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp,
    					struct xdr_stream *xdr,
    					struct nfs4_secinfo_res *res)
    {
    	struct compound_hdr hdr;
    	int status;
    
    	status = decode_compound_hdr(xdr, &hdr);
    	if (status)
    		goto out;
    	status = decode_sequence(xdr, &res->seq_res, rqstp);
    	if (status)
    		goto out;
    	status = decode_putrootfh(xdr);
    	if (status)
    		goto out;
    
    	status = decode_secinfo_no_name(xdr, res);
    
    out:
    	return status;
    }
    
    
    /*
     * Decode TEST_STATEID response
     */
    static int nfs4_xdr_dec_test_stateid(struct rpc_rqst *rqstp,
    				     struct xdr_stream *xdr,
    				     struct nfs41_test_stateid_res *res)
    {
    	struct compound_hdr hdr;
    	int status;
    
    	status = decode_compound_hdr(xdr, &hdr);
    	if (status)
    		goto out;
    	status = decode_sequence(xdr, &res->seq_res, rqstp);
    	if (status)
    		goto out;
    	status = decode_test_stateid(xdr, res);
    out:
    	return status;
    }
    
    
    /*
     * Decode FREE_STATEID response
     */
    static int nfs4_xdr_dec_free_stateid(struct rpc_rqst *rqstp,
    				     struct xdr_stream *xdr,
    				     struct nfs41_free_stateid_res *res)
    {
    	struct compound_hdr hdr;
    	int status;
    
    	status = decode_compound_hdr(xdr, &hdr);
    	if (status)
    		goto out;
    	status = decode_sequence(xdr, &res->seq_res, rqstp);
    	if (status)
    		goto out;
    	status = decode_free_stateid(xdr, res);
    out:
    	return status;
    }
    
    #endif /* CONFIG_NFS_V4_1 */
    
    
    /**
     * nfs4_decode_dirent - Decode a single NFSv4 directory entry stored in
     *                      the local page cache.
     * @xdr: XDR stream where entry resides
     * @entry: buffer to fill in with entry data
     * @plus: boolean indicating whether this should be a readdirplus entry
     *
     * Returns zero if successful, otherwise a negative errno value is
     * returned.
     *
     * This function is not invoked during READDIR reply decoding, but
     * rather whenever an application invokes the getdents(2) system call
     * on a directory already in our cache.
     */
    int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
    		       int plus)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	uint32_t bitmap[3] = {0};
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	uint32_t len;
    
    	__be32 *p = xdr_inline_decode(xdr, 4);
    	if (unlikely(!p))
    		goto out_overflow;
    
    	if (*p == xdr_zero) {
    
    		p = xdr_inline_decode(xdr, 4);
    		if (unlikely(!p))
    			goto out_overflow;
    
    		if (*p == xdr_zero)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		entry->eof = 1;
    
    		return -EBADCOOKIE;
    
    	p = xdr_inline_decode(xdr, 12);
    	if (unlikely(!p))
    		goto out_overflow;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	entry->prev_cookie = entry->cookie;
    	p = xdr_decode_hyper(p, &entry->cookie);
    
    	entry->len = be32_to_cpup(p);
    
    	p = xdr_inline_decode(xdr, entry->len);
    
    	if (unlikely(!p))
    		goto out_overflow;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	entry->name = (const char *) p;
    
    	/*
    	 * In case the server doesn't return an inode number,
    	 * we fake one here.  (We don't use inode number 0,
    	 * since glibc seems to choke on it...)
    	 */
    	entry->ino = 1;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	if (decode_attr_bitmap(xdr, bitmap) < 0)
    		goto out_overflow;
    
    
    	if (decode_attr_length(xdr, &len, &savep) < 0)
    
    		goto out_overflow;
    
    
    	if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
    
    		goto out_overflow;
    
    	if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
    		entry->ino = entry->fattr->mounted_on_fileid;
    	else if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
    
    		entry->ino = entry->fattr->fileid;
    
    
    	entry->d_type = DT_UNKNOWN;
    	if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
    		entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
    
    
    
    out_overflow:
    	print_overflow_msg(__func__, xdr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    /*
     * We need to translate between nfs status return values and
     * the local errno values which may not be the same.
     */
    static struct {
    	int stat;
    	int errno;
    } nfs_errtbl[] = {
    	{ NFS4_OK,		0		},
    
    	{ NFS4ERR_PERM,		-EPERM		},
    	{ NFS4ERR_NOENT,	-ENOENT		},
    	{ NFS4ERR_IO,		-errno_NFSERR_IO},
    	{ NFS4ERR_NXIO,		-ENXIO		},
    	{ NFS4ERR_ACCESS,	-EACCES		},
    	{ NFS4ERR_EXIST,	-EEXIST		},
    	{ NFS4ERR_XDEV,		-EXDEV		},
    	{ NFS4ERR_NOTDIR,	-ENOTDIR	},
    	{ NFS4ERR_ISDIR,	-EISDIR		},
    	{ NFS4ERR_INVAL,	-EINVAL		},
    	{ NFS4ERR_FBIG,		-EFBIG		},
    	{ NFS4ERR_NOSPC,	-ENOSPC		},
    	{ NFS4ERR_ROFS,		-EROFS		},
    	{ NFS4ERR_MLINK,	-EMLINK		},
    	{ NFS4ERR_NAMETOOLONG,	-ENAMETOOLONG	},
    	{ NFS4ERR_NOTEMPTY,	-ENOTEMPTY	},
    	{ NFS4ERR_DQUOT,	-EDQUOT		},
    	{ NFS4ERR_STALE,	-ESTALE		},
    	{ NFS4ERR_BADHANDLE,	-EBADHANDLE	},
    	{ NFS4ERR_BAD_COOKIE,	-EBADCOOKIE	},
    	{ NFS4ERR_NOTSUPP,	-ENOTSUPP	},
    	{ NFS4ERR_TOOSMALL,	-ETOOSMALL	},
    
    	{ NFS4ERR_SERVERFAULT,	-EREMOTEIO	},
    
    	{ NFS4ERR_BADTYPE,	-EBADTYPE	},
    	{ NFS4ERR_LOCKED,	-EAGAIN		},
    	{ NFS4ERR_SYMLINK,	-ELOOP		},
    	{ NFS4ERR_OP_ILLEGAL,	-EOPNOTSUPP	},
    	{ NFS4ERR_DEADLOCK,	-EDEADLK	},
    	{ -1,			-EIO		}
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    };
    
    /*
     * Convert an NFS error code to a local one.
     * This one is used jointly by NFSv2 and NFSv3.
     */
    static int
    
    nfs4_stat_to_errno(int stat)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	int i;
    	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
    		if (nfs_errtbl[i].stat == stat)
    			return nfs_errtbl[i].errno;
    	}
    	if (stat <= 10000 || stat > 10100) {
    		/* The server is looney tunes. */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    	/* If we cannot translate the error, the recovery routines should
    	 * handle it.
    	 * Note: remaining NFSv4 error codes have values > 10000, so should
    	 * not conflict with native Linux error codes.
    	 */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    #define PROC(proc, argtype, restype)				\
    [NFSPROC4_CLNT_##proc] = {					\
    	.p_proc   = NFSPROC4_COMPOUND,				\
    
    	.p_encode = (kxdreproc_t)nfs4_xdr_##argtype,		\
    
    	.p_decode = (kxdrdproc_t)nfs4_xdr_##restype,		\
    
    	.p_arglen = NFS4_##argtype##_sz,			\
    	.p_replen = NFS4_##restype##_sz,			\
    
    	.p_statidx = NFSPROC4_CLNT_##proc,			\
    	.p_name   = #proc,					\
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    struct rpc_procinfo	nfs4_procedures[] = {
    
    	PROC(READ,		enc_read,		dec_read),
    	PROC(WRITE,		enc_write,		dec_write),
    	PROC(COMMIT,		enc_commit,		dec_commit),
    	PROC(OPEN,		enc_open,		dec_open),
    	PROC(OPEN_CONFIRM,	enc_open_confirm,	dec_open_confirm),
    	PROC(OPEN_NOATTR,	enc_open_noattr,	dec_open_noattr),
    	PROC(OPEN_DOWNGRADE,	enc_open_downgrade,	dec_open_downgrade),
    	PROC(CLOSE,		enc_close,		dec_close),
    	PROC(SETATTR,		enc_setattr,		dec_setattr),
    	PROC(FSINFO,		enc_fsinfo,		dec_fsinfo),
    	PROC(RENEW,		enc_renew,		dec_renew),
    	PROC(SETCLIENTID,	enc_setclientid,	dec_setclientid),
    	PROC(SETCLIENTID_CONFIRM, enc_setclientid_confirm, dec_setclientid_confirm),
    	PROC(LOCK,		enc_lock,		dec_lock),
    	PROC(LOCKT,		enc_lockt,		dec_lockt),
    	PROC(LOCKU,		enc_locku,		dec_locku),
    	PROC(ACCESS,		enc_access,		dec_access),
    	PROC(GETATTR,		enc_getattr,		dec_getattr),
    	PROC(LOOKUP,		enc_lookup,		dec_lookup),
    	PROC(LOOKUP_ROOT,	enc_lookup_root,	dec_lookup_root),
    	PROC(REMOVE,		enc_remove,		dec_remove),
    	PROC(RENAME,		enc_rename,		dec_rename),
    	PROC(LINK,		enc_link,		dec_link),
    	PROC(SYMLINK,		enc_symlink,		dec_symlink),
    	PROC(CREATE,		enc_create,		dec_create),
    	PROC(PATHCONF,		enc_pathconf,		dec_pathconf),
    	PROC(STATFS,		enc_statfs,		dec_statfs),
    	PROC(READLINK,		enc_readlink,		dec_readlink),
    	PROC(READDIR,		enc_readdir,		dec_readdir),
    	PROC(SERVER_CAPS,	enc_server_caps,	dec_server_caps),
    	PROC(DELEGRETURN,	enc_delegreturn,	dec_delegreturn),
    	PROC(GETACL,		enc_getacl,		dec_getacl),
    	PROC(SETACL,		enc_setacl,		dec_setacl),
    	PROC(FS_LOCATIONS,	enc_fs_locations,	dec_fs_locations),
    	PROC(RELEASE_LOCKOWNER,	enc_release_lockowner,	dec_release_lockowner),
    
    	PROC(SECINFO,		enc_secinfo,		dec_secinfo),
    
    #if defined(CONFIG_NFS_V4_1)
    
    	PROC(EXCHANGE_ID,	enc_exchange_id,	dec_exchange_id),
    	PROC(CREATE_SESSION,	enc_create_session,	dec_create_session),
    	PROC(DESTROY_SESSION,	enc_destroy_session,	dec_destroy_session),
    	PROC(SEQUENCE,		enc_sequence,		dec_sequence),
    	PROC(GET_LEASE_TIME,	enc_get_lease_time,	dec_get_lease_time),
    	PROC(RECLAIM_COMPLETE,	enc_reclaim_complete,	dec_reclaim_complete),
    	PROC(GETDEVICEINFO,	enc_getdeviceinfo,	dec_getdeviceinfo),
    	PROC(LAYOUTGET,		enc_layoutget,		dec_layoutget),
    
    Andy Adamson's avatar
    Andy Adamson committed
    	PROC(LAYOUTCOMMIT,	enc_layoutcommit,	dec_layoutcommit),
    
    Benny Halevy's avatar
    Benny Halevy committed
    	PROC(LAYOUTRETURN,	enc_layoutreturn,	dec_layoutreturn),
    
    	PROC(SECINFO_NO_NAME,	enc_secinfo_no_name,	dec_secinfo_no_name),
    
    	PROC(TEST_STATEID,	enc_test_stateid,	dec_test_stateid),
    
    	PROC(FREE_STATEID,	enc_free_stateid,	dec_free_stateid),
    
    Andy Adamson's avatar
    Andy Adamson committed
    	PROC(GETDEVICELIST,	enc_getdevicelist,	dec_getdevicelist),
    
    	PROC(BIND_CONN_TO_SESSION,
    			enc_bind_conn_to_session, dec_bind_conn_to_session),
    
    	PROC(DESTROY_CLIENTID,	enc_destroy_clientid,	dec_destroy_clientid),
    
    #endif /* CONFIG_NFS_V4_1 */
    
    const struct rpc_version nfs_version4 = {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	.number			= 4,
    
    	.nrprocs		= ARRAY_SIZE(nfs4_procedures),
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	.procs			= nfs4_procedures
    };
    
    /*
     * Local variables:
     *  c-basic-offset: 8
     * End:
     */