|
Lines 127-132
static enum nfsclds_state nfscl_getsames
Link Here
|
| 127 |
static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *, |
127 |
static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *, |
| 128 |
struct nfsfh *, struct ucred *, NFSPROC_T *, void *); |
128 |
struct nfsfh *, struct ucred *, NFSPROC_T *, void *); |
| 129 |
#endif |
129 |
#endif |
|
|
130 |
static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t, |
| 131 |
uint64_t, uint64_t, nfsv4stateid_t *, int, int); |
| 132 |
static int nfsrv_parselayoutget(struct nfsrv_descript *, nfsv4stateid_t *, |
| 133 |
int *, struct nfsclflayouthead *); |
| 134 |
static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *, |
| 135 |
int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, |
| 136 |
struct nfscldeleg **, struct ucred *, NFSPROC_T *); |
| 137 |
static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *, |
| 138 |
nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, |
| 139 |
struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, |
| 140 |
struct nfsfh **, int *, int *, void *, int *); |
| 141 |
static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *, |
| 142 |
int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, |
| 143 |
struct nfscldeleg **, nfsv4stateid_t *, int, int, int *, |
| 144 |
struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *); |
| 145 |
static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *, |
| 146 |
nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, |
| 147 |
struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, |
| 148 |
struct nfsfh **, int *, int *, void *, int *, nfsv4stateid_t *, |
| 149 |
int, int, int *, struct nfsclflayouthead *, int *); |
| 150 |
static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *, |
| 151 |
int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **, |
| 152 |
struct nfsclflayouthead *, int, int *, struct ucred *, NFSPROC_T *); |
| 130 |
|
153 |
|
| 131 |
/* |
154 |
/* |
| 132 |
* nfs null call from vfs. |
155 |
* nfs null call from vfs. |
|
Lines 301-311
else printf(" fhl=0\n");
Link Here
|
| 301 |
clidrev = 0; |
324 |
clidrev = 0; |
| 302 |
if (ret == NFSCLOPEN_DOOPEN) { |
325 |
if (ret == NFSCLOPEN_DOOPEN) { |
| 303 |
if (np->n_v4 != NULL) { |
326 |
if (np->n_v4 != NULL) { |
| 304 |
error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data, |
327 |
/* |
| 305 |
np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, |
328 |
* For the first attempt, try and get a layout, if |
| 306 |
np->n_fhp->nfh_len, mode, op, |
329 |
* pNFS is enabled for the mount. |
| 307 |
NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp, |
330 |
*/ |
| 308 |
0, 0x0, cred, p, 0, 0); |
331 |
if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || |
|
|
332 |
nfs_numnfscbd == 0 || |
| 333 |
(np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0) |
| 334 |
error = nfsrpc_openrpc(nmp, vp, |
| 335 |
np->n_v4->n4_data, |
| 336 |
np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, |
| 337 |
np->n_fhp->nfh_len, mode, op, |
| 338 |
NFS4NODENAME(np->n_v4), |
| 339 |
np->n_v4->n4_namelen, |
| 340 |
&dp, 0, 0x0, cred, p, 0, 0); |
| 341 |
else |
| 342 |
error = nfsrpc_getopenlayout(nmp, vp, |
| 343 |
np->n_v4->n4_data, |
| 344 |
np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, |
| 345 |
np->n_fhp->nfh_len, mode, op, |
| 346 |
NFS4NODENAME(np->n_v4), |
| 347 |
np->n_v4->n4_namelen, &dp, cred, p); |
| 309 |
if (dp != NULL) { |
348 |
if (dp != NULL) { |
| 310 |
#ifdef APPLE |
349 |
#ifdef APPLE |
| 311 |
OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag); |
350 |
OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag); |
|
Lines 1894-1902
nfsrpc_create(vnode_t dvp, char *name, i
Link Here
|
| 1894 |
clidrev = nmp->nm_clp->nfsc_clientidrev; |
1933 |
clidrev = nmp->nm_clp->nfsc_clientidrev; |
| 1895 |
else |
1934 |
else |
| 1896 |
clidrev = 0; |
1935 |
clidrev = 0; |
| 1897 |
error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode, |
1936 |
if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || |
| 1898 |
owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, |
1937 |
nfs_numnfscbd == 0 || retrycnt > 0) |
| 1899 |
dstuff, &unlocked); |
1938 |
error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, |
|
|
1939 |
fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, |
| 1940 |
attrflagp, dattrflagp, dstuff, &unlocked); |
| 1941 |
else |
| 1942 |
error = nfsrpc_getcreatelayout(dvp, name, namelen, vap, |
| 1943 |
cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, |
| 1944 |
attrflagp, dattrflagp, dstuff, &unlocked); |
| 1900 |
/* |
1945 |
/* |
| 1901 |
* There is no need to invalidate cached attributes here, |
1946 |
* There is no need to invalidate cached attributes here, |
| 1902 |
* since new post-delegation issue attributes are always |
1947 |
* since new post-delegation issue attributes are always |
|
Lines 4766-4914
nfsrpc_layoutget(struct nfsmount *nmp, u
Link Here
|
| 4766 |
nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp, |
4811 |
nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp, |
| 4767 |
struct ucred *cred, NFSPROC_T *p, void *stuff) |
4812 |
struct ucred *cred, NFSPROC_T *p, void *stuff) |
| 4768 |
{ |
4813 |
{ |
| 4769 |
uint32_t *tl; |
|
|
| 4770 |
struct nfsrv_descript nfsd, *nd = &nfsd; |
4814 |
struct nfsrv_descript nfsd, *nd = &nfsd; |
| 4771 |
struct nfsfh *nfhp; |
4815 |
int error; |
| 4772 |
struct nfsclflayout *flp, *prevflp, *tflp; |
|
|
| 4773 |
int cnt, error, gotiomode, fhcnt, nfhlen, i, j; |
| 4774 |
uint8_t *cp; |
| 4775 |
uint64_t retlen; |
| 4776 |
|
4816 |
|
| 4777 |
flp = NULL; |
|
|
| 4778 |
gotiomode = -1; |
| 4779 |
nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL); |
4817 |
nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL); |
| 4780 |
NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + |
4818 |
nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp, |
| 4781 |
NFSX_STATEID); |
4819 |
layoutlen, 0); |
| 4782 |
*tl++ = newnfs_false; /* Don't signal availability. */ |
|
|
| 4783 |
*tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES); |
| 4784 |
*tl++ = txdr_unsigned(iomode); |
| 4785 |
txdr_hyper(offset, tl); |
| 4786 |
tl += 2; |
| 4787 |
txdr_hyper(len, tl); |
| 4788 |
tl += 2; |
| 4789 |
txdr_hyper(minlen, tl); |
| 4790 |
tl += 2; |
| 4791 |
*tl++ = txdr_unsigned(stateidp->seqid); |
| 4792 |
NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); |
| 4793 |
*tl++ = stateidp->other[0]; |
| 4794 |
*tl++ = stateidp->other[1]; |
| 4795 |
*tl++ = stateidp->other[2]; |
| 4796 |
*tl = txdr_unsigned(layoutlen); |
| 4797 |
nd->nd_flag |= ND_USEGSSNAME; |
4820 |
nd->nd_flag |= ND_USEGSSNAME; |
| 4798 |
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, |
4821 |
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, |
| 4799 |
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); |
4822 |
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); |
|
|
4823 |
NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat); |
| 4800 |
if (error != 0) |
4824 |
if (error != 0) |
| 4801 |
return (error); |
4825 |
return (error); |
| 4802 |
if (nd->nd_repstat == 0) { |
4826 |
if (nd->nd_repstat == 0) |
| 4803 |
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); |
4827 |
error = nfsrv_parselayoutget(nd, stateidp, retonclosep, flhp); |
| 4804 |
if (*tl++ != 0) |
4828 |
if (error == 0 && nd->nd_repstat != 0) |
| 4805 |
*retonclosep = 1; |
|
|
| 4806 |
else |
| 4807 |
*retonclosep = 0; |
| 4808 |
stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); |
| 4809 |
NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, |
| 4810 |
(int)stateidp->seqid); |
| 4811 |
stateidp->other[0] = *tl++; |
| 4812 |
stateidp->other[1] = *tl++; |
| 4813 |
stateidp->other[2] = *tl++; |
| 4814 |
cnt = fxdr_unsigned(int, *tl); |
| 4815 |
NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); |
| 4816 |
if (cnt <= 0 || cnt > 10000) { |
| 4817 |
/* Don't accept more than 10000 layouts in reply. */ |
| 4818 |
error = NFSERR_BADXDR; |
| 4819 |
goto nfsmout; |
| 4820 |
} |
| 4821 |
for (i = 0; i < cnt; i++) { |
| 4822 |
/* Dissect all the way to the file handle cnt. */ |
| 4823 |
NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER + |
| 4824 |
6 * NFSX_UNSIGNED + NFSX_V4DEVICEID); |
| 4825 |
fhcnt = fxdr_unsigned(int, *(tl + 11 + |
| 4826 |
NFSX_V4DEVICEID / NFSX_UNSIGNED)); |
| 4827 |
NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); |
| 4828 |
if (fhcnt < 0 || fhcnt > 100) { |
| 4829 |
/* Don't accept more than 100 file handles. */ |
| 4830 |
error = NFSERR_BADXDR; |
| 4831 |
goto nfsmout; |
| 4832 |
} |
| 4833 |
if (fhcnt > 1) |
| 4834 |
flp = malloc(sizeof(*flp) + (fhcnt - 1) * |
| 4835 |
sizeof(struct nfsfh *), |
| 4836 |
M_NFSFLAYOUT, M_WAITOK); |
| 4837 |
else |
| 4838 |
flp = malloc(sizeof(*flp), |
| 4839 |
M_NFSFLAYOUT, M_WAITOK); |
| 4840 |
flp->nfsfl_flags = 0; |
| 4841 |
flp->nfsfl_fhcnt = 0; |
| 4842 |
flp->nfsfl_devp = NULL; |
| 4843 |
flp->nfsfl_off = fxdr_hyper(tl); tl += 2; |
| 4844 |
retlen = fxdr_hyper(tl); tl += 2; |
| 4845 |
if (flp->nfsfl_off + retlen < flp->nfsfl_off) |
| 4846 |
flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; |
| 4847 |
else |
| 4848 |
flp->nfsfl_end = flp->nfsfl_off + retlen; |
| 4849 |
flp->nfsfl_iomode = fxdr_unsigned(int, *tl++); |
| 4850 |
if (gotiomode == -1) |
| 4851 |
gotiomode = flp->nfsfl_iomode; |
| 4852 |
NFSCL_DEBUG(4, "layg reqiom=%d retiom=%d\n", iomode, |
| 4853 |
(int)flp->nfsfl_iomode); |
| 4854 |
if (fxdr_unsigned(int, *tl++) != |
| 4855 |
NFSLAYOUT_NFSV4_1_FILES) { |
| 4856 |
printf("NFSv4.1: got non-files layout\n"); |
| 4857 |
error = NFSERR_BADXDR; |
| 4858 |
goto nfsmout; |
| 4859 |
} |
| 4860 |
NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID); |
| 4861 |
tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); |
| 4862 |
flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); |
| 4863 |
NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); |
| 4864 |
flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); |
| 4865 |
flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; |
| 4866 |
if (fxdr_unsigned(int, *tl) != fhcnt) { |
| 4867 |
printf("EEK! bad fhcnt\n"); |
| 4868 |
error = NFSERR_BADXDR; |
| 4869 |
goto nfsmout; |
| 4870 |
} |
| 4871 |
for (j = 0; j < fhcnt; j++) { |
| 4872 |
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); |
| 4873 |
nfhlen = fxdr_unsigned(int, *tl); |
| 4874 |
if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { |
| 4875 |
error = NFSERR_BADXDR; |
| 4876 |
goto nfsmout; |
| 4877 |
} |
| 4878 |
nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, |
| 4879 |
M_NFSFH, M_WAITOK); |
| 4880 |
flp->nfsfl_fh[j] = nfhp; |
| 4881 |
flp->nfsfl_fhcnt++; |
| 4882 |
nfhp->nfh_len = nfhlen; |
| 4883 |
NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); |
| 4884 |
NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); |
| 4885 |
} |
| 4886 |
if (flp->nfsfl_iomode == gotiomode) { |
| 4887 |
/* Keep the list in increasing offset order. */ |
| 4888 |
tflp = LIST_FIRST(flhp); |
| 4889 |
prevflp = NULL; |
| 4890 |
while (tflp != NULL && |
| 4891 |
tflp->nfsfl_off < flp->nfsfl_off) { |
| 4892 |
prevflp = tflp; |
| 4893 |
tflp = LIST_NEXT(tflp, nfsfl_list); |
| 4894 |
} |
| 4895 |
if (prevflp == NULL) |
| 4896 |
LIST_INSERT_HEAD(flhp, flp, nfsfl_list); |
| 4897 |
else |
| 4898 |
LIST_INSERT_AFTER(prevflp, flp, |
| 4899 |
nfsfl_list); |
| 4900 |
} else { |
| 4901 |
printf("nfscl_layoutget(): got wrong iomode\n"); |
| 4902 |
nfscl_freeflayout(flp); |
| 4903 |
} |
| 4904 |
flp = NULL; |
| 4905 |
} |
| 4906 |
} |
| 4907 |
if (nd->nd_repstat != 0 && error == 0) |
| 4908 |
error = nd->nd_repstat; |
4829 |
error = nd->nd_repstat; |
| 4909 |
nfsmout: |
|
|
| 4910 |
if (error != 0 && flp != NULL) |
| 4911 |
nfscl_freeflayout(flp); |
| 4912 |
mbuf_freem(nd->nd_mrep); |
4830 |
mbuf_freem(nd->nd_mrep); |
| 4913 |
return (error); |
4831 |
return (error); |
| 4914 |
} |
4832 |
} |
|
Lines 5209-5216
nfsrpc_getlayout(struct nfsmount *nmp, v
Link Here
|
| 5209 |
struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) |
5127 |
struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) |
| 5210 |
{ |
5128 |
{ |
| 5211 |
struct nfscllayout *lyp; |
5129 |
struct nfscllayout *lyp; |
| 5212 |
struct nfsclflayout *flp, *tflp; |
5130 |
struct nfsclflayout *flp; |
| 5213 |
struct nfscldevinfo *dip; |
|
|
| 5214 |
struct nfsclflayouthead flh; |
5131 |
struct nfsclflayouthead flh; |
| 5215 |
int error = 0, islocked, layoutlen, recalled, retonclose; |
5132 |
int error = 0, islocked, layoutlen, recalled, retonclose; |
| 5216 |
nfsv4stateid_t stateid; |
5133 |
nfsv4stateid_t stateid; |
|
Lines 5252-5286
nfsrpc_getlayout(struct nfsmount *nmp, v
Link Here
|
| 5252 |
(uint64_t)0, layoutlen, &stateid, &retonclose, |
5169 |
(uint64_t)0, layoutlen, &stateid, &retonclose, |
| 5253 |
&flh, cred, p, NULL); |
5170 |
&flh, cred, p, NULL); |
| 5254 |
} |
5171 |
} |
|
|
5172 |
error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh, |
| 5173 |
nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp, |
| 5174 |
&flh, error, NULL, cred, p); |
| 5255 |
if (error == 0) |
5175 |
if (error == 0) |
| 5256 |
LIST_FOREACH(tflp, &flh, nfsfl_list) { |
5176 |
*lypp = lyp; |
| 5257 |
error = nfscl_adddevinfo(nmp, NULL, tflp); |
5177 |
else if (islocked != 0) |
| 5258 |
if (error != 0) { |
5178 |
nfscl_rellayout(lyp, 1); |
| 5259 |
error = nfsrpc_getdeviceinfo(nmp, |
|
|
| 5260 |
tflp->nfsfl_dev, |
| 5261 |
NFSLAYOUT_NFSV4_1_FILES, |
| 5262 |
notifybitsp, &dip, cred, p); |
| 5263 |
if (error != 0) |
| 5264 |
break; |
| 5265 |
error = nfscl_adddevinfo(nmp, dip, |
| 5266 |
tflp); |
| 5267 |
if (error != 0) |
| 5268 |
printf( |
| 5269 |
"getlayout: cannot add\n"); |
| 5270 |
} |
| 5271 |
} |
| 5272 |
if (error == 0) { |
| 5273 |
/* |
| 5274 |
* nfscl_layout() always returns with the nfsly_lock |
| 5275 |
* set to a refcnt (shared lock). |
| 5276 |
*/ |
| 5277 |
error = nfscl_layout(nmp, vp, nfhp->nfh_fh, |
| 5278 |
nfhp->nfh_len, &stateid, retonclose, &flh, &lyp, |
| 5279 |
cred, p); |
| 5280 |
if (error == 0) |
| 5281 |
*lypp = lyp; |
| 5282 |
} else if (islocked != 0) |
| 5283 |
nfsv4_unlock(&lyp->nfsly_lock, 0); |
| 5284 |
} else |
5179 |
} else |
| 5285 |
*lypp = lyp; |
5180 |
*lypp = lyp; |
| 5286 |
return (error); |
5181 |
return (error); |
|
Lines 6003-6005
nfsmout:
Link Here
|
| 6003 |
} |
5898 |
} |
| 6004 |
#endif |
5899 |
#endif |
| 6005 |
|
5900 |
|
|
|
5901 |
/* |
| 5902 |
* Set up the XDR arguments for the LayoutGet operation. |
| 5903 |
*/ |
| 5904 |
static void |
| 5905 |
nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset, |
| 5906 |
uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layoutlen, |
| 5907 |
int usecurstateid) |
| 5908 |
{ |
| 5909 |
uint32_t *tl; |
| 5910 |
|
| 5911 |
NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + |
| 5912 |
NFSX_STATEID); |
| 5913 |
*tl++ = newnfs_false; /* Don't signal availability. */ |
| 5914 |
*tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES); |
| 5915 |
*tl++ = txdr_unsigned(iomode); |
| 5916 |
txdr_hyper(offset, tl); |
| 5917 |
tl += 2; |
| 5918 |
txdr_hyper(len, tl); |
| 5919 |
tl += 2; |
| 5920 |
txdr_hyper(minlen, tl); |
| 5921 |
tl += 2; |
| 5922 |
if (usecurstateid != 0) { |
| 5923 |
/* Special stateid for Current stateid. */ |
| 5924 |
*tl++ = txdr_unsigned(1); |
| 5925 |
*tl++ = 0; |
| 5926 |
*tl++ = 0; |
| 5927 |
*tl++ = 0; |
| 5928 |
} else { |
| 5929 |
*tl++ = txdr_unsigned(stateidp->seqid); |
| 5930 |
NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); |
| 5931 |
*tl++ = stateidp->other[0]; |
| 5932 |
*tl++ = stateidp->other[1]; |
| 5933 |
*tl++ = stateidp->other[2]; |
| 5934 |
} |
| 5935 |
*tl = txdr_unsigned(layoutlen); |
| 5936 |
} |
| 5937 |
|
| 5938 |
/* |
| 5939 |
* Parse the reply for a successful LayoutGet operation. |
| 5940 |
*/ |
| 5941 |
static int |
| 5942 |
nfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, |
| 5943 |
int *retonclosep, struct nfsclflayouthead *flhp) |
| 5944 |
{ |
| 5945 |
uint32_t *tl; |
| 5946 |
struct nfsclflayout *flp, *prevflp, *tflp; |
| 5947 |
int cnt, error, gotiomode, fhcnt, nfhlen, i, j; |
| 5948 |
uint64_t retlen; |
| 5949 |
struct nfsfh *nfhp; |
| 5950 |
uint8_t *cp; |
| 5951 |
|
| 5952 |
error = 0; |
| 5953 |
flp = NULL; |
| 5954 |
gotiomode = -1; |
| 5955 |
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); |
| 5956 |
if (*tl++ != 0) |
| 5957 |
*retonclosep = 1; |
| 5958 |
else |
| 5959 |
*retonclosep = 0; |
| 5960 |
stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); |
| 5961 |
NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, |
| 5962 |
(int)stateidp->seqid); |
| 5963 |
stateidp->other[0] = *tl++; |
| 5964 |
stateidp->other[1] = *tl++; |
| 5965 |
stateidp->other[2] = *tl++; |
| 5966 |
cnt = fxdr_unsigned(int, *tl); |
| 5967 |
NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); |
| 5968 |
if (cnt <= 0 || cnt > 10000) { |
| 5969 |
/* Don't accept more than 10000 layouts in reply. */ |
| 5970 |
error = NFSERR_BADXDR; |
| 5971 |
goto nfsmout; |
| 5972 |
} |
| 5973 |
for (i = 0; i < cnt; i++) { |
| 5974 |
/* Dissect all the way to the file handle cnt. */ |
| 5975 |
NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER + |
| 5976 |
6 * NFSX_UNSIGNED + NFSX_V4DEVICEID); |
| 5977 |
fhcnt = fxdr_unsigned(int, *(tl + 11 + |
| 5978 |
NFSX_V4DEVICEID / NFSX_UNSIGNED)); |
| 5979 |
NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); |
| 5980 |
if (fhcnt < 0 || fhcnt > 100) { |
| 5981 |
/* Don't accept more than 100 file handles. */ |
| 5982 |
error = NFSERR_BADXDR; |
| 5983 |
goto nfsmout; |
| 5984 |
} |
| 5985 |
if (fhcnt > 1) |
| 5986 |
flp = malloc(sizeof(*flp) + (fhcnt - 1) * |
| 5987 |
sizeof(struct nfsfh *), M_NFSFLAYOUT, M_WAITOK); |
| 5988 |
else |
| 5989 |
flp = malloc(sizeof(*flp), M_NFSFLAYOUT, M_WAITOK); |
| 5990 |
flp->nfsfl_flags = 0; |
| 5991 |
flp->nfsfl_fhcnt = 0; |
| 5992 |
flp->nfsfl_devp = NULL; |
| 5993 |
flp->nfsfl_off = fxdr_hyper(tl); tl += 2; |
| 5994 |
retlen = fxdr_hyper(tl); tl += 2; |
| 5995 |
if (flp->nfsfl_off + retlen < flp->nfsfl_off) |
| 5996 |
flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; |
| 5997 |
else |
| 5998 |
flp->nfsfl_end = flp->nfsfl_off + retlen; |
| 5999 |
flp->nfsfl_iomode = fxdr_unsigned(int, *tl++); |
| 6000 |
if (gotiomode == -1) |
| 6001 |
gotiomode = flp->nfsfl_iomode; |
| 6002 |
if (fxdr_unsigned(int, *tl++) != NFSLAYOUT_NFSV4_1_FILES) { |
| 6003 |
printf("NFSv4.1: got non-files layout\n"); |
| 6004 |
error = NFSERR_BADXDR; |
| 6005 |
goto nfsmout; |
| 6006 |
} |
| 6007 |
NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID); |
| 6008 |
tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); |
| 6009 |
flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); |
| 6010 |
NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); |
| 6011 |
flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); |
| 6012 |
flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; |
| 6013 |
if (fxdr_unsigned(int, *tl) != fhcnt) { |
| 6014 |
printf("EEK! bad fhcnt\n"); |
| 6015 |
error = NFSERR_BADXDR; |
| 6016 |
goto nfsmout; |
| 6017 |
} |
| 6018 |
for (j = 0; j < fhcnt; j++) { |
| 6019 |
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); |
| 6020 |
nfhlen = fxdr_unsigned(int, *tl); |
| 6021 |
if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { |
| 6022 |
error = NFSERR_BADXDR; |
| 6023 |
goto nfsmout; |
| 6024 |
} |
| 6025 |
nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, M_NFSFH, |
| 6026 |
M_WAITOK); |
| 6027 |
flp->nfsfl_fh[j] = nfhp; |
| 6028 |
flp->nfsfl_fhcnt++; |
| 6029 |
nfhp->nfh_len = nfhlen; |
| 6030 |
NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); |
| 6031 |
NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); |
| 6032 |
} |
| 6033 |
if (flp->nfsfl_iomode == gotiomode) { |
| 6034 |
/* Keep the list in increasing offset order. */ |
| 6035 |
tflp = LIST_FIRST(flhp); |
| 6036 |
prevflp = NULL; |
| 6037 |
while (tflp != NULL && |
| 6038 |
tflp->nfsfl_off < flp->nfsfl_off) { |
| 6039 |
prevflp = tflp; |
| 6040 |
tflp = LIST_NEXT(tflp, nfsfl_list); |
| 6041 |
} |
| 6042 |
if (prevflp == NULL) |
| 6043 |
LIST_INSERT_HEAD(flhp, flp, nfsfl_list); |
| 6044 |
else |
| 6045 |
LIST_INSERT_AFTER(prevflp, flp, |
| 6046 |
nfsfl_list); |
| 6047 |
} else { |
| 6048 |
printf("nfscl_layoutget(): got wrong iomode\n"); |
| 6049 |
nfscl_freeflayout(flp); |
| 6050 |
} |
| 6051 |
flp = NULL; |
| 6052 |
} |
| 6053 |
nfsmout: |
| 6054 |
if (error != 0 && flp != NULL) |
| 6055 |
nfscl_freeflayout(flp); |
| 6056 |
return (error); |
| 6057 |
} |
| 6058 |
|
| 6059 |
/* |
| 6060 |
* Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(), |
| 6061 |
* so that it does both an Open and a Layoutget. |
| 6062 |
*/ |
| 6063 |
static int |
| 6064 |
nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, |
| 6065 |
int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, |
| 6066 |
struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, |
| 6067 |
struct ucred *cred, NFSPROC_T *p) |
| 6068 |
{ |
| 6069 |
struct nfscllayout *lyp; |
| 6070 |
struct nfsclflayout *flp; |
| 6071 |
struct nfsclflayouthead flh; |
| 6072 |
int error, islocked, layoutlen, recalled, retonclose, usecurstateid; |
| 6073 |
int laystat; |
| 6074 |
nfsv4stateid_t stateid; |
| 6075 |
struct nfsclsession *tsep; |
| 6076 |
|
| 6077 |
error = 0; |
| 6078 |
/* |
| 6079 |
* If lyp is returned non-NULL, there will be a refcnt (shared lock) |
| 6080 |
* on it, iff flp != NULL or a lock (exclusive lock) on it iff |
| 6081 |
* flp == NULL. |
| 6082 |
*/ |
| 6083 |
lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, &flp, |
| 6084 |
&recalled); |
| 6085 |
NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp); |
| 6086 |
if (lyp == NULL) |
| 6087 |
islocked = 0; |
| 6088 |
else if (flp != NULL) |
| 6089 |
islocked = 1; |
| 6090 |
else |
| 6091 |
islocked = 2; |
| 6092 |
if ((lyp == NULL || flp == NULL) && recalled == 0) { |
| 6093 |
LIST_INIT(&flh); |
| 6094 |
tsep = nfsmnt_mdssession(nmp); |
| 6095 |
layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + |
| 6096 |
3 * NFSX_UNSIGNED); |
| 6097 |
if (lyp == NULL) |
| 6098 |
usecurstateid = 1; |
| 6099 |
else { |
| 6100 |
usecurstateid = 0; |
| 6101 |
stateid.seqid = lyp->nfsly_stateid.seqid; |
| 6102 |
stateid.other[0] = lyp->nfsly_stateid.other[0]; |
| 6103 |
stateid.other[1] = lyp->nfsly_stateid.other[1]; |
| 6104 |
stateid.other[2] = lyp->nfsly_stateid.other[2]; |
| 6105 |
} |
| 6106 |
error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen, |
| 6107 |
newfhp, newfhlen, mode, op, name, namelen, |
| 6108 |
dpp, &stateid, usecurstateid, layoutlen, |
| 6109 |
&retonclose, &flh, &laystat, cred, p); |
| 6110 |
NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n", |
| 6111 |
laystat, error); |
| 6112 |
laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen, |
| 6113 |
&stateid, retonclose, NULL, &lyp, &flh, laystat, &islocked, |
| 6114 |
cred, p); |
| 6115 |
} else |
| 6116 |
error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, |
| 6117 |
mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0); |
| 6118 |
if (islocked == 2) |
| 6119 |
nfscl_rellayout(lyp, 1); |
| 6120 |
else if (islocked == 1) |
| 6121 |
nfscl_rellayout(lyp, 0); |
| 6122 |
return (error); |
| 6123 |
} |
| 6124 |
|
| 6125 |
/* |
| 6126 |
* This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS |
| 6127 |
* enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are |
| 6128 |
* handled by nfsrpc_openrpc(). |
| 6129 |
* For the case where op == NULL, dvp is the directory. When op != NULL, it |
| 6130 |
* can be NULL. |
| 6131 |
*/ |
| 6132 |
static int |
| 6133 |
nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, |
| 6134 |
int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, |
| 6135 |
struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, |
| 6136 |
nfsv4stateid_t *stateidp, int usecurstateid, |
| 6137 |
int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp, |
| 6138 |
int *laystatp, struct ucred *cred, NFSPROC_T *p) |
| 6139 |
{ |
| 6140 |
uint32_t *tl; |
| 6141 |
struct nfsrv_descript nfsd, *nd = &nfsd; |
| 6142 |
struct nfscldeleg *ndp = NULL; |
| 6143 |
struct nfsvattr nfsva; |
| 6144 |
struct nfsclsession *tsep; |
| 6145 |
uint32_t rflags, deleg; |
| 6146 |
nfsattrbit_t attrbits; |
| 6147 |
int error, ret, acesize, limitby, iomode; |
| 6148 |
|
| 6149 |
*dpp = NULL; |
| 6150 |
*laystatp = ENXIO; |
| 6151 |
nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL); |
| 6152 |
NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); |
| 6153 |
*tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); |
| 6154 |
*tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); |
| 6155 |
*tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); |
| 6156 |
tsep = nfsmnt_mdssession(nmp); |
| 6157 |
*tl++ = tsep->nfsess_clientid.lval[0]; |
| 6158 |
*tl = tsep->nfsess_clientid.lval[1]; |
| 6159 |
nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); |
| 6160 |
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); |
| 6161 |
*tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); |
| 6162 |
*tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); |
| 6163 |
nfsm_strtom(nd, name, namelen); |
| 6164 |
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); |
| 6165 |
*tl = txdr_unsigned(NFSV4OP_GETATTR); |
| 6166 |
NFSZERO_ATTRBIT(&attrbits); |
| 6167 |
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); |
| 6168 |
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); |
| 6169 |
nfsrv_putattrbit(nd, &attrbits); |
| 6170 |
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); |
| 6171 |
*tl = txdr_unsigned(NFSV4OP_LAYOUTGET); |
| 6172 |
if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) |
| 6173 |
iomode = NFSLAYOUTIOMODE_RW; |
| 6174 |
else |
| 6175 |
iomode = NFSLAYOUTIOMODE_READ; |
| 6176 |
nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp, |
| 6177 |
layoutlen, usecurstateid); |
| 6178 |
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, |
| 6179 |
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); |
| 6180 |
if (error != 0) |
| 6181 |
return (error); |
| 6182 |
NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); |
| 6183 |
if (nd->nd_repstat != 0) |
| 6184 |
*laystatp = nd->nd_repstat; |
| 6185 |
if ((nd->nd_flag & ND_NOMOREDATA) == 0) { |
| 6186 |
/* ND_NOMOREDATA will be set if the Open operation failed. */ |
| 6187 |
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + |
| 6188 |
6 * NFSX_UNSIGNED); |
| 6189 |
op->nfso_stateid.seqid = *tl++; |
| 6190 |
op->nfso_stateid.other[0] = *tl++; |
| 6191 |
op->nfso_stateid.other[1] = *tl++; |
| 6192 |
op->nfso_stateid.other[2] = *tl; |
| 6193 |
rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); |
| 6194 |
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); |
| 6195 |
if (error != 0) |
| 6196 |
goto nfsmout; |
| 6197 |
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); |
| 6198 |
deleg = fxdr_unsigned(u_int32_t, *tl); |
| 6199 |
if (deleg == NFSV4OPEN_DELEGATEREAD || |
| 6200 |
deleg == NFSV4OPEN_DELEGATEWRITE) { |
| 6201 |
if (!(op->nfso_own->nfsow_clp->nfsc_flags & |
| 6202 |
NFSCLFLAGS_FIRSTDELEG)) |
| 6203 |
op->nfso_own->nfsow_clp->nfsc_flags |= |
| 6204 |
(NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); |
| 6205 |
ndp = malloc(sizeof(struct nfscldeleg) + newfhlen, |
| 6206 |
M_NFSCLDELEG, M_WAITOK); |
| 6207 |
LIST_INIT(&ndp->nfsdl_owner); |
| 6208 |
LIST_INIT(&ndp->nfsdl_lock); |
| 6209 |
ndp->nfsdl_clp = op->nfso_own->nfsow_clp; |
| 6210 |
ndp->nfsdl_fhlen = newfhlen; |
| 6211 |
NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); |
| 6212 |
newnfs_copyincred(cred, &ndp->nfsdl_cred); |
| 6213 |
nfscl_lockinit(&ndp->nfsdl_rwlock); |
| 6214 |
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + |
| 6215 |
NFSX_UNSIGNED); |
| 6216 |
ndp->nfsdl_stateid.seqid = *tl++; |
| 6217 |
ndp->nfsdl_stateid.other[0] = *tl++; |
| 6218 |
ndp->nfsdl_stateid.other[1] = *tl++; |
| 6219 |
ndp->nfsdl_stateid.other[2] = *tl++; |
| 6220 |
ret = fxdr_unsigned(int, *tl); |
| 6221 |
if (deleg == NFSV4OPEN_DELEGATEWRITE) { |
| 6222 |
ndp->nfsdl_flags = NFSCLDL_WRITE; |
| 6223 |
/* |
| 6224 |
* Indicates how much the file can grow. |
| 6225 |
*/ |
| 6226 |
NFSM_DISSECT(tl, u_int32_t *, |
| 6227 |
3 * NFSX_UNSIGNED); |
| 6228 |
limitby = fxdr_unsigned(int, *tl++); |
| 6229 |
switch (limitby) { |
| 6230 |
case NFSV4OPEN_LIMITSIZE: |
| 6231 |
ndp->nfsdl_sizelimit = fxdr_hyper(tl); |
| 6232 |
break; |
| 6233 |
case NFSV4OPEN_LIMITBLOCKS: |
| 6234 |
ndp->nfsdl_sizelimit = |
| 6235 |
fxdr_unsigned(u_int64_t, *tl++); |
| 6236 |
ndp->nfsdl_sizelimit *= |
| 6237 |
fxdr_unsigned(u_int64_t, *tl); |
| 6238 |
break; |
| 6239 |
default: |
| 6240 |
error = NFSERR_BADXDR; |
| 6241 |
goto nfsmout; |
| 6242 |
}; |
| 6243 |
} else |
| 6244 |
ndp->nfsdl_flags = NFSCLDL_READ; |
| 6245 |
if (ret != 0) |
| 6246 |
ndp->nfsdl_flags |= NFSCLDL_RECALL; |
| 6247 |
error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, |
| 6248 |
&acesize, p); |
| 6249 |
if (error != 0) |
| 6250 |
goto nfsmout; |
| 6251 |
} else if (deleg != NFSV4OPEN_DELEGATENONE) { |
| 6252 |
error = NFSERR_BADXDR; |
| 6253 |
goto nfsmout; |
| 6254 |
} |
| 6255 |
if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || |
| 6256 |
nfscl_assumeposixlocks) |
| 6257 |
op->nfso_posixlock = 1; |
| 6258 |
else |
| 6259 |
op->nfso_posixlock = 0; |
| 6260 |
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); |
| 6261 |
/* If the 2nd element == NFS_OK, the Getattr succeeded. */ |
| 6262 |
if (*++tl == 0) { |
| 6263 |
error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, |
| 6264 |
NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, |
| 6265 |
NULL, NULL, NULL, p, cred); |
| 6266 |
if (error != 0) |
| 6267 |
goto nfsmout; |
| 6268 |
if (ndp != NULL) { |
| 6269 |
ndp->nfsdl_change = nfsva.na_filerev; |
| 6270 |
ndp->nfsdl_modtime = nfsva.na_mtime; |
| 6271 |
ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; |
| 6272 |
*dpp = ndp; |
| 6273 |
ndp = NULL; |
| 6274 |
} |
| 6275 |
/* |
| 6276 |
* At this point, the Open has succeeded, so set |
| 6277 |
* nd_repstat = NFS_OK. If the Layoutget failed, |
| 6278 |
* this function just won't return a layout. |
| 6279 |
*/ |
| 6280 |
if (nd->nd_repstat == 0) { |
| 6281 |
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); |
| 6282 |
*laystatp = fxdr_unsigned(int, *++tl); |
| 6283 |
if (*laystatp == 0) { |
| 6284 |
error = nfsrv_parselayoutget(nd, |
| 6285 |
stateidp, retonclosep, flhp); |
| 6286 |
if (error != 0) |
| 6287 |
*laystatp = error; |
| 6288 |
} |
| 6289 |
} else |
| 6290 |
nd->nd_repstat = 0; /* Return 0 for Open. */ |
| 6291 |
} |
| 6292 |
} |
| 6293 |
if (nd->nd_repstat != 0 && error == 0) |
| 6294 |
error = nd->nd_repstat; |
| 6295 |
nfsmout: |
| 6296 |
free(ndp, M_NFSCLDELEG); |
| 6297 |
mbuf_freem(nd->nd_mrep); |
| 6298 |
return (error); |
| 6299 |
} |
| 6300 |
|
| 6301 |
/* |
| 6302 |
* Similar nfsrpc_createv4(), but also does the LayoutGet operation. |
| 6303 |
* Used only for mounts with pNFS enabled. |
| 6304 |
*/ |
| 6305 |
static int |
| 6306 |
nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, |
| 6307 |
nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, |
| 6308 |
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, |
| 6309 |
struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, |
| 6310 |
int *dattrflagp, void *dstuff, int *unlockedp, nfsv4stateid_t *stateidp, |
| 6311 |
int usecurstateid, int layoutlen, int *retonclosep, |
| 6312 |
struct nfsclflayouthead *flhp, int *laystatp) |
| 6313 |
{ |
| 6314 |
uint32_t *tl; |
| 6315 |
int error = 0, deleg, newone, ret, acesize, limitby; |
| 6316 |
struct nfsrv_descript nfsd, *nd = &nfsd; |
| 6317 |
struct nfsclopen *op; |
| 6318 |
struct nfscldeleg *dp = NULL; |
| 6319 |
struct nfsnode *np; |
| 6320 |
struct nfsfh *nfhp; |
| 6321 |
struct nfsclsession *tsep; |
| 6322 |
nfsattrbit_t attrbits; |
| 6323 |
nfsv4stateid_t stateid; |
| 6324 |
uint32_t rflags; |
| 6325 |
struct nfsmount *nmp; |
| 6326 |
|
| 6327 |
nmp = VFSTONFS(dvp->v_mount); |
| 6328 |
np = VTONFS(dvp); |
| 6329 |
*laystatp = ENXIO; |
| 6330 |
*unlockedp = 0; |
| 6331 |
*nfhpp = NULL; |
| 6332 |
*dpp = NULL; |
| 6333 |
*attrflagp = 0; |
| 6334 |
*dattrflagp = 0; |
| 6335 |
if (namelen > NFS_MAXNAMLEN) |
| 6336 |
return (ENAMETOOLONG); |
| 6337 |
NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp); |
| 6338 |
/* |
| 6339 |
* For V4, this is actually an Open op. |
| 6340 |
*/ |
| 6341 |
NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); |
| 6342 |
*tl++ = txdr_unsigned(owp->nfsow_seqid); |
| 6343 |
*tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | |
| 6344 |
NFSV4OPEN_ACCESSREAD); |
| 6345 |
*tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); |
| 6346 |
tsep = nfsmnt_mdssession(nmp); |
| 6347 |
*tl++ = tsep->nfsess_clientid.lval[0]; |
| 6348 |
*tl = tsep->nfsess_clientid.lval[1]; |
| 6349 |
nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); |
| 6350 |
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); |
| 6351 |
*tl++ = txdr_unsigned(NFSV4OPEN_CREATE); |
| 6352 |
if ((fmode & O_EXCL) != 0) { |
| 6353 |
if (NFSHASSESSPERSIST(nmp)) { |
| 6354 |
/* Use GUARDED for persistent sessions. */ |
| 6355 |
*tl = txdr_unsigned(NFSCREATE_GUARDED); |
| 6356 |
nfscl_fillsattr(nd, vap, dvp, 0, 0); |
| 6357 |
} else { |
| 6358 |
/* Otherwise, use EXCLUSIVE4_1. */ |
| 6359 |
*tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); |
| 6360 |
NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); |
| 6361 |
*tl++ = cverf.lval[0]; |
| 6362 |
*tl = cverf.lval[1]; |
| 6363 |
nfscl_fillsattr(nd, vap, dvp, 0, 0); |
| 6364 |
} |
| 6365 |
} else { |
| 6366 |
*tl = txdr_unsigned(NFSCREATE_UNCHECKED); |
| 6367 |
nfscl_fillsattr(nd, vap, dvp, 0, 0); |
| 6368 |
} |
| 6369 |
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); |
| 6370 |
*tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); |
| 6371 |
nfsm_strtom(nd, name, namelen); |
| 6372 |
/* Get the new file's handle and attributes, plus save the FH. */ |
| 6373 |
NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); |
| 6374 |
*tl++ = txdr_unsigned(NFSV4OP_SAVEFH); |
| 6375 |
*tl++ = txdr_unsigned(NFSV4OP_GETFH); |
| 6376 |
*tl = txdr_unsigned(NFSV4OP_GETATTR); |
| 6377 |
NFSGETATTR_ATTRBIT(&attrbits); |
| 6378 |
nfsrv_putattrbit(nd, &attrbits); |
| 6379 |
/* Get the directory's post-op attributes. */ |
| 6380 |
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); |
| 6381 |
*tl = txdr_unsigned(NFSV4OP_PUTFH); |
| 6382 |
nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); |
| 6383 |
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); |
| 6384 |
*tl = txdr_unsigned(NFSV4OP_GETATTR); |
| 6385 |
nfsrv_putattrbit(nd, &attrbits); |
| 6386 |
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); |
| 6387 |
*tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); |
| 6388 |
*tl = txdr_unsigned(NFSV4OP_LAYOUTGET); |
| 6389 |
nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp, |
| 6390 |
layoutlen, usecurstateid); |
| 6391 |
error = nfscl_request(nd, dvp, p, cred, dstuff); |
| 6392 |
if (error != 0) |
| 6393 |
return (error); |
| 6394 |
NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat, |
| 6395 |
error); |
| 6396 |
if (nd->nd_repstat != 0) |
| 6397 |
*laystatp = nd->nd_repstat; |
| 6398 |
NFSCL_INCRSEQID(owp->nfsow_seqid, nd); |
| 6399 |
if ((nd->nd_flag & ND_NOMOREDATA) == 0) { |
| 6400 |
NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n"); |
| 6401 |
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + |
| 6402 |
6 * NFSX_UNSIGNED); |
| 6403 |
stateid.seqid = *tl++; |
| 6404 |
stateid.other[0] = *tl++; |
| 6405 |
stateid.other[1] = *tl++; |
| 6406 |
stateid.other[2] = *tl; |
| 6407 |
rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); |
| 6408 |
nfsrv_getattrbits(nd, &attrbits, NULL, NULL); |
| 6409 |
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); |
| 6410 |
deleg = fxdr_unsigned(int, *tl); |
| 6411 |
if (deleg == NFSV4OPEN_DELEGATEREAD || |
| 6412 |
deleg == NFSV4OPEN_DELEGATEWRITE) { |
| 6413 |
if (!(owp->nfsow_clp->nfsc_flags & |
| 6414 |
NFSCLFLAGS_FIRSTDELEG)) |
| 6415 |
owp->nfsow_clp->nfsc_flags |= |
| 6416 |
(NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); |
| 6417 |
dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX, |
| 6418 |
M_NFSCLDELEG, M_WAITOK); |
| 6419 |
LIST_INIT(&dp->nfsdl_owner); |
| 6420 |
LIST_INIT(&dp->nfsdl_lock); |
| 6421 |
dp->nfsdl_clp = owp->nfsow_clp; |
| 6422 |
newnfs_copyincred(cred, &dp->nfsdl_cred); |
| 6423 |
nfscl_lockinit(&dp->nfsdl_rwlock); |
| 6424 |
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + |
| 6425 |
NFSX_UNSIGNED); |
| 6426 |
dp->nfsdl_stateid.seqid = *tl++; |
| 6427 |
dp->nfsdl_stateid.other[0] = *tl++; |
| 6428 |
dp->nfsdl_stateid.other[1] = *tl++; |
| 6429 |
dp->nfsdl_stateid.other[2] = *tl++; |
| 6430 |
ret = fxdr_unsigned(int, *tl); |
| 6431 |
if (deleg == NFSV4OPEN_DELEGATEWRITE) { |
| 6432 |
dp->nfsdl_flags = NFSCLDL_WRITE; |
| 6433 |
/* |
| 6434 |
* Indicates how much the file can grow. |
| 6435 |
*/ |
| 6436 |
NFSM_DISSECT(tl, u_int32_t *, |
| 6437 |
3 * NFSX_UNSIGNED); |
| 6438 |
limitby = fxdr_unsigned(int, *tl++); |
| 6439 |
switch (limitby) { |
| 6440 |
case NFSV4OPEN_LIMITSIZE: |
| 6441 |
dp->nfsdl_sizelimit = fxdr_hyper(tl); |
| 6442 |
break; |
| 6443 |
case NFSV4OPEN_LIMITBLOCKS: |
| 6444 |
dp->nfsdl_sizelimit = |
| 6445 |
fxdr_unsigned(u_int64_t, *tl++); |
| 6446 |
dp->nfsdl_sizelimit *= |
| 6447 |
fxdr_unsigned(u_int64_t, *tl); |
| 6448 |
break; |
| 6449 |
default: |
| 6450 |
error = NFSERR_BADXDR; |
| 6451 |
goto nfsmout; |
| 6452 |
}; |
| 6453 |
} else { |
| 6454 |
dp->nfsdl_flags = NFSCLDL_READ; |
| 6455 |
} |
| 6456 |
if (ret != 0) |
| 6457 |
dp->nfsdl_flags |= NFSCLDL_RECALL; |
| 6458 |
error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, |
| 6459 |
&acesize, p); |
| 6460 |
if (error != 0) |
| 6461 |
goto nfsmout; |
| 6462 |
} else if (deleg != NFSV4OPEN_DELEGATENONE) { |
| 6463 |
error = NFSERR_BADXDR; |
| 6464 |
goto nfsmout; |
| 6465 |
} |
| 6466 |
|
| 6467 |
/* Now, we should have the status for the SaveFH. */ |
| 6468 |
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); |
| 6469 |
if (*++tl == 0) { |
| 6470 |
NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n"); |
| 6471 |
/* |
| 6472 |
* Now, process the GetFH and Getattr for the newly |
| 6473 |
* created file. nfscl_mtofh() will set |
| 6474 |
* ND_NOMOREDATA if these weren't successful. |
| 6475 |
*/ |
| 6476 |
error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); |
| 6477 |
NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error); |
| 6478 |
if (error != 0) |
| 6479 |
goto nfsmout; |
| 6480 |
} else |
| 6481 |
nd->nd_flag |= ND_NOMOREDATA; |
| 6482 |
/* Now we have the PutFH and Getattr for the directory. */ |
| 6483 |
if ((nd->nd_flag & ND_NOMOREDATA) == 0) { |
| 6484 |
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); |
| 6485 |
if (*++tl != 0) |
| 6486 |
nd->nd_flag |= ND_NOMOREDATA; |
| 6487 |
else { |
| 6488 |
NFSM_DISSECT(tl, uint32_t *, 2 * |
| 6489 |
NFSX_UNSIGNED); |
| 6490 |
if (*++tl != 0) |
| 6491 |
nd->nd_flag |= ND_NOMOREDATA; |
| 6492 |
} |
| 6493 |
} |
| 6494 |
if ((nd->nd_flag & ND_NOMOREDATA) == 0) { |
| 6495 |
/* Load the directory attributes. */ |
| 6496 |
error = nfsm_loadattr(nd, dnap); |
| 6497 |
NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error); |
| 6498 |
if (error != 0) |
| 6499 |
goto nfsmout; |
| 6500 |
*dattrflagp = 1; |
| 6501 |
if (dp != NULL && *attrflagp != 0) { |
| 6502 |
dp->nfsdl_change = nnap->na_filerev; |
| 6503 |
dp->nfsdl_modtime = nnap->na_mtime; |
| 6504 |
dp->nfsdl_flags |= NFSCLDL_MODTIMESET; |
| 6505 |
} |
| 6506 |
/* |
| 6507 |
* We can now complete the Open state. |
| 6508 |
*/ |
| 6509 |
nfhp = *nfhpp; |
| 6510 |
if (dp != NULL) { |
| 6511 |
dp->nfsdl_fhlen = nfhp->nfh_len; |
| 6512 |
NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, |
| 6513 |
nfhp->nfh_len); |
| 6514 |
} |
| 6515 |
/* |
| 6516 |
* Get an Open structure that will be |
| 6517 |
* attached to the OpenOwner, acquired already. |
| 6518 |
*/ |
| 6519 |
error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, |
| 6520 |
(NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, |
| 6521 |
cred, p, NULL, &op, &newone, NULL, 0); |
| 6522 |
if (error != 0) |
| 6523 |
goto nfsmout; |
| 6524 |
op->nfso_stateid = stateid; |
| 6525 |
newnfs_copyincred(cred, &op->nfso_cred); |
| 6526 |
|
| 6527 |
nfscl_openrelease(nmp, op, error, newone); |
| 6528 |
*unlockedp = 1; |
| 6529 |
|
| 6530 |
/* Now, handle the RestoreFH and LayoutGet. */ |
| 6531 |
if (nd->nd_repstat == 0) { |
| 6532 |
NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); |
| 6533 |
*laystatp = fxdr_unsigned(int, *(tl + 3)); |
| 6534 |
if (*laystatp == 0) { |
| 6535 |
error = nfsrv_parselayoutget(nd, |
| 6536 |
stateidp, retonclosep, flhp); |
| 6537 |
if (error != 0) |
| 6538 |
*laystatp = error; |
| 6539 |
} |
| 6540 |
NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n", |
| 6541 |
error); |
| 6542 |
} else |
| 6543 |
nd->nd_repstat = 0; |
| 6544 |
} |
| 6545 |
} |
| 6546 |
if (nd->nd_repstat != 0 && error == 0) |
| 6547 |
error = nd->nd_repstat; |
| 6548 |
if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION) |
| 6549 |
nfscl_initiate_recovery(owp->nfsow_clp); |
| 6550 |
nfsmout: |
| 6551 |
NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error); |
| 6552 |
if (error == 0) |
| 6553 |
*dpp = dp; |
| 6554 |
else |
| 6555 |
free(dp, M_NFSCLDELEG); |
| 6556 |
mbuf_freem(nd->nd_mrep); |
| 6557 |
return (error); |
| 6558 |
} |
| 6559 |
|
| 6560 |
/* |
| 6561 |
* Similar to nfsrpc_getopenlayout(), except that it used for the Create case. |
| 6562 |
*/ |
| 6563 |
static int |
| 6564 |
nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, |
| 6565 |
nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, |
| 6566 |
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, |
| 6567 |
struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, |
| 6568 |
int *dattrflagp, void *dstuff, int *unlockedp) |
| 6569 |
{ |
| 6570 |
struct nfscllayout *lyp; |
| 6571 |
struct nfsclflayouthead flh; |
| 6572 |
struct nfsfh *nfhp; |
| 6573 |
struct nfsclsession *tsep; |
| 6574 |
struct nfsmount *nmp; |
| 6575 |
nfsv4stateid_t stateid; |
| 6576 |
int error, layoutlen, retonclose, laystat; |
| 6577 |
|
| 6578 |
error = 0; |
| 6579 |
nmp = VFSTONFS(dvp->v_mount); |
| 6580 |
LIST_INIT(&flh); |
| 6581 |
tsep = nfsmnt_mdssession(nmp); |
| 6582 |
layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); |
| 6583 |
error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode, |
| 6584 |
owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, |
| 6585 |
dstuff, unlockedp, &stateid, 1, layoutlen, &retonclose, &flh, |
| 6586 |
&laystat); |
| 6587 |
NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n", |
| 6588 |
laystat, error); |
| 6589 |
lyp = NULL; |
| 6590 |
nfhp = *nfhpp; |
| 6591 |
laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh, nfhp->nfh_len, |
| 6592 |
&stateid, retonclose, NULL, &lyp, &flh, laystat, NULL, cred, p); |
| 6593 |
if (laystat == 0) |
| 6594 |
nfscl_rellayout(lyp, 0); |
| 6595 |
return (error); |
| 6596 |
} |
| 6597 |
|
| 6598 |
/* |
| 6599 |
* Process the results of a layoutget() operation. |
| 6600 |
*/ |
| 6601 |
static int |
| 6602 |
nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp, |
| 6603 |
int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit, |
| 6604 |
struct nfscllayout **lypp, struct nfsclflayouthead *flhp, |
| 6605 |
int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p) |
| 6606 |
{ |
| 6607 |
struct nfsclflayout *tflp; |
| 6608 |
struct nfscldevinfo *dip; |
| 6609 |
|
| 6610 |
if (laystat == NFSERR_UNKNLAYOUTTYPE) { |
| 6611 |
/* Disable PNFS. */ |
| 6612 |
NFSCL_DEBUG(1, "disable PNFS\n"); |
| 6613 |
NFSLOCKMNT(nmp); |
| 6614 |
nmp->nm_state &= ~NFSSTA_PNFS; |
| 6615 |
NFSUNLOCKMNT(nmp); |
| 6616 |
} |
| 6617 |
if (laystat == 0) { |
| 6618 |
NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n"); |
| 6619 |
LIST_FOREACH(tflp, flhp, nfsfl_list) { |
| 6620 |
laystat = nfscl_adddevinfo(nmp, NULL, tflp); |
| 6621 |
NFSCL_DEBUG(4, "aft adddev=%d\n", laystat); |
| 6622 |
if (laystat != 0) { |
| 6623 |
laystat = nfsrpc_getdeviceinfo(nmp, |
| 6624 |
tflp->nfsfl_dev, NFSLAYOUT_NFSV4_1_FILES, |
| 6625 |
notifybit, &dip, cred, p); |
| 6626 |
NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n", |
| 6627 |
laystat); |
| 6628 |
if (laystat != 0) |
| 6629 |
break; |
| 6630 |
laystat = nfscl_adddevinfo(nmp, dip, tflp); |
| 6631 |
if (laystat != 0) |
| 6632 |
printf("getlayout: cannot add\n"); |
| 6633 |
} |
| 6634 |
} |
| 6635 |
} |
| 6636 |
if (laystat == 0) { |
| 6637 |
/* |
| 6638 |
* nfscl_layout() always returns with the nfsly_lock |
| 6639 |
* set to a refcnt (shared lock). |
| 6640 |
* Passing in dvp is sufficient, since it is only used to |
| 6641 |
* get the fsid for the file system. |
| 6642 |
*/ |
| 6643 |
laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp, |
| 6644 |
retonclose, flhp, lypp, cred, p); |
| 6645 |
NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n", |
| 6646 |
laystat); |
| 6647 |
if (laystat == 0 && islockedp != NULL) |
| 6648 |
*islockedp = 1; |
| 6649 |
} |
| 6650 |
return (laystat); |
| 6651 |
} |
| 6652 |
|