12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039 |
- /*
- * linux/fs/nfs/nfs3xdr.c
- *
- * XDR functions to encode/decode NFSv3 RPC arguments and results.
- *
- * Copyright (C) 1996, 1997 Olaf Kirch
- */
- #include <linux/param.h>
- #include <linux/time.h>
- #include <linux/mm.h>
- #include <linux/errno.h>
- #include <linux/string.h>
- #include <linux/in.h>
- #include <linux/pagemap.h>
- #include <linux/proc_fs.h>
- #include <linux/kdev_t.h>
- #include <linux/sunrpc/clnt.h>
- #include <linux/nfs.h>
- #include <linux/nfs3.h>
- #include <linux/nfs_fs.h>
- #include <linux/nfsacl.h>
- #include "internal.h"
- #define NFSDBG_FACILITY NFSDBG_XDR
- /* Mapping from NFS error code to "errno" error code. */
- #define errno_NFSERR_IO EIO
- /*
- * Declare the space requirements for NFS arguments and replies as
- * number of 32bit-words
- */
- #define NFS3_fhandle_sz (1+16)
- #define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */
- #define NFS3_sattr_sz (15)
- #define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2))
- #define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2))
- #define NFS3_fattr_sz (21)
- #define NFS3_cookieverf_sz (NFS3_COOKIEVERFSIZE>>2)
- #define NFS3_wcc_attr_sz (6)
- #define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
- #define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
- #define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
- #define NFS3_fsstat_sz
- #define NFS3_fsinfo_sz
- #define NFS3_pathconf_sz
- #define NFS3_entry_sz (NFS3_filename_sz+3)
- #define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
- #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
- #define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
- #define NFS3_accessargs_sz (NFS3_fh_sz+1)
- #define NFS3_readlinkargs_sz (NFS3_fh_sz)
- #define NFS3_readargs_sz (NFS3_fh_sz+3)
- #define NFS3_writeargs_sz (NFS3_fh_sz+5)
- #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
- #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
- #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
- #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
- #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
- #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
- #define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3)
- #define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4)
- #define NFS3_commitargs_sz (NFS3_fh_sz+3)
- #define NFS3_attrstat_sz (1+NFS3_fattr_sz)
- #define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
- #define NFS3_removeres_sz (NFS3_wccstat_sz)
- #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
- #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
- #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
- #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3)
- #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
- #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
- #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
- #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
- #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2)
- #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
- #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
- #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
- #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
- #define ACL3_getaclargs_sz (NFS3_fh_sz+1)
- #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
- XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
- #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
- XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
- #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
- /*
- * Map file type to S_IFMT bits
- */
- static const umode_t nfs_type2fmt[] = {
- [NF3BAD] = 0,
- [NF3REG] = S_IFREG,
- [NF3DIR] = S_IFDIR,
- [NF3BLK] = S_IFBLK,
- [NF3CHR] = S_IFCHR,
- [NF3LNK] = S_IFLNK,
- [NF3SOCK] = S_IFSOCK,
- [NF3FIFO] = S_IFIFO,
- };
- static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
- {
- dprintk("nfs: %s: prematurely hit end of receive buffer. "
- "Remaining buffer length is %tu words.\n",
- func, xdr->end - xdr->p);
- }
- /*
- * While encoding arguments, set up the reply buffer in advance to
- * receive reply data directly into the page cache.
- */
- static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
- unsigned int base, unsigned int len,
- unsigned int bufsize)
- {
- struct rpc_auth *auth = req->rq_cred->cr_auth;
- unsigned int replen;
- replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
- xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
- }
- /*
- * Common NFS XDR functions as inlines
- */
- static inline __be32 *
- xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
- {
- return xdr_encode_array(p, fh->data, fh->size);
- }
- static inline __be32 *
- xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
- {
- if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
- memcpy(fh->data, p, fh->size);
- return p + XDR_QUADLEN(fh->size);
- }
- return NULL;
- }
- static inline __be32 *
- xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
- {
- __be32 *p;
- p = xdr_inline_decode(xdr, 4);
- if (unlikely(!p))
- goto out_overflow;
- fh->size = ntohl(*p++);
- if (fh->size <= NFS3_FHSIZE) {
- p = xdr_inline_decode(xdr, fh->size);
- if (unlikely(!p))
- goto out_overflow;
- memcpy(fh->data, p, fh->size);
- return p + XDR_QUADLEN(fh->size);
- }
- return NULL;
- out_overflow:
- print_overflow_msg(__func__, xdr);
- return ERR_PTR(-EIO);
- }
- /*
- * Encode/decode time.
- */
- static inline __be32 *
- xdr_encode_time3(__be32 *p, const struct timespec *timep)
- {
- *p++ = htonl(timep->tv_sec);
- *p++ = htonl(timep->tv_nsec);
- return p;
- }
- static inline __be32 *
- xdr_decode_time3(__be32 *p, struct timespec *timep)
- {
- timep->tv_sec = ntohl(*p++);
- timep->tv_nsec = ntohl(*p++);
- return p;
- }
- static __be32 *
- xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
- {
- unsigned int type, major, minor;
- umode_t fmode;
- type = ntohl(*p++);
- if (type > NF3FIFO)
- type = NF3NON;
- fmode = nfs_type2fmt[type];
- fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
- fattr->nlink = ntohl(*p++);
- fattr->uid = ntohl(*p++);
- fattr->gid = ntohl(*p++);
- p = xdr_decode_hyper(p, &fattr->size);
- p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
- /* Turn remote device info into Linux-specific dev_t */
- major = ntohl(*p++);
- minor = ntohl(*p++);
- fattr->rdev = MKDEV(major, minor);
- if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
- fattr->rdev = 0;
- p = xdr_decode_hyper(p, &fattr->fsid.major);
- fattr->fsid.minor = 0;
- p = xdr_decode_hyper(p, &fattr->fileid);
- p = xdr_decode_time3(p, &fattr->atime);
- p = xdr_decode_time3(p, &fattr->mtime);
- p = xdr_decode_time3(p, &fattr->ctime);
- /* Update the mode bits */
- fattr->valid |= NFS_ATTR_FATTR_V3;
- return p;
- }
- static inline __be32 *
- xdr_encode_sattr(__be32 *p, const struct iattr *attr)
- {
- if (attr->ia_valid & ATTR_MODE) {
- *p++ = xdr_one;
- *p++ = htonl(attr->ia_mode & S_IALLUGO);
- } else {
- *p++ = xdr_zero;
- }
- if (attr->ia_valid & ATTR_UID) {
- *p++ = xdr_one;
- *p++ = htonl(attr->ia_uid);
- } else {
- *p++ = xdr_zero;
- }
- if (attr->ia_valid & ATTR_GID) {
- *p++ = xdr_one;
- *p++ = htonl(attr->ia_gid);
- } else {
- *p++ = xdr_zero;
- }
- if (attr->ia_valid & ATTR_SIZE) {
- *p++ = xdr_one;
- p = xdr_encode_hyper(p, (__u64) attr->ia_size);
- } else {
- *p++ = xdr_zero;
- }
- if (attr->ia_valid & ATTR_ATIME_SET) {
- *p++ = xdr_two;
- p = xdr_encode_time3(p, &attr->ia_atime);
- } else if (attr->ia_valid & ATTR_ATIME) {
- *p++ = xdr_one;
- } else {
- *p++ = xdr_zero;
- }
- if (attr->ia_valid & ATTR_MTIME_SET) {
- *p++ = xdr_two;
- p = xdr_encode_time3(p, &attr->ia_mtime);
- } else if (attr->ia_valid & ATTR_MTIME) {
- *p++ = xdr_one;
- } else {
- *p++ = xdr_zero;
- }
- return p;
- }
- static inline __be32 *
- xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
- {
- p = xdr_decode_hyper(p, &fattr->pre_size);
- p = xdr_decode_time3(p, &fattr->pre_mtime);
- p = xdr_decode_time3(p, &fattr->pre_ctime);
- fattr->valid |= NFS_ATTR_FATTR_PRESIZE
- | NFS_ATTR_FATTR_PREMTIME
- | NFS_ATTR_FATTR_PRECTIME;
- return p;
- }
- static inline __be32 *
- xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
- {
- if (*p++)
- p = xdr_decode_fattr(p, fattr);
- return p;
- }
- static inline __be32 *
- xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
- {
- __be32 *p;
- p = xdr_inline_decode(xdr, 4);
- if (unlikely(!p))
- goto out_overflow;
- if (ntohl(*p++)) {
- p = xdr_inline_decode(xdr, 84);
- if (unlikely(!p))
- goto out_overflow;
- p = xdr_decode_fattr(p, fattr);
- }
- return p;
- out_overflow:
- print_overflow_msg(__func__, xdr);
- return ERR_PTR(-EIO);
- }
- static inline __be32 *
- xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
- {
- if (*p++)
- return xdr_decode_wcc_attr(p, fattr);
- return p;
- }
- static inline __be32 *
- xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
- {
- p = xdr_decode_pre_op_attr(p, fattr);
- return xdr_decode_post_op_attr(p, fattr);
- }
- /*
- * Encode/decode NFSv3 basic data types
- *
- * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
- * "NFS Version 3 Protocol Specification".
- *
- * Not all basic data types have their own encoding and decoding
- * functions. For run-time efficiency, some data types are encoded
- * or decoded inline.
- */
- static void encode_uint32(struct xdr_stream *xdr, u32 value)
- {
- __be32 *p = xdr_reserve_space(xdr, 4);
- *p = cpu_to_be32(value);
- }
- /*
- * filename3
- *
- * typedef string filename3<>;
- */
- static void encode_filename3(struct xdr_stream *xdr,
- const char *name, u32 length)
- {
- __be32 *p;
- BUG_ON(length > NFS3_MAXNAMLEN);
- p = xdr_reserve_space(xdr, 4 + length);
- xdr_encode_opaque(p, name, length);
- }
- /*
- * nfspath3
- *
- * typedef string nfspath3<>;
- */
- static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
- const u32 length)
- {
- BUG_ON(length > NFS3_MAXPATHLEN);
- encode_uint32(xdr, length);
- xdr_write_pages(xdr, pages, 0, length);
- }
- /*
- * cookie3
- *
- * typedef uint64 cookie3
- */
- static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
- {
- return xdr_encode_hyper(p, cookie);
- }
- /*
- * cookieverf3
- *
- * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
- */
- static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
- {
- memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
- return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
- }
- /*
- * createverf3
- *
- * typedef opaque createverf3[NFS3_CREATEVERFSIZE];
- */
- static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
- {
- __be32 *p;
- p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
- memcpy(p, verifier, NFS3_CREATEVERFSIZE);
- }
- /*
- * ftype3
- *
- * enum ftype3 {
- * NF3REG = 1,
- * NF3DIR = 2,
- * NF3BLK = 3,
- * NF3CHR = 4,
- * NF3LNK = 5,
- * NF3SOCK = 6,
- * NF3FIFO = 7
- * };
- */
- static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
- {
- BUG_ON(type > NF3FIFO);
- encode_uint32(xdr, type);
- }
- /*
- * specdata3
- *
- * struct specdata3 {
- * uint32 specdata1;
- * uint32 specdata2;
- * };
- */
- static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
- {
- __be32 *p;
- p = xdr_reserve_space(xdr, 8);
- *p++ = cpu_to_be32(MAJOR(rdev));
- *p = cpu_to_be32(MINOR(rdev));
- }
- /*
- * nfs_fh3
- *
- * struct nfs_fh3 {
- * opaque data<NFS3_FHSIZE>;
- * };
- */
- static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
- {
- __be32 *p;
- BUG_ON(fh->size > NFS3_FHSIZE);
- p = xdr_reserve_space(xdr, 4 + fh->size);
- xdr_encode_opaque(p, fh->data, fh->size);
- }
- /*
- * sattr3
- *
- * enum time_how {
- * DONT_CHANGE = 0,
- * SET_TO_SERVER_TIME = 1,
- * SET_TO_CLIENT_TIME = 2
- * };
- *
- * union set_mode3 switch (bool set_it) {
- * case TRUE:
- * mode3 mode;
- * default:
- * void;
- * };
- *
- * union set_uid3 switch (bool set_it) {
- * case TRUE:
- * uid3 uid;
- * default:
- * void;
- * };
- *
- * union set_gid3 switch (bool set_it) {
- * case TRUE:
- * gid3 gid;
- * default:
- * void;
- * };
- *
- * union set_size3 switch (bool set_it) {
- * case TRUE:
- * size3 size;
- * default:
- * void;
- * };
- *
- * union set_atime switch (time_how set_it) {
- * case SET_TO_CLIENT_TIME:
- * nfstime3 atime;
- * default:
- * void;
- * };
- *
- * union set_mtime switch (time_how set_it) {
- * case SET_TO_CLIENT_TIME:
- * nfstime3 mtime;
- * default:
- * void;
- * };
- *
- * struct sattr3 {
- * set_mode3 mode;
- * set_uid3 uid;
- * set_gid3 gid;
- * set_size3 size;
- * set_atime atime;
- * set_mtime mtime;
- * };
- */
- static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
- {
- u32 nbytes;
- __be32 *p;
- /*
- * In order to make only a single xdr_reserve_space() call,
- * pre-compute the total number of bytes to be reserved.
- * Six boolean values, one for each set_foo field, are always
- * present in the encoded result, so start there.
- */
- nbytes = 6 * 4;
- if (attr->ia_valid & ATTR_MODE)
- nbytes += 4;
- if (attr->ia_valid & ATTR_UID)
- nbytes += 4;
- if (attr->ia_valid & ATTR_GID)
- nbytes += 4;
- if (attr->ia_valid & ATTR_SIZE)
- nbytes += 8;
- if (attr->ia_valid & ATTR_ATIME_SET)
- nbytes += 8;
- if (attr->ia_valid & ATTR_MTIME_SET)
- nbytes += 8;
- p = xdr_reserve_space(xdr, nbytes);
- xdr_encode_sattr(p, attr);
- }
- /*
- * diropargs3
- *
- * struct diropargs3 {
- * nfs_fh3 dir;
- * filename3 name;
- * };
- */
- static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
- const char *name, u32 length)
- {
- encode_nfs_fh3(xdr, fh);
- encode_filename3(xdr, name, length);
- }
- /*
- * NFS encode functions
- */
- /*
- * Encode file handle argument
- */
- static int
- nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
- {
- p = xdr_encode_fhandle(p, fh);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * 3.3.1 GETATTR3args
- *
- * struct GETATTR3args {
- * nfs_fh3 object;
- * };
- */
- static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs_fh *fh)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_nfs_fh3(&xdr, fh);
- return 0;
- }
- /*
- * Encode SETATTR arguments
- */
- static int
- nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_sattr(p, args->sattr);
- *p++ = htonl(args->guard);
- if (args->guard)
- p = xdr_encode_time3(p, &args->guardtime);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * 3.3.2 SETATTR3args
- *
- * union sattrguard3 switch (bool check) {
- * case TRUE:
- * nfstime3 obj_ctime;
- * case FALSE:
- * void;
- * };
- *
- * struct SETATTR3args {
- * nfs_fh3 object;
- * sattr3 new_attributes;
- * sattrguard3 guard;
- * };
- */
- static void encode_sattrguard3(struct xdr_stream *xdr,
- const struct nfs3_sattrargs *args)
- {
- __be32 *p;
- if (args->guard) {
- p = xdr_reserve_space(xdr, 4 + 8);
- *p++ = xdr_one;
- xdr_encode_time3(p, &args->guardtime);
- } else {
- p = xdr_reserve_space(xdr, 4);
- *p = xdr_zero;
- }
- }
- static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_sattrargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_nfs_fh3(&xdr, args->fh);
- encode_sattr3(&xdr, args->sattr);
- encode_sattrguard3(&xdr, args);
- return 0;
- }
- /*
- * Encode directory ops argument
- */
- static int
- nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_array(p, args->name, args->len);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * 3.3.3 LOOKUP3args
- *
- * struct LOOKUP3args {
- * diropargs3 what;
- * };
- */
- static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_diropargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_diropargs3(&xdr, args->fh, args->name, args->len);
- return 0;
- }
- /*
- * Encode REMOVE argument
- */
- static int
- nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_array(p, args->name.name, args->name.len);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * Encode access() argument
- */
- static int
- nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- *p++ = htonl(args->access);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * 3.3.4 ACCESS3args
- *
- * struct ACCESS3args {
- * nfs_fh3 object;
- * uint32 access;
- * };
- */
- static void encode_access3args(struct xdr_stream *xdr,
- const struct nfs3_accessargs *args)
- {
- encode_nfs_fh3(xdr, args->fh);
- encode_uint32(xdr, args->access);
- }
- static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_accessargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_access3args(&xdr, args);
- return 0;
- }
- /*
- * 3.3.5 READLINK3args
- *
- * struct READLINK3args {
- * nfs_fh3 symlink;
- * };
- */
- static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_readlinkargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_nfs_fh3(&xdr, args->fh);
- prepare_reply_buffer(req, args->pages, args->pgbase,
- args->pglen, NFS3_readlinkres_sz);
- return 0;
- }
- /*
- * Arguments to a READ call. Since we read data directly into the page
- * cache, we also set up the reply iovec here so that iov[1] points
- * exactly to the page we want to fetch.
- */
- static int
- nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
- {
- struct rpc_auth *auth = req->rq_cred->cr_auth;
- unsigned int replen;
- u32 count = args->count;
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_hyper(p, args->offset);
- *p++ = htonl(count);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- /* Inline the page array */
- replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
- xdr_inline_pages(&req->rq_rcv_buf, replen,
- args->pages, args->pgbase, count);
- req->rq_rcv_buf.flags |= XDRBUF_READ;
- return 0;
- }
- /*
- * 3.3.6 READ3args
- *
- * struct READ3args {
- * nfs_fh3 file;
- * offset3 offset;
- * count3 count;
- * };
- */
- static void encode_read3args(struct xdr_stream *xdr,
- const struct nfs_readargs *args)
- {
- __be32 *p;
- encode_nfs_fh3(xdr, args->fh);
- p = xdr_reserve_space(xdr, 8 + 4);
- p = xdr_encode_hyper(p, args->offset);
- *p = cpu_to_be32(args->count);
- }
- static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs_readargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_read3args(&xdr, args);
- prepare_reply_buffer(req, args->pages, args->pgbase,
- args->count, NFS3_readres_sz);
- req->rq_rcv_buf.flags |= XDRBUF_READ;
- return 0;
- }
- /*
- * Write arguments. Splice the buffer to be written into the iovec.
- */
- static int
- nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
- {
- struct xdr_buf *sndbuf = &req->rq_snd_buf;
- u32 count = args->count;
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_hyper(p, args->offset);
- *p++ = htonl(count);
- *p++ = htonl(args->stable);
- *p++ = htonl(count);
- sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
- /* Copy the page array */
- xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
- sndbuf->flags |= XDRBUF_WRITE;
- return 0;
- }
- /*
- * 3.3.7 WRITE3args
- *
- * enum stable_how {
- * UNSTABLE = 0,
- * DATA_SYNC = 1,
- * FILE_SYNC = 2
- * };
- *
- * struct WRITE3args {
- * nfs_fh3 file;
- * offset3 offset;
- * count3 count;
- * stable_how stable;
- * opaque data<>;
- * };
- */
- static void encode_write3args(struct xdr_stream *xdr,
- const struct nfs_writeargs *args)
- {
- __be32 *p;
- encode_nfs_fh3(xdr, args->fh);
- p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
- p = xdr_encode_hyper(p, args->offset);
- *p++ = cpu_to_be32(args->count);
- BUG_ON(args->stable > NFS_FILE_SYNC);
- *p++ = cpu_to_be32(args->stable);
- *p = cpu_to_be32(args->count);
- xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
- }
- static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs_writeargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_write3args(&xdr, args);
- xdr.buf->flags |= XDRBUF_WRITE;
- return 0;
- }
- /*
- * Encode CREATE arguments
- */
- static int
- nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_array(p, args->name, args->len);
- *p++ = htonl(args->createmode);
- if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
- *p++ = args->verifier[0];
- *p++ = args->verifier[1];
- } else
- p = xdr_encode_sattr(p, args->sattr);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * 3.3.8 CREATE3args
- *
- * enum createmode3 {
- * UNCHECKED = 0,
- * GUARDED = 1,
- * EXCLUSIVE = 2
- * };
- *
- * union createhow3 switch (createmode3 mode) {
- * case UNCHECKED:
- * case GUARDED:
- * sattr3 obj_attributes;
- * case EXCLUSIVE:
- * createverf3 verf;
- * };
- *
- * struct CREATE3args {
- * diropargs3 where;
- * createhow3 how;
- * };
- */
- static void encode_createhow3(struct xdr_stream *xdr,
- const struct nfs3_createargs *args)
- {
- encode_uint32(xdr, args->createmode);
- switch (args->createmode) {
- case NFS3_CREATE_UNCHECKED:
- case NFS3_CREATE_GUARDED:
- encode_sattr3(xdr, args->sattr);
- break;
- case NFS3_CREATE_EXCLUSIVE:
- encode_createverf3(xdr, args->verifier);
- break;
- default:
- BUG();
- }
- }
- static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_createargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_diropargs3(&xdr, args->fh, args->name, args->len);
- encode_createhow3(&xdr, args);
- return 0;
- }
- /*
- * Encode MKDIR arguments
- */
- static int
- nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_array(p, args->name, args->len);
- p = xdr_encode_sattr(p, args->sattr);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * 3.3.9 MKDIR3args
- *
- * struct MKDIR3args {
- * diropargs3 where;
- * sattr3 attributes;
- * };
- */
- static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_mkdirargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_diropargs3(&xdr, args->fh, args->name, args->len);
- encode_sattr3(&xdr, args->sattr);
- return 0;
- }
- /*
- * Encode SYMLINK arguments
- */
- static int
- nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
- {
- p = xdr_encode_fhandle(p, args->fromfh);
- p = xdr_encode_array(p, args->fromname, args->fromlen);
- p = xdr_encode_sattr(p, args->sattr);
- *p++ = htonl(args->pathlen);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- /* Copy the page */
- xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
- return 0;
- }
- /*
- * 3.3.10 SYMLINK3args
- *
- * struct symlinkdata3 {
- * sattr3 symlink_attributes;
- * nfspath3 symlink_data;
- * };
- *
- * struct SYMLINK3args {
- * diropargs3 where;
- * symlinkdata3 symlink;
- * };
- */
- static void encode_symlinkdata3(struct xdr_stream *xdr,
- const struct nfs3_symlinkargs *args)
- {
- encode_sattr3(xdr, args->sattr);
- encode_nfspath3(xdr, args->pages, args->pathlen);
- }
- static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_symlinkargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen);
- encode_symlinkdata3(&xdr, args);
- return 0;
- }
- /*
- * Encode MKNOD arguments
- */
- static int
- nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_array(p, args->name, args->len);
- *p++ = htonl(args->type);
- p = xdr_encode_sattr(p, args->sattr);
- if (args->type == NF3CHR || args->type == NF3BLK) {
- *p++ = htonl(MAJOR(args->rdev));
- *p++ = htonl(MINOR(args->rdev));
- }
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * 3.3.11 MKNOD3args
- *
- * struct devicedata3 {
- * sattr3 dev_attributes;
- * specdata3 spec;
- * };
- *
- * union mknoddata3 switch (ftype3 type) {
- * case NF3CHR:
- * case NF3BLK:
- * devicedata3 device;
- * case NF3SOCK:
- * case NF3FIFO:
- * sattr3 pipe_attributes;
- * default:
- * void;
- * };
- *
- * struct MKNOD3args {
- * diropargs3 where;
- * mknoddata3 what;
- * };
- */
- static void encode_devicedata3(struct xdr_stream *xdr,
- const struct nfs3_mknodargs *args)
- {
- encode_sattr3(xdr, args->sattr);
- encode_specdata3(xdr, args->rdev);
- }
- static void encode_mknoddata3(struct xdr_stream *xdr,
- const struct nfs3_mknodargs *args)
- {
- encode_ftype3(xdr, args->type);
- switch (args->type) {
- case NF3CHR:
- case NF3BLK:
- encode_devicedata3(xdr, args);
- break;
- case NF3SOCK:
- case NF3FIFO:
- encode_sattr3(xdr, args->sattr);
- break;
- case NF3REG:
- case NF3DIR:
- break;
- default:
- BUG();
- }
- }
- static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_mknodargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_diropargs3(&xdr, args->fh, args->name, args->len);
- encode_mknoddata3(&xdr, args);
- return 0;
- }
- /*
- * 3.3.12 REMOVE3args
- *
- * struct REMOVE3args {
- * diropargs3 object;
- * };
- */
- static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs_removeargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len);
- return 0;
- }
- /*
- * Encode RENAME arguments
- */
- static int
- nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
- {
- p = xdr_encode_fhandle(p, args->old_dir);
- p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
- p = xdr_encode_fhandle(p, args->new_dir);
- p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * 3.3.14 RENAME3args
- *
- * struct RENAME3args {
- * diropargs3 from;
- * diropargs3 to;
- * };
- */
- static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs_renameargs *args)
- {
- const struct qstr *old = args->old_name;
- const struct qstr *new = args->new_name;
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_diropargs3(&xdr, args->old_dir, old->name, old->len);
- encode_diropargs3(&xdr, args->new_dir, new->name, new->len);
- return 0;
- }
- /*
- * Encode LINK arguments
- */
- static int
- nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
- {
- p = xdr_encode_fhandle(p, args->fromfh);
- p = xdr_encode_fhandle(p, args->tofh);
- p = xdr_encode_array(p, args->toname, args->tolen);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * 3.3.15 LINK3args
- *
- * struct LINK3args {
- * nfs_fh3 file;
- * diropargs3 link;
- * };
- */
- static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_linkargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_nfs_fh3(&xdr, args->fromfh);
- encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen);
- return 0;
- }
- /*
- * Encode arguments to readdir call
- */
- static int
- nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
- {
- struct rpc_auth *auth = req->rq_cred->cr_auth;
- unsigned int replen;
- u32 count = args->count;
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_hyper(p, args->cookie);
- *p++ = args->verf[0];
- *p++ = args->verf[1];
- if (args->plus) {
- /* readdirplus: need dircount + buffer size.
- * We just make sure we make dircount big enough */
- *p++ = htonl(count >> 3);
- }
- *p++ = htonl(count);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- /* Inline the page array */
- replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
- xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
- return 0;
- }
- /*
- * 3.3.16 READDIR3args
- *
- * struct READDIR3args {
- * nfs_fh3 dir;
- * cookie3 cookie;
- * cookieverf3 cookieverf;
- * count3 count;
- * };
- */
- static void encode_readdir3args(struct xdr_stream *xdr,
- const struct nfs3_readdirargs *args)
- {
- __be32 *p;
- encode_nfs_fh3(xdr, args->fh);
- p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
- p = xdr_encode_cookie3(p, args->cookie);
- p = xdr_encode_cookieverf3(p, args->verf);
- *p = cpu_to_be32(args->count);
- }
- static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_readdirargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_readdir3args(&xdr, args);
- prepare_reply_buffer(req, args->pages, 0,
- args->count, NFS3_readdirres_sz);
- return 0;
- }
- /*
- * 3.3.17 READDIRPLUS3args
- *
- * struct READDIRPLUS3args {
- * nfs_fh3 dir;
- * cookie3 cookie;
- * cookieverf3 cookieverf;
- * count3 dircount;
- * count3 maxcount;
- * };
- */
- static void encode_readdirplus3args(struct xdr_stream *xdr,
- const struct nfs3_readdirargs *args)
- {
- __be32 *p;
- encode_nfs_fh3(xdr, args->fh);
- p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
- p = xdr_encode_cookie3(p, args->cookie);
- p = xdr_encode_cookieverf3(p, args->verf);
- /*
- * readdirplus: need dircount + buffer size.
- * We just make sure we make dircount big enough
- */
- *p++ = cpu_to_be32(args->count >> 3);
- *p = cpu_to_be32(args->count);
- }
- static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_readdirargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_readdirplus3args(&xdr, args);
- prepare_reply_buffer(req, args->pages, 0,
- args->count, NFS3_readdirres_sz);
- return 0;
- }
- /*
- * Decode the result of a readdir call.
- * We just check for syntactical correctness.
- */
- static int
- nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
- {
- struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
- struct kvec *iov = rcvbuf->head;
- struct page **page;
- size_t hdrlen;
- u32 recvd, pglen;
- int status;
- status = ntohl(*p++);
- /* Decode post_op_attrs */
- p = xdr_decode_post_op_attr(p, res->dir_attr);
- if (status)
- return nfs_stat_to_errno(status);
- /* Decode verifier cookie */
- if (res->verf) {
- res->verf[0] = *p++;
- res->verf[1] = *p++;
- } else {
- p += 2;
- }
- hdrlen = (u8 *) p - (u8 *) iov->iov_base;
- if (iov->iov_len < hdrlen) {
- dprintk("NFS: READDIR reply header overflowed:"
- "length %Zu > %Zu\n", hdrlen, iov->iov_len);
- return -errno_NFSERR_IO;
- } else if (iov->iov_len != hdrlen) {
- dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
- xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
- }
- pglen = rcvbuf->page_len;
- recvd = rcvbuf->len - hdrlen;
- if (pglen > recvd)
- pglen = recvd;
- page = rcvbuf->pages;
- return pglen;
- }
- __be32 *
- nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
- {
- __be32 *p;
- struct nfs_entry old = *entry;
- p = xdr_inline_decode(xdr, 4);
- if (unlikely(!p))
- goto out_overflow;
- if (!ntohl(*p++)) {
- p = xdr_inline_decode(xdr, 4);
- if (unlikely(!p))
- goto out_overflow;
- if (!ntohl(*p++))
- return ERR_PTR(-EAGAIN);
- entry->eof = 1;
- return ERR_PTR(-EBADCOOKIE);
- }
- p = xdr_inline_decode(xdr, 12);
- if (unlikely(!p))
- goto out_overflow;
- p = xdr_decode_hyper(p, &entry->ino);
- entry->len = ntohl(*p++);
- p = xdr_inline_decode(xdr, entry->len + 8);
- if (unlikely(!p))
- goto out_overflow;
- entry->name = (const char *) p;
- p += XDR_QUADLEN(entry->len);
- entry->prev_cookie = entry->cookie;
- p = xdr_decode_hyper(p, &entry->cookie);
- entry->d_type = DT_UNKNOWN;
- if (plus) {
- entry->fattr->valid = 0;
- p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
- if (IS_ERR(p))
- goto out_overflow_exit;
- entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
- /* In fact, a post_op_fh3: */
- p = xdr_inline_decode(xdr, 4);
- if (unlikely(!p))
- goto out_overflow;
- if (*p++) {
- p = xdr_decode_fhandle_stream(xdr, entry->fh);
- if (IS_ERR(p))
- goto out_overflow_exit;
- /* Ugh -- server reply was truncated */
- if (p == NULL) {
- dprintk("NFS: FH truncated\n");
- *entry = old;
- return ERR_PTR(-EAGAIN);
- }
- } else
- memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
- }
- p = xdr_inline_peek(xdr, 8);
- if (p != NULL)
- entry->eof = !p[0] && p[1];
- else
- entry->eof = 0;
- return p;
- out_overflow:
- print_overflow_msg(__func__, xdr);
- out_overflow_exit:
- return ERR_PTR(-EAGAIN);
- }
- /*
- * Encode COMMIT arguments
- */
- static int
- nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_hyper(p, args->offset);
- *p++ = htonl(args->count);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * 3.3.21 COMMIT3args
- *
- * struct COMMIT3args {
- * nfs_fh3 file;
- * offset3 offset;
- * count3 count;
- * };
- */
- static void encode_commit3args(struct xdr_stream *xdr,
- const struct nfs_writeargs *args)
- {
- __be32 *p;
- encode_nfs_fh3(xdr, args->fh);
- p = xdr_reserve_space(xdr, 8 + 4);
- p = xdr_encode_hyper(p, args->offset);
- *p = cpu_to_be32(args->count);
- }
- static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs_writeargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_commit3args(&xdr, args);
- return 0;
- }
- #ifdef CONFIG_NFS_V3_ACL
- /*
- * Encode GETACL arguments
- */
- static int
- nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
- struct nfs3_getaclargs *args)
- {
- struct rpc_auth *auth = req->rq_cred->cr_auth;
- unsigned int replen;
- p = xdr_encode_fhandle(p, args->fh);
- *p++ = htonl(args->mask);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- if (args->mask & (NFS_ACL | NFS_DFACL)) {
- /* Inline the page array */
- replen = (RPC_REPHDRSIZE + auth->au_rslack +
- ACL3_getaclres_sz) << 2;
- xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
- NFSACL_MAXPAGES << PAGE_SHIFT);
- }
- return 0;
- }
- static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_getaclargs *args)
- {
- struct xdr_stream xdr;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_nfs_fh3(&xdr, args->fh);
- encode_uint32(&xdr, args->mask);
- if (args->mask & (NFS_ACL | NFS_DFACL))
- prepare_reply_buffer(req, args->pages, 0,
- NFSACL_MAXPAGES << PAGE_SHIFT,
- ACL3_getaclres_sz);
- return 0;
- }
- /*
- * Encode SETACL arguments
- */
- static int
- nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
- struct nfs3_setaclargs *args)
- {
- struct xdr_buf *buf = &req->rq_snd_buf;
- unsigned int base;
- int err;
- p = xdr_encode_fhandle(p, NFS_FH(args->inode));
- *p++ = htonl(args->mask);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- base = req->rq_slen;
- if (args->npages != 0)
- xdr_encode_pages(buf, args->pages, 0, args->len);
- else
- req->rq_slen = xdr_adjust_iovec(req->rq_svec,
- p + XDR_QUADLEN(args->len));
- err = nfsacl_encode(buf, base, args->inode,
- (args->mask & NFS_ACL) ?
- args->acl_access : NULL, 1, 0);
- if (err > 0)
- err = nfsacl_encode(buf, base + err, args->inode,
- (args->mask & NFS_DFACL) ?
- args->acl_default : NULL, 1,
- NFS_ACL_DEFAULT);
- return (err > 0) ? 0 : err;
- }
- static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p,
- const struct nfs3_setaclargs *args)
- {
- struct xdr_stream xdr;
- unsigned int base;
- int error;
- xdr_init_encode(&xdr, &req->rq_snd_buf, p);
- encode_nfs_fh3(&xdr, NFS_FH(args->inode));
- encode_uint32(&xdr, args->mask);
- if (args->npages != 0)
- xdr_write_pages(&xdr, args->pages, 0, args->len);
- base = req->rq_slen;
- error = nfsacl_encode(xdr.buf, base, args->inode,
- (args->mask & NFS_ACL) ?
- args->acl_access : NULL, 1, 0);
- BUG_ON(error < 0);
- error = nfsacl_encode(xdr.buf, base + error, args->inode,
- (args->mask & NFS_DFACL) ?
- args->acl_default : NULL, 1,
- NFS_ACL_DEFAULT);
- BUG_ON(error < 0);
- return 0;
- }
- #endif /* CONFIG_NFS_V3_ACL */
- /*
- * NFS XDR decode functions
- */
- /*
- * Decode attrstat reply.
- */
- static int
- nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
- {
- int status;
- if ((status = ntohl(*p++)))
- return nfs_stat_to_errno(status);
- xdr_decode_fattr(p, fattr);
- return 0;
- }
- /*
- * Decode status+wcc_data reply
- * SATTR, REMOVE, RMDIR
- */
- static int
- nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
- {
- int status;
- if ((status = ntohl(*p++)))
- status = nfs_stat_to_errno(status);
- xdr_decode_wcc_data(p, fattr);
- return status;
- }
- static int
- nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
- {
- return nfs3_xdr_wccstat(req, p, res->dir_attr);
- }
- /*
- * Decode LOOKUP reply
- */
- static int
- nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
- {
- int status;
- if ((status = ntohl(*p++))) {
- status = nfs_stat_to_errno(status);
- } else {
- if (!(p = xdr_decode_fhandle(p, res->fh)))
- return -errno_NFSERR_IO;
- p = xdr_decode_post_op_attr(p, res->fattr);
- }
- xdr_decode_post_op_attr(p, res->dir_attr);
- return status;
- }
- /*
- * Decode ACCESS reply
- */
- static int
- nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
- {
- int status = ntohl(*p++);
- p = xdr_decode_post_op_attr(p, res->fattr);
- if (status)
- return nfs_stat_to_errno(status);
- res->access = ntohl(*p++);
- return 0;
- }
- static int
- nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
- {
- struct rpc_auth *auth = req->rq_cred->cr_auth;
- unsigned int replen;
- p = xdr_encode_fhandle(p, args->fh);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- /* Inline the page array */
- replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
- xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
- return 0;
- }
- /*
- * Decode READLINK reply
- */
- static int
- nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
- {
- struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
- struct kvec *iov = rcvbuf->head;
- size_t hdrlen;
- u32 len, recvd;
- int status;
- status = ntohl(*p++);
- p = xdr_decode_post_op_attr(p, fattr);
- if (status != 0)
- return nfs_stat_to_errno(status);
- /* Convert length of symlink */
- len = ntohl(*p++);
- if (len >= rcvbuf->page_len) {
- dprintk("nfs: server returned giant symlink!\n");
- return -ENAMETOOLONG;
- }
- hdrlen = (u8 *) p - (u8 *) iov->iov_base;
- if (iov->iov_len < hdrlen) {
- dprintk("NFS: READLINK reply header overflowed:"
- "length %Zu > %Zu\n", hdrlen, iov->iov_len);
- return -errno_NFSERR_IO;
- } else if (iov->iov_len != hdrlen) {
- dprintk("NFS: READLINK header is short. "
- "iovec will be shifted.\n");
- xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
- }
- recvd = req->rq_rcv_buf.len - hdrlen;
- if (recvd < len) {
- dprintk("NFS: server cheating in readlink reply: "
- "count %u > recvd %u\n", len, recvd);
- return -EIO;
- }
- xdr_terminate_string(rcvbuf, len);
- return 0;
- }
- /*
- * Decode READ reply
- */
- static int
- nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
- {
- struct kvec *iov = req->rq_rcv_buf.head;
- size_t hdrlen;
- u32 count, ocount, recvd;
- int status;
- status = ntohl(*p++);
- p = xdr_decode_post_op_attr(p, res->fattr);
- if (status != 0)
- return nfs_stat_to_errno(status);
- /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
- * in that it puts the count both in the res struct and in the
- * opaque data count. */
- count = ntohl(*p++);
- res->eof = ntohl(*p++);
- ocount = ntohl(*p++);
- if (ocount != count) {
- dprintk("NFS: READ count doesn't match RPC opaque count.\n");
- return -errno_NFSERR_IO;
- }
- hdrlen = (u8 *) p - (u8 *) iov->iov_base;
- if (iov->iov_len < hdrlen) {
- dprintk("NFS: READ reply header overflowed:"
- "length %Zu > %Zu\n", hdrlen, iov->iov_len);
- return -errno_NFSERR_IO;
- } else if (iov->iov_len != hdrlen) {
- dprintk("NFS: READ header is short. iovec will be shifted.\n");
- xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
- }
- recvd = req->rq_rcv_buf.len - hdrlen;
- if (count > recvd) {
- dprintk("NFS: server cheating in read reply: "
- "count %u > recvd %u\n", count, recvd);
- count = recvd;
- res->eof = 0;
- }
- if (count < res->count)
- res->count = count;
- return count;
- }
- /*
- * Decode WRITE response
- */
- static int
- nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
- {
- int status;
- status = ntohl(*p++);
- p = xdr_decode_wcc_data(p, res->fattr);
- if (status != 0)
- return nfs_stat_to_errno(status);
- res->count = ntohl(*p++);
- res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
- res->verf->verifier[0] = *p++;
- res->verf->verifier[1] = *p++;
- return res->count;
- }
- /*
- * Decode a CREATE response
- */
- static int
- nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
- {
- int status;
- status = ntohl(*p++);
- if (status == 0) {
- if (*p++) {
- if (!(p = xdr_decode_fhandle(p, res->fh)))
- return -errno_NFSERR_IO;
- p = xdr_decode_post_op_attr(p, res->fattr);
- } else {
- memset(res->fh, 0, sizeof(*res->fh));
- /* Do decode post_op_attr but set it to NULL */
- p = xdr_decode_post_op_attr(p, res->fattr);
- res->fattr->valid = 0;
- }
- } else {
- status = nfs_stat_to_errno(status);
- }
- p = xdr_decode_wcc_data(p, res->dir_attr);
- return status;
- }
- /*
- * Decode RENAME reply
- */
- static int
- nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
- {
- int status;
- if ((status = ntohl(*p++)) != 0)
- status = nfs_stat_to_errno(status);
- p = xdr_decode_wcc_data(p, res->old_fattr);
- p = xdr_decode_wcc_data(p, res->new_fattr);
- return status;
- }
- /*
- * Decode LINK reply
- */
- static int
- nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
- {
- int status;
- if ((status = ntohl(*p++)) != 0)
- status = nfs_stat_to_errno(status);
- p = xdr_decode_post_op_attr(p, res->fattr);
- p = xdr_decode_wcc_data(p, res->dir_attr);
- return status;
- }
- /*
- * Decode FSSTAT reply
- */
- static int
- nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
- {
- int status;
- status = ntohl(*p++);
- p = xdr_decode_post_op_attr(p, res->fattr);
- if (status != 0)
- return nfs_stat_to_errno(status);
- p = xdr_decode_hyper(p, &res->tbytes);
- p = xdr_decode_hyper(p, &res->fbytes);
- p = xdr_decode_hyper(p, &res->abytes);
- p = xdr_decode_hyper(p, &res->tfiles);
- p = xdr_decode_hyper(p, &res->ffiles);
- p = xdr_decode_hyper(p, &res->afiles);
- /* ignore invarsec */
- return 0;
- }
- /*
- * Decode FSINFO reply
- */
- static int
- nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
- {
- int status;
- status = ntohl(*p++);
- p = xdr_decode_post_op_attr(p, res->fattr);
- if (status != 0)
- return nfs_stat_to_errno(status);
- res->rtmax = ntohl(*p++);
- res->rtpref = ntohl(*p++);
- res->rtmult = ntohl(*p++);
- res->wtmax = ntohl(*p++);
- res->wtpref = ntohl(*p++);
- res->wtmult = ntohl(*p++);
- res->dtpref = ntohl(*p++);
- p = xdr_decode_hyper(p, &res->maxfilesize);
- p = xdr_decode_time3(p, &res->time_delta);
- /* ignore properties */
- res->lease_time = 0;
- return 0;
- }
- /*
- * Decode PATHCONF reply
- */
- static int
- nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
- {
- int status;
- status = ntohl(*p++);
- p = xdr_decode_post_op_attr(p, res->fattr);
- if (status != 0)
- return nfs_stat_to_errno(status);
- res->max_link = ntohl(*p++);
- res->max_namelen = ntohl(*p++);
- /* ignore remaining fields */
- return 0;
- }
- /*
- * Decode COMMIT reply
- */
- static int
- nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
- {
- int status;
- status = ntohl(*p++);
- p = xdr_decode_wcc_data(p, res->fattr);
- if (status != 0)
- return nfs_stat_to_errno(status);
- res->verf->verifier[0] = *p++;
- res->verf->verifier[1] = *p++;
- return 0;
- }
- #ifdef CONFIG_NFS_V3_ACL
- /*
- * Decode GETACL reply
- */
- static int
- nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
- struct nfs3_getaclres *res)
- {
- struct xdr_buf *buf = &req->rq_rcv_buf;
- int status = ntohl(*p++);
- struct posix_acl **acl;
- unsigned int *aclcnt;
- int err, base;
- if (status != 0)
- return nfs_stat_to_errno(status);
- p = xdr_decode_post_op_attr(p, res->fattr);
- res->mask = ntohl(*p++);
- if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
- return -EINVAL;
- base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
- acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
- aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
- err = nfsacl_decode(buf, base, aclcnt, acl);
- acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
- aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
- if (err > 0)
- err = nfsacl_decode(buf, base + err, aclcnt, acl);
- return (err > 0) ? 0 : err;
- }
- /*
- * Decode setacl reply.
- */
- static int
- nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
- {
- int status = ntohl(*p++);
- if (status)
- return nfs_stat_to_errno(status);
- xdr_decode_post_op_attr(p, fattr);
- return 0;
- }
- #endif /* CONFIG_NFS_V3_ACL */
- #define PROC(proc, argtype, restype, timer) \
- [NFS3PROC_##proc] = { \
- .p_proc = NFS3PROC_##proc, \
- .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
- .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
- .p_arglen = NFS3_##argtype##_sz, \
- .p_replen = NFS3_##restype##_sz, \
- .p_timer = timer, \
- .p_statidx = NFS3PROC_##proc, \
- .p_name = #proc, \
- }
- struct rpc_procinfo nfs3_procedures[] = {
- PROC(GETATTR, fhandle, attrstat, 1),
- PROC(SETATTR, sattrargs, wccstat, 0),
- PROC(LOOKUP, diropargs, lookupres, 2),
- PROC(ACCESS, accessargs, accessres, 1),
- PROC(READLINK, readlinkargs, readlinkres, 3),
- PROC(READ, readargs, readres, 3),
- PROC(WRITE, writeargs, writeres, 4),
- PROC(CREATE, createargs, createres, 0),
- PROC(MKDIR, mkdirargs, createres, 0),
- PROC(SYMLINK, symlinkargs, createres, 0),
- PROC(MKNOD, mknodargs, createres, 0),
- PROC(REMOVE, removeargs, removeres, 0),
- PROC(RMDIR, diropargs, wccstat, 0),
- PROC(RENAME, renameargs, renameres, 0),
- PROC(LINK, linkargs, linkres, 0),
- PROC(READDIR, readdirargs, readdirres, 3),
- PROC(READDIRPLUS, readdirargs, readdirres, 3),
- PROC(FSSTAT, fhandle, fsstatres, 0),
- PROC(FSINFO, fhandle, fsinfores, 0),
- PROC(PATHCONF, fhandle, pathconfres, 0),
- PROC(COMMIT, commitargs, commitres, 5),
- };
- struct rpc_version nfs_version3 = {
- .number = 3,
- .nrprocs = ARRAY_SIZE(nfs3_procedures),
- .procs = nfs3_procedures
- };
- #ifdef CONFIG_NFS_V3_ACL
- static struct rpc_procinfo nfs3_acl_procedures[] = {
- [ACLPROC3_GETACL] = {
- .p_proc = ACLPROC3_GETACL,
- .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
- .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
- .p_arglen = ACL3_getaclargs_sz,
- .p_replen = ACL3_getaclres_sz,
- .p_timer = 1,
- .p_name = "GETACL",
- },
- [ACLPROC3_SETACL] = {
- .p_proc = ACLPROC3_SETACL,
- .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
- .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
- .p_arglen = ACL3_setaclargs_sz,
- .p_replen = ACL3_setaclres_sz,
- .p_timer = 0,
- .p_name = "SETACL",
- },
- };
- struct rpc_version nfsacl_version3 = {
- .number = 3,
- .nrprocs = sizeof(nfs3_acl_procedures)/
- sizeof(nfs3_acl_procedures[0]),
- .procs = nfs3_acl_procedures,
- };
- #endif /* CONFIG_NFS_V3_ACL */
|