|
1 /* |
|
2 * CDDL HEADER START |
|
3 * |
|
4 * The contents of this file are subject to the terms of the |
|
5 * Common Development and Distribution License, Version 1.0 only |
|
6 * (the "License"). You may not use this file except in compliance |
|
7 * with the License. |
|
8 * |
|
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
10 * or http://www.opensolaris.org/os/licensing. |
|
11 * See the License for the specific language governing permissions |
|
12 * and limitations under the License. |
|
13 * |
|
14 * When distributing Covered Code, include this CDDL HEADER in each |
|
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
16 * If applicable, add the following below this CDDL HEADER, with the |
|
17 * fields enclosed by brackets "[]" replaced with your own identifying |
|
18 * information: Portions Copyright [yyyy] [name of copyright owner] |
|
19 * |
|
20 * CDDL HEADER END |
|
21 */ |
|
22 /* |
|
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. |
|
24 * Use is subject to license terms. |
|
25 */ |
|
26 |
|
27 #pragma ident "%Z%%M% %I% %E% SMI" |
|
28 |
|
29 #include <sys/param.h> |
|
30 #include <sys/types.h> |
|
31 #include <sys/systm.h> |
|
32 #include <sys/cred.h> |
|
33 #include <sys/buf.h> |
|
34 #include <sys/vfs.h> |
|
35 #include <sys/vnode.h> |
|
36 #include <sys/uio.h> |
|
37 #include <sys/errno.h> |
|
38 #include <sys/sysmacros.h> |
|
39 #include <sys/statvfs.h> |
|
40 #include <sys/kmem.h> |
|
41 #include <sys/dirent.h> |
|
42 #include <rpc/types.h> |
|
43 #include <rpc/auth.h> |
|
44 #include <rpc/rpcsec_gss.h> |
|
45 #include <rpc/svc.h> |
|
46 #include <sys/strsubr.h> |
|
47 #include <sys/strsun.h> |
|
48 #include <sys/sdt.h> |
|
49 |
|
50 #include <nfs/nfs.h> |
|
51 #include <nfs/export.h> |
|
52 #include <nfs/nfs4.h> |
|
53 |
|
54 |
|
55 /* |
|
56 * RFS4_MINLEN_ENTRY4: XDR-encoded size of smallest possible dirent. |
|
57 * This is used to return NFS4ERR_TOOSMALL when clients specify |
|
58 * maxcount that isn't large enough to hold the smallest possible |
|
59 * XDR encoded dirent. |
|
60 * |
|
61 * sizeof cookie (8 bytes) + |
|
62 * sizeof name_len (4 bytes) + |
|
63 * sizeof smallest (padded) name (4 bytes) + |
|
64 * sizeof bitmap4_len (12 bytes) + NOTE: we always encode len=2 bm4 |
|
65 * sizeof attrlist4_len (4 bytes) + |
|
66 * sizeof next boolean (4 bytes) |
|
67 * |
|
68 * RFS4_MINLEN_RDDIR4: XDR-encoded size of READDIR op reply containing |
|
69 * the smallest possible entry4 (assumes no attrs requested). |
|
70 * sizeof nfsstat4 (4 bytes) + |
|
71 * sizeof verifier4 (8 bytes) + |
|
72 * sizeof entsecond_to_ry4list bool (4 bytes) + |
|
73 * sizeof entry4 (36 bytes) + |
|
74 * sizeof eof bool (4 bytes) |
|
75 * |
|
76 * RFS4_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to |
|
77 * VOP_READDIR. Its value is the size of the maximum possible dirent |
|
78 * for solaris. The DIRENT64_RECLEN macro returns the size of dirent |
|
79 * required for a given name length. MAXNAMELEN is the maximum |
|
80 * filename length allowed in Solaris. The first two DIRENT64_RECLEN() |
|
81 * macros are to allow for . and .. entries -- just a minor tweak to try |
|
82 * and guarantee that buffer we give to VOP_READDIR will be large enough |
|
83 * to hold ., .., and the largest possible solaris dirent64. |
|
84 */ |
|
85 #define RFS4_MINLEN_ENTRY4 36 |
|
86 #define RFS4_MINLEN_RDDIR4 (4 + NFS4_VERIFIER_SIZE + 4 + RFS4_MINLEN_ENTRY4 + 4) |
|
87 #define RFS4_MINLEN_RDDIR_BUF \ |
|
88 (DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2) + DIRENT64_RECLEN(MAXNAMELEN)) |
|
89 |
|
90 |
|
91 #ifdef nextdp |
|
92 #undef nextdp |
|
93 #endif |
|
94 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) |
|
95 |
|
96 verifier4 Readdir4verf = 0x0; |
|
97 |
|
98 static nfs_ftype4 vt_to_nf4[] = { |
|
99 0, NF4REG, NF4DIR, NF4BLK, NF4CHR, NF4LNK, NF4FIFO, 0, 0, NF4SOCK, 0 |
|
100 }; |
|
101 |
|
102 |
|
103 int |
|
104 nfs4_readdir_getvp(vnode_t *dvp, char *d_name, vnode_t **vpp, |
|
105 struct exportinfo **exi, struct svc_req *req, |
|
106 struct compound_state *cs, int expseudo) |
|
107 { |
|
108 int error; |
|
109 int ismntpt; |
|
110 fid_t fid; |
|
111 vnode_t *vp, *pre_tvp; |
|
112 nfsstat4 status; |
|
113 struct exportinfo *newexi, *saveexi; |
|
114 cred_t *scr; |
|
115 |
|
116 *vpp = vp = NULL; |
|
117 |
|
118 if (error = VOP_LOOKUP(dvp, d_name, &vp, NULL, 0, NULL, cs->cr)) |
|
119 return (error); |
|
120 |
|
121 VN_SETPATH(rootdir, dvp, vp, d_name, strlen(d_name)); |
|
122 |
|
123 /* Is this object mounted upon? */ |
|
124 ismntpt = vn_ismntpt(vp); |
|
125 /* |
|
126 * Nothing more to do if object is not a mount point or |
|
127 * a possible LOFS shadow of an LOFS mount (which won't |
|
128 * have v_vfsmountedhere set) |
|
129 */ |
|
130 if (ismntpt == 0 && dvp->v_vfsp == vp->v_vfsp && expseudo == 0) { |
|
131 *vpp = vp; |
|
132 return (0); |
|
133 } |
|
134 |
|
135 if (ismntpt) { |
|
136 /* |
|
137 * Something is mounted here. Traverse and manage the |
|
138 * namespace |
|
139 */ |
|
140 pre_tvp = vp; |
|
141 VN_HOLD(pre_tvp); |
|
142 |
|
143 if ((error = traverse(&vp)) != 0) { |
|
144 VN_RELE(pre_tvp); |
|
145 return (error); |
|
146 } |
|
147 } |
|
148 |
|
149 bzero(&fid, sizeof (fid)); |
|
150 fid.fid_len = MAXFIDSZ; |
|
151 |
|
152 /* |
|
153 * If VOP_FID not supported by underlying fs (mntfs, procfs, |
|
154 * etc.), then return attrs for stub instead of VROOT object. |
|
155 * If it fails for any other reason, then return the error. |
|
156 */ |
|
157 if (error = VOP_FID(vp, &fid)) { |
|
158 if (ismntpt == 0) { |
|
159 VN_RELE(vp); |
|
160 return (error); |
|
161 } |
|
162 |
|
163 if (error != ENOSYS && error != ENOTSUP) { |
|
164 VN_RELE(vp); |
|
165 VN_RELE(pre_tvp); |
|
166 return (error); |
|
167 } |
|
168 /* go back to vnode that is "under" mount */ |
|
169 VN_RELE(vp); |
|
170 *vpp = pre_tvp; |
|
171 return (0); |
|
172 } |
|
173 |
|
174 newexi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); |
|
175 if (newexi == NULL) { |
|
176 if (ismntpt == 0) { |
|
177 *vpp = vp; |
|
178 } else { |
|
179 VN_RELE(vp); |
|
180 *vpp = pre_tvp; |
|
181 } |
|
182 return (0); |
|
183 } |
|
184 |
|
185 if (ismntpt) |
|
186 VN_RELE(pre_tvp); |
|
187 |
|
188 /* Save the exi and present the new one to checkauth4() */ |
|
189 saveexi = cs->exi; |
|
190 cs->exi = newexi; |
|
191 |
|
192 /* Get the right cred like lookup does */ |
|
193 scr = cs->cr; |
|
194 cs->cr = crdup(cs->basecr); |
|
195 |
|
196 status = call_checkauth4(cs, req); |
|
197 |
|
198 crfree(cs->cr); |
|
199 cs->cr = scr; |
|
200 cs->exi = saveexi; |
|
201 |
|
202 /* Reset what call_checkauth4() may have set */ |
|
203 *cs->statusp = NFS4_OK; |
|
204 |
|
205 if (status != NFS4_OK) { |
|
206 VN_RELE(vp); |
|
207 if (status == NFS4ERR_DELAY) |
|
208 status = NFS4ERR_ACCESS; |
|
209 return (status); |
|
210 } |
|
211 *vpp = vp; |
|
212 *exi = newexi; |
|
213 |
|
214 return (0); |
|
215 } |
|
216 |
|
217 /* This is the set of pathconf data for vfs */ |
|
218 typedef struct { |
|
219 uint64_t maxfilesize; |
|
220 uint32_t maxlink; |
|
221 uint32_t maxname; |
|
222 } rfs4_pc_encode_t; |
|
223 |
|
224 |
|
225 static int |
|
226 rfs4_get_pc_encode(vnode_t *vp, rfs4_pc_encode_t *pce, bitmap4 ar, cred_t *cr) |
|
227 { |
|
228 int error; |
|
229 ulong_t pc_val; |
|
230 |
|
231 pce->maxfilesize = 0; |
|
232 pce->maxlink = 0; |
|
233 pce->maxname = 0; |
|
234 |
|
235 if (ar & FATTR4_MAXFILESIZE_MASK) { |
|
236 /* Maximum File Size */ |
|
237 if (error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &pc_val, cr)) |
|
238 return (error); |
|
239 |
|
240 if (pc_val >= (sizeof (uint64_t) * 8)) |
|
241 pce->maxfilesize = UINT64_MAX; |
|
242 else |
|
243 pce->maxfilesize = ((1LL << pc_val) - 1); |
|
244 } |
|
245 |
|
246 if (ar & FATTR4_MAXLINK_MASK) { |
|
247 /* Maximum Link Count */ |
|
248 if (error = VOP_PATHCONF(vp, _PC_LINK_MAX, &pc_val, cr)) |
|
249 return (error); |
|
250 |
|
251 pce->maxlink = pc_val; |
|
252 } |
|
253 |
|
254 if (ar & FATTR4_MAXNAME_MASK) { |
|
255 /* Maximum Name Length */ |
|
256 if (error = VOP_PATHCONF(vp, _PC_NAME_MAX, &pc_val, cr)) |
|
257 return (error); |
|
258 |
|
259 pce->maxname = pc_val; |
|
260 } |
|
261 |
|
262 return (0); |
|
263 } |
|
264 |
|
265 /* This is the set of statvfs data that is ready for encoding */ |
|
266 typedef struct { |
|
267 uint64_t space_avail; |
|
268 uint64_t space_free; |
|
269 uint64_t space_total; |
|
270 u_longlong_t fa; |
|
271 u_longlong_t ff; |
|
272 u_longlong_t ft; |
|
273 } rfs4_sb_encode_t; |
|
274 |
|
275 static int |
|
276 rfs4_get_sb_encode(vfs_t *vfsp, rfs4_sb_encode_t *psbe) |
|
277 { |
|
278 int error; |
|
279 struct statvfs64 sb; |
|
280 |
|
281 /* Grab the per filesystem info */ |
|
282 if (error = VFS_STATVFS(vfsp, &sb)) { |
|
283 return (error); |
|
284 } |
|
285 |
|
286 /* Calculate space available */ |
|
287 if (sb.f_bavail != (fsblkcnt64_t)-1) { |
|
288 psbe->space_avail = |
|
289 (fattr4_space_avail) sb.f_frsize * |
|
290 (fattr4_space_avail) sb.f_bavail; |
|
291 } else { |
|
292 psbe->space_avail = |
|
293 (fattr4_space_avail) sb.f_bavail; |
|
294 } |
|
295 |
|
296 /* Calculate space free */ |
|
297 if (sb.f_bfree != (fsblkcnt64_t)-1) { |
|
298 psbe->space_free = |
|
299 (fattr4_space_free) sb.f_frsize * |
|
300 (fattr4_space_free) sb.f_bfree; |
|
301 } else { |
|
302 psbe->space_free = |
|
303 (fattr4_space_free) sb.f_bfree; |
|
304 } |
|
305 |
|
306 /* Calculate space total */ |
|
307 if (sb.f_blocks != (fsblkcnt64_t)-1) { |
|
308 psbe->space_total = |
|
309 (fattr4_space_total) sb.f_frsize * |
|
310 (fattr4_space_total) sb.f_blocks; |
|
311 } else { |
|
312 psbe->space_total = |
|
313 (fattr4_space_total) sb.f_blocks; |
|
314 } |
|
315 |
|
316 /* For use later on attr encode */ |
|
317 psbe->fa = sb.f_favail; |
|
318 psbe->ff = sb.f_ffree; |
|
319 psbe->ft = sb.f_files; |
|
320 |
|
321 return (0); |
|
322 } |
|
323 |
|
324 /* |
|
325 * Macros to handle if we have don't have enough space for the requested |
|
326 * attributes and this is the first entry and the |
|
327 * requested attributes are more than the minimal useful |
|
328 * set, reset the attributes to the minimal set and |
|
329 * retry the encoding. If the client has asked for both |
|
330 * mounted_on_fileid and fileid, prefer mounted_on_fileid. |
|
331 */ |
|
332 #define MINIMAL_RD_ATTRS \ |
|
333 (FATTR4_MOUNTED_ON_FILEID_MASK| \ |
|
334 FATTR4_FILEID_MASK| \ |
|
335 FATTR4_RDATTR_ERROR_MASK) |
|
336 |
|
337 #define MINIMIZE_ATTR_MASK(m) { \ |
|
338 if ((m) & FATTR4_MOUNTED_ON_FILEID_MASK) \ |
|
339 (m) &= FATTR4_RDATTR_ERROR_MASK|FATTR4_MOUNTED_ON_FILEID_MASK;\ |
|
340 else \ |
|
341 (m) &= FATTR4_RDATTR_ERROR_MASK|FATTR4_FILEID_MASK; \ |
|
342 } |
|
343 |
|
344 #define IS_MIN_ATTR_MASK(m) (((m) & ~MINIMAL_RD_ATTRS) == 0) |
|
345 /* |
|
346 * If readdir only needs to return FILEID, we can take it from the |
|
347 * dirent struct and save doing the lookup. |
|
348 */ |
|
349 /* ARGSUSED */ |
|
350 void |
|
351 rfs4_op_readdir(nfs_argop4 *argop, nfs_resop4 *resop, |
|
352 struct svc_req *req, struct compound_state *cs) |
|
353 { |
|
354 READDIR4args *args = &argop->nfs_argop4_u.opreaddir; |
|
355 READDIR4res *resp = &resop->nfs_resop4_u.opreaddir; |
|
356 struct exportinfo *newexi = NULL; |
|
357 int error; |
|
358 mblk_t *mp; |
|
359 uint_t mpcount; |
|
360 int alloc_err = 0; |
|
361 vnode_t *dvp = cs->vp; |
|
362 vnode_t *vp; |
|
363 vattr_t va; |
|
364 struct dirent64 *dp; |
|
365 rfs4_sb_encode_t dsbe, sbe; |
|
366 int vfs_different; |
|
367 int rddir_data_len, rddir_result_size; |
|
368 caddr_t rddir_data; |
|
369 offset_t rddir_next_offset; |
|
370 int dircount; |
|
371 int no_space; |
|
372 int iseofdir; |
|
373 uint_t eof; |
|
374 struct iovec iov; |
|
375 struct uio uio; |
|
376 int tsize; |
|
377 int check_visible; |
|
378 int expseudo = 0; |
|
379 |
|
380 uint32_t *ptr, *ptr_redzone; |
|
381 uint32_t *beginning_ptr; |
|
382 uint32_t *lastentry_ptr; |
|
383 uint32_t *attrmask_ptr; |
|
384 uint32_t *attr_offset_ptr; |
|
385 uint32_t attr_length; |
|
386 uint32_t rndup; |
|
387 uint32_t namelen; |
|
388 uint32_t rddirattr_error = 0; |
|
389 int nents; |
|
390 bitmap4 ar = args->attr_request & NFS4_SRV_RDDIR_SUPPORTED_ATTRS; |
|
391 bitmap4 ae; |
|
392 rfs4_pc_encode_t dpce, pce; |
|
393 ulong_t pc_val; |
|
394 uint64_t maxread; |
|
395 uint64_t maxwrite; |
|
396 uint_t true = TRUE; |
|
397 uint_t false = FALSE; |
|
398 uid_t lastuid; |
|
399 gid_t lastgid; |
|
400 int lu_set, lg_set; |
|
401 utf8string owner, group; |
|
402 int owner_error, group_error; |
|
403 |
|
404 lu_set = lg_set = 0; |
|
405 owner.utf8string_len = group.utf8string_len = 0; |
|
406 owner.utf8string_val = group.utf8string_val = NULL; |
|
407 |
|
408 resp->mblk = NULL; |
|
409 |
|
410 /* Maximum read and write size */ |
|
411 maxread = maxwrite = rfs4_tsize(req); |
|
412 |
|
413 if (dvp == NULL) { |
|
414 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; |
|
415 return; |
|
416 } |
|
417 |
|
418 /* |
|
419 * If there is an unshared filesystem mounted on this vnode, |
|
420 * do not allow readdir in this directory. |
|
421 */ |
|
422 if (vn_ismntpt(dvp)) { |
|
423 *cs->statusp = resp->status = NFS4ERR_ACCESS; |
|
424 return; |
|
425 } |
|
426 |
|
427 if (dvp->v_type != VDIR) { |
|
428 *cs->statusp = resp->status = NFS4ERR_NOTDIR; |
|
429 return; |
|
430 } |
|
431 |
|
432 if (args->maxcount <= RFS4_MINLEN_RDDIR4) { |
|
433 *cs->statusp = resp->status = NFS4ERR_TOOSMALL; |
|
434 return; |
|
435 } |
|
436 |
|
437 /* |
|
438 * If write-only attrs are requested, then fail the readdir op |
|
439 */ |
|
440 if (args->attr_request & |
|
441 (FATTR4_TIME_MODIFY_SET_MASK | FATTR4_TIME_ACCESS_SET_MASK)) { |
|
442 *cs->statusp = resp->status = NFS4ERR_INVAL; |
|
443 return; |
|
444 } |
|
445 |
|
446 error = VOP_ACCESS(dvp, VREAD, 0, cs->cr); |
|
447 if (error) { |
|
448 *cs->statusp = resp->status = puterrno4(error); |
|
449 return; |
|
450 } |
|
451 |
|
452 if (args->cookieverf != Readdir4verf) { |
|
453 *cs->statusp = resp->status = NFS4ERR_NOT_SAME; |
|
454 return; |
|
455 } |
|
456 |
|
457 /* Is there pseudo-fs work that is needed for this readdir? */ |
|
458 check_visible = PSEUDO(cs->exi) || |
|
459 ! is_exported_sec(cs->nfsflavor, cs->exi) || |
|
460 cs->access & CS_ACCESS_LIMITED; |
|
461 |
|
462 /* Check the requested attributes and only do the work if needed */ |
|
463 |
|
464 if (ar & (FATTR4_MAXFILESIZE_MASK | |
|
465 FATTR4_MAXLINK_MASK | |
|
466 FATTR4_MAXNAME_MASK)) { |
|
467 if (error = rfs4_get_pc_encode(cs->vp, &dpce, ar, cs->cr)) { |
|
468 *cs->statusp = resp->status = puterrno4(error); |
|
469 return; |
|
470 } |
|
471 pce = dpce; |
|
472 } |
|
473 |
|
474 /* If there is statvfs data requested, pick it up once */ |
|
475 if (ar & |
|
476 (FATTR4_FILES_AVAIL_MASK | |
|
477 FATTR4_FILES_FREE_MASK | |
|
478 FATTR4_FILES_TOTAL_MASK | |
|
479 FATTR4_FILES_AVAIL_MASK | |
|
480 FATTR4_FILES_FREE_MASK | |
|
481 FATTR4_FILES_TOTAL_MASK)) { |
|
482 if (error = rfs4_get_sb_encode(dvp->v_vfsp, &dsbe)) { |
|
483 *cs->statusp = resp->status = puterrno4(error); |
|
484 return; |
|
485 } |
|
486 sbe = dsbe; |
|
487 } |
|
488 |
|
489 /* |
|
490 * Max transfer size of the server is the absolute limite. |
|
491 * If the client has decided to max out with something really |
|
492 * tiny, then return toosmall. Otherwise, move forward and |
|
493 * see if a single entry can be encoded. |
|
494 */ |
|
495 tsize = rfs4_tsize(req); |
|
496 if (args->maxcount > tsize) |
|
497 args->maxcount = tsize; |
|
498 else if (args->maxcount < RFS4_MINLEN_RDDIR_BUF) { |
|
499 if (args->maxcount < RFS4_MINLEN_ENTRY4) { |
|
500 *cs->statusp = resp->status = NFS4ERR_TOOSMALL; |
|
501 return; |
|
502 } |
|
503 } |
|
504 |
|
505 /* |
|
506 * How large should the mblk be for outgoing encoding. |
|
507 */ |
|
508 if (args->maxcount < MAXBSIZE) |
|
509 mpcount = MAXBSIZE; |
|
510 else |
|
511 mpcount = args->maxcount; |
|
512 |
|
513 /* |
|
514 * mp will contain the data to be sent out in the readdir reply. |
|
515 * It will be freed after the reply has been sent. |
|
516 * Let's roundup the data to a BYTES_PER_XDR_UNIX multiple, |
|
517 * so that the call to xdrmblk_putmblk() never fails. |
|
518 */ |
|
519 mp = allocb(RNDUP(mpcount), BPRI_MED); |
|
520 |
|
521 if (mp == NULL) { |
|
522 /* |
|
523 * The allocation of the client's requested size has |
|
524 * failed. It may be that the size is too large for |
|
525 * current system utilization; step down to a "common" |
|
526 * size and wait for the allocation to occur. |
|
527 */ |
|
528 if (mpcount > MAXBSIZE) |
|
529 args->maxcount = mpcount = MAXBSIZE; |
|
530 mp = allocb_wait(RNDUP(mpcount), BPRI_MED, |
|
531 STR_NOSIG, &alloc_err); |
|
532 } |
|
533 |
|
534 ASSERT(mp != NULL); |
|
535 ASSERT(alloc_err == 0); |
|
536 |
|
537 resp->mblk = mp; |
|
538 |
|
539 ptr = beginning_ptr = (uint32_t *)mp->b_datap->db_base; |
|
540 |
|
541 /* |
|
542 * The "redzone" at the end of the encoding buffer is used |
|
543 * to deal with xdr encoding length. Instead of checking |
|
544 * each encoding of an attribute value before it is done, |
|
545 * make the assumption that it will fit into the buffer and |
|
546 * check occasionally. |
|
547 * |
|
548 * The largest block of attributes that are encoded without |
|
549 * checking the redzone is 18 * BYTES_PER_XDR_UNIT (72 bytes) |
|
550 * "round" to 128 as the redzone size. |
|
551 */ |
|
552 if (args->maxcount < (mpcount - 128)) |
|
553 ptr_redzone = |
|
554 (uint32_t *)(((char *)ptr) + RNDUP(args->maxcount)); |
|
555 else |
|
556 ptr_redzone = |
|
557 (uint32_t *)((((char *)ptr) + RNDUP(mpcount)) - 128); |
|
558 |
|
559 /* |
|
560 * Set the dircount; this will be used as the size for the |
|
561 * readdir of the underlying filesystem. First make sure |
|
562 * that it is large enough to do a reasonable readdir (client |
|
563 * may have short changed us - it is an advisory number); |
|
564 * then make sure that it isn't too large. |
|
565 * After all of that, if maxcount is "small" then just use |
|
566 * that for the dircount number. |
|
567 */ |
|
568 dircount = (args->dircount < MAXBSIZE) ? MAXBSIZE : args->dircount; |
|
569 dircount = (dircount > tsize) ? tsize : dircount; |
|
570 if (dircount > args->maxcount) |
|
571 dircount = args->maxcount; |
|
572 if (args->maxcount <= MAXBSIZE) { |
|
573 if (args->maxcount < RFS4_MINLEN_RDDIR_BUF) |
|
574 dircount = RFS4_MINLEN_RDDIR_BUF; |
|
575 else |
|
576 dircount = args->maxcount; |
|
577 } |
|
578 |
|
579 /* number of entries fully encoded in outgoing buffer */ |
|
580 nents = 0; |
|
581 |
|
582 /* ENCODE READDIR4res.cookieverf */ |
|
583 IXDR_PUT_HYPER(ptr, Readdir4verf); |
|
584 |
|
585 rddir_data_len = dircount; |
|
586 rddir_data = kmem_alloc(rddir_data_len, KM_NOSLEEP); |
|
587 if (rddir_data == NULL) { |
|
588 /* The allocation failed; downsize and wait for it this time */ |
|
589 if (rddir_data_len > MAXBSIZE) |
|
590 rddir_data_len = dircount = MAXBSIZE; |
|
591 rddir_data = kmem_alloc(rddir_data_len, KM_SLEEP); |
|
592 } |
|
593 |
|
594 rddir_next_offset = (offset_t)args->cookie; |
|
595 |
|
596 readagain: |
|
597 |
|
598 no_space = FALSE; |
|
599 iseofdir = FALSE; |
|
600 |
|
601 vp = NULL; |
|
602 |
|
603 /* Move on to reading the directory contents */ |
|
604 iov.iov_base = rddir_data; |
|
605 iov.iov_len = rddir_data_len; |
|
606 uio.uio_iov = &iov; |
|
607 uio.uio_iovcnt = 1; |
|
608 uio.uio_segflg = UIO_SYSSPACE; |
|
609 uio.uio_extflg = UIO_COPY_CACHED; |
|
610 uio.uio_loffset = rddir_next_offset; |
|
611 uio.uio_resid = rddir_data_len; |
|
612 |
|
613 (void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL); |
|
614 |
|
615 error = VOP_READDIR(dvp, &uio, cs->cr, &iseofdir); |
|
616 |
|
617 VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL); |
|
618 |
|
619 if (error) { |
|
620 kmem_free((caddr_t)rddir_data, rddir_data_len); |
|
621 freeb(resp->mblk); |
|
622 resp->mblk = NULL; |
|
623 resp->data_len = 0; |
|
624 *cs->statusp = resp->status = puterrno4(error); |
|
625 return; |
|
626 } |
|
627 |
|
628 |
|
629 rddir_result_size = rddir_data_len - uio.uio_resid; |
|
630 |
|
631 /* Reading at the end of the directory */ |
|
632 if (iseofdir && (rddir_result_size == 0)) { |
|
633 /* encode the BOOLEAN marking no further entries */ |
|
634 IXDR_PUT_U_INT32(ptr, false); |
|
635 /* encode the BOOLEAN signifying end of directory */ |
|
636 IXDR_PUT_U_INT32(ptr, true); |
|
637 resp->data_len = (char *)ptr - (char *)beginning_ptr; |
|
638 resp->mblk->b_wptr += resp->data_len; |
|
639 kmem_free((caddr_t)rddir_data, rddir_data_len); |
|
640 *cs->statusp = resp->status = NFS4_OK; |
|
641 return; |
|
642 } |
|
643 |
|
644 lastentry_ptr = ptr; |
|
645 no_space = 0; |
|
646 for (dp = (struct dirent64 *)rddir_data; |
|
647 !no_space && rddir_result_size > 0; dp = nextdp(dp)) { |
|
648 |
|
649 /* reset expseudo */ |
|
650 expseudo = 0; |
|
651 |
|
652 if (vp) { |
|
653 VN_RELE(vp); |
|
654 vp = NULL; |
|
655 } |
|
656 |
|
657 if (newexi) |
|
658 newexi = NULL; |
|
659 |
|
660 rddir_result_size -= dp->d_reclen; |
|
661 |
|
662 /* skip "." and ".." entries */ |
|
663 if (dp->d_ino == 0 || NFS_IS_DOTNAME(dp->d_name)) { |
|
664 rddir_next_offset = dp->d_off; |
|
665 continue; |
|
666 } |
|
667 |
|
668 if (check_visible && |
|
669 !nfs_visible_inode(cs->exi, dp->d_ino, &expseudo)) { |
|
670 rddir_next_offset = dp->d_off; |
|
671 continue; |
|
672 } |
|
673 |
|
674 /* |
|
675 * Only if the client requested attributes... |
|
676 * If the VOP_LOOKUP fails ENOENT, then skip this entry |
|
677 * for the readdir response. If there was another error, |
|
678 * then set the rddirattr_error and the error will be |
|
679 * encoded later in the "attributes" section. |
|
680 */ |
|
681 ae = ar; |
|
682 if (ar != 0) { |
|
683 error = nfs4_readdir_getvp(dvp, dp->d_name, |
|
684 &vp, &newexi, req, cs, |
|
685 expseudo); |
|
686 if (error == ENOENT) { |
|
687 rddir_next_offset = dp->d_off; |
|
688 continue; |
|
689 } |
|
690 |
|
691 rddirattr_error = error; |
|
692 |
|
693 /* |
|
694 * The vp obtained from above may be from a |
|
695 * different filesystem mount and the vfs-like |
|
696 * attributes should be obtained from that |
|
697 * different vfs; only do this if appropriate. |
|
698 */ |
|
699 if (vp && |
|
700 (vfs_different = (dvp->v_vfsp != vp->v_vfsp))) { |
|
701 if (ar & (FATTR4_FILES_AVAIL_MASK | |
|
702 FATTR4_FILES_FREE_MASK | |
|
703 FATTR4_FILES_TOTAL_MASK | |
|
704 FATTR4_FILES_AVAIL_MASK | |
|
705 FATTR4_FILES_FREE_MASK | |
|
706 FATTR4_FILES_TOTAL_MASK)) { |
|
707 if (error = |
|
708 rfs4_get_sb_encode(dvp->v_vfsp, &sbe)) { |
|
709 /* Remove attrs from encode */ |
|
710 ae &= ~(FATTR4_FILES_AVAIL_MASK | |
|
711 FATTR4_FILES_FREE_MASK | |
|
712 FATTR4_FILES_TOTAL_MASK | |
|
713 FATTR4_FILES_AVAIL_MASK | |
|
714 FATTR4_FILES_FREE_MASK | |
|
715 FATTR4_FILES_TOTAL_MASK); |
|
716 rddirattr_error = error; |
|
717 } |
|
718 } |
|
719 if (ar & (FATTR4_MAXFILESIZE_MASK | |
|
720 FATTR4_MAXLINK_MASK | |
|
721 FATTR4_MAXNAME_MASK)) { |
|
722 if (error = |
|
723 rfs4_get_pc_encode(cs->vp, |
|
724 &pce, ar, cs->cr)) { |
|
725 ar &= ~(FATTR4_MAXFILESIZE_MASK | |
|
726 FATTR4_MAXLINK_MASK | |
|
727 FATTR4_MAXNAME_MASK); |
|
728 rddirattr_error = error; |
|
729 } |
|
730 } |
|
731 } |
|
732 } |
|
733 |
|
734 reencode_attrs: |
|
735 /* encode the BOOLEAN for the existence of the next entry */ |
|
736 IXDR_PUT_U_INT32(ptr, true); |
|
737 /* encode the COOKIE for the entry */ |
|
738 IXDR_PUT_U_HYPER(ptr, dp->d_off); |
|
739 |
|
740 /* Calculate the dirent name length */ |
|
741 namelen = strlen(dp->d_name); |
|
742 |
|
743 rndup = RNDUP(namelen) / BYTES_PER_XDR_UNIT; |
|
744 |
|
745 /* room for LENGTH + string ? */ |
|
746 if ((ptr + (1 + rndup)) > ptr_redzone) { |
|
747 no_space = TRUE; |
|
748 continue; |
|
749 } |
|
750 |
|
751 /* encode the LENGTH of the name */ |
|
752 IXDR_PUT_U_INT32(ptr, namelen); |
|
753 /* encode the RNDUP FILL first */ |
|
754 ptr[rndup - 1] = 0; |
|
755 /* encode the NAME of the entry */ |
|
756 bcopy(dp->d_name, (char *)ptr, namelen); |
|
757 /* now bump the ptr after... */ |
|
758 ptr += rndup; |
|
759 |
|
760 /* |
|
761 * Keep checking on the dircount to see if we have |
|
762 * reached the limit; from the RFC, dircount is to be |
|
763 * the XDR encoded limit of the cookie plus name. |
|
764 * So the count is the name, XDR_UNIT of length for |
|
765 * that name and 2 * XDR_UNIT bytes of cookie; |
|
766 * However, use the regular DIRENT64 to match most |
|
767 * client's APIs. |
|
768 */ |
|
769 dircount -= DIRENT64_RECLEN(namelen); |
|
770 if (nents != 0 && dircount < 0) { |
|
771 no_space = TRUE; |
|
772 continue; |
|
773 } |
|
774 |
|
775 /* |
|
776 * Attributes requested? |
|
777 * Gather up the attribute info and the previous VOP_LOOKUP() |
|
778 * succeeded; if an error occurs on the VOP_GETATTR() then |
|
779 * return just the error (again if it is requested). |
|
780 * Note that the previous VOP_LOOKUP() could have failed |
|
781 * itself which leaves this code without anything for |
|
782 * a VOP_GETATTR(). |
|
783 * Also note that the readdir_attr_error is left in the |
|
784 * encoding mask if requested and so is the mounted_on_fileid. |
|
785 */ |
|
786 if (ae != 0) { |
|
787 if (!vp) { |
|
788 ae = ar & (FATTR4_RDATTR_ERROR_MASK | |
|
789 FATTR4_MOUNTED_ON_FILEID_MASK); |
|
790 } else { |
|
791 va.va_mask = AT_ALL; |
|
792 rddirattr_error = |
|
793 VOP_GETATTR(vp, &va, 0, cs->cr); |
|
794 if (rddirattr_error) |
|
795 ae = ar & (FATTR4_RDATTR_ERROR_MASK | |
|
796 FATTR4_MOUNTED_ON_FILEID_MASK); |
|
797 } |
|
798 } |
|
799 |
|
800 /* START OF ATTRIBUTE ENCODING */ |
|
801 |
|
802 /* encode the LENGTH of the BITMAP4 array */ |
|
803 IXDR_PUT_U_INT32(ptr, 2); |
|
804 /* encode the BITMAP4 */ |
|
805 attrmask_ptr = ptr; |
|
806 IXDR_PUT_HYPER(ptr, ae); |
|
807 attr_offset_ptr = ptr; |
|
808 /* encode the default LENGTH of the attributes for entry */ |
|
809 IXDR_PUT_U_INT32(ptr, 0); |
|
810 |
|
811 if (ptr > ptr_redzone) { |
|
812 no_space = TRUE; |
|
813 continue; |
|
814 } |
|
815 |
|
816 /* Check if any of the first 32 attributes are being encoded */ |
|
817 if (ae & 0xffffffff00000000) { |
|
818 /* |
|
819 * Redzone check is done at the end of this section. |
|
820 * This particular section will encode a maximum of |
|
821 * 18 * BYTES_PER_XDR_UNIT of data |
|
822 */ |
|
823 if (ae & |
|
824 (FATTR4_SUPPORTED_ATTRS_MASK | |
|
825 FATTR4_TYPE_MASK | |
|
826 FATTR4_FH_EXPIRE_TYPE_MASK | |
|
827 FATTR4_CHANGE_MASK | |
|
828 FATTR4_SIZE_MASK | |
|
829 FATTR4_LINK_SUPPORT_MASK | |
|
830 FATTR4_SYMLINK_SUPPORT_MASK | |
|
831 FATTR4_NAMED_ATTR_MASK | |
|
832 FATTR4_FSID_MASK | |
|
833 FATTR4_UNIQUE_HANDLES_MASK | |
|
834 FATTR4_LEASE_TIME_MASK | |
|
835 FATTR4_RDATTR_ERROR_MASK)) { |
|
836 |
|
837 if (ae & FATTR4_SUPPORTED_ATTRS_MASK) { |
|
838 IXDR_PUT_INT32(ptr, 2); |
|
839 IXDR_PUT_HYPER(ptr, |
|
840 rfs4_supported_attrs); |
|
841 } |
|
842 if (ae & FATTR4_TYPE_MASK) { |
|
843 uint_t ftype = vt_to_nf4[va.va_type]; |
|
844 if (dvp->v_flag & V_XATTRDIR) { |
|
845 if (va.va_type == VDIR) |
|
846 ftype = NF4ATTRDIR; |
|
847 else |
|
848 ftype = NF4NAMEDATTR; |
|
849 } |
|
850 IXDR_PUT_U_INT32(ptr, ftype); |
|
851 } |
|
852 if (ae & FATTR4_FH_EXPIRE_TYPE_MASK) { |
|
853 uint_t expire_type = FH4_PERSISTENT; |
|
854 IXDR_PUT_U_INT32(ptr, expire_type); |
|
855 } |
|
856 if (ae & FATTR4_CHANGE_MASK) { |
|
857 u_longlong_t change; |
|
858 NFS4_SET_FATTR4_CHANGE(change, |
|
859 va.va_ctime); |
|
860 IXDR_PUT_HYPER(ptr, change); |
|
861 } |
|
862 if (ae & FATTR4_SIZE_MASK) { |
|
863 u_longlong_t size = va.va_size; |
|
864 IXDR_PUT_HYPER(ptr, size); |
|
865 } |
|
866 if (ae & FATTR4_LINK_SUPPORT_MASK) { |
|
867 IXDR_PUT_U_INT32(ptr, true); |
|
868 } |
|
869 if (ae & FATTR4_SYMLINK_SUPPORT_MASK) { |
|
870 IXDR_PUT_U_INT32(ptr, true); |
|
871 } |
|
872 if (ae & FATTR4_NAMED_ATTR_MASK) { |
|
873 uint_t isit; |
|
874 pc_val = FALSE; |
|
875 |
|
876 if (!(vp->v_vfsp->vfs_flag & |
|
877 VFS_XATTR)) { |
|
878 isit = FALSE; |
|
879 } else { |
|
880 (void) VOP_PATHCONF(vp, |
|
881 _PC_XATTR_EXISTS, |
|
882 &pc_val, cs->cr); |
|
883 } |
|
884 isit = (pc_val ? TRUE : FALSE); |
|
885 IXDR_PUT_U_INT32(ptr, isit); |
|
886 } |
|
887 if (ae & FATTR4_FSID_MASK) { |
|
888 u_longlong_t major, minor; |
|
889 struct exportinfo *exi; |
|
890 |
|
891 exi = newexi ? newexi : cs->exi; |
|
892 if (exi->exi_volatile_dev) { |
|
893 int *pmaj = (int *)&major; |
|
894 |
|
895 pmaj[0] = exi->exi_fsid.val[0]; |
|
896 pmaj[1] = exi->exi_fsid.val[1]; |
|
897 minor = 0; |
|
898 } else { |
|
899 major = getmajor(va.va_fsid); |
|
900 minor = getminor(va.va_fsid); |
|
901 } |
|
902 IXDR_PUT_HYPER(ptr, major); |
|
903 IXDR_PUT_HYPER(ptr, minor); |
|
904 } |
|
905 if (ae & FATTR4_UNIQUE_HANDLES_MASK) { |
|
906 IXDR_PUT_U_INT32(ptr, false); |
|
907 } |
|
908 if (ae & FATTR4_LEASE_TIME_MASK) { |
|
909 uint_t lt = rfs4_lease_time; |
|
910 IXDR_PUT_U_INT32(ptr, lt); |
|
911 } |
|
912 if (ae & FATTR4_RDATTR_ERROR_MASK) { |
|
913 rddirattr_error = |
|
914 (rddirattr_error == 0 ? |
|
915 0 : puterrno4(rddirattr_error)); |
|
916 IXDR_PUT_U_INT32(ptr, rddirattr_error); |
|
917 } |
|
918 |
|
919 /* Check the redzone boundary */ |
|
920 if (ptr > ptr_redzone) { |
|
921 if (nents || IS_MIN_ATTR_MASK(ar)) { |
|
922 no_space = TRUE; |
|
923 continue; |
|
924 } |
|
925 MINIMIZE_ATTR_MASK(ar); |
|
926 ae = ar; |
|
927 ptr = lastentry_ptr; |
|
928 goto reencode_attrs; |
|
929 } |
|
930 } |
|
931 /* |
|
932 * Redzone check is done at the end of this section. |
|
933 * This particular section will encode a maximum of |
|
934 * 4 * BYTES_PER_XDR_UNIT of data. |
|
935 * NOTE: that if ACLs are supported that the |
|
936 * redzone calculations will need to change. |
|
937 */ |
|
938 if (ae & |
|
939 (FATTR4_ACL_MASK | |
|
940 FATTR4_ACLSUPPORT_MASK | |
|
941 FATTR4_ARCHIVE_MASK | |
|
942 FATTR4_CANSETTIME_MASK | |
|
943 FATTR4_CASE_INSENSITIVE_MASK | |
|
944 FATTR4_CASE_PRESERVING_MASK | |
|
945 FATTR4_CHOWN_RESTRICTED_MASK)) { |
|
946 |
|
947 if (ae & FATTR4_ACL_MASK) { |
|
948 ASSERT(0); |
|
949 } |
|
950 if (ae & FATTR4_ACLSUPPORT_MASK) { |
|
951 ASSERT(0); |
|
952 } |
|
953 if (ae & FATTR4_ARCHIVE_MASK) { |
|
954 ASSERT(0); |
|
955 } |
|
956 if (ae & FATTR4_CANSETTIME_MASK) { |
|
957 IXDR_PUT_U_INT32(ptr, true); |
|
958 } |
|
959 if (ae & FATTR4_CASE_INSENSITIVE_MASK) { |
|
960 IXDR_PUT_U_INT32(ptr, false); |
|
961 } |
|
962 if (ae & FATTR4_CASE_PRESERVING_MASK) { |
|
963 IXDR_PUT_U_INT32(ptr, true); |
|
964 } |
|
965 if (ae & FATTR4_CHOWN_RESTRICTED_MASK) { |
|
966 uint_t isit; |
|
967 pc_val = FALSE; |
|
968 (void) VOP_PATHCONF(vp, |
|
969 _PC_CHOWN_RESTRICTED, |
|
970 &pc_val, cs->cr); |
|
971 isit = (pc_val ? TRUE : FALSE); |
|
972 IXDR_PUT_U_INT32(ptr, isit); |
|
973 } |
|
974 /* Check the redzone boundary */ |
|
975 if (ptr > ptr_redzone) { |
|
976 if (nents || IS_MIN_ATTR_MASK(ar)) { |
|
977 no_space = TRUE; |
|
978 continue; |
|
979 } |
|
980 MINIMIZE_ATTR_MASK(ar); |
|
981 ae = ar; |
|
982 ptr = lastentry_ptr; |
|
983 goto reencode_attrs; |
|
984 } |
|
985 } |
|
986 /* |
|
987 * Redzone check is done before the filehandle |
|
988 * is encoded. |
|
989 */ |
|
990 if (ae & |
|
991 (FATTR4_FILEHANDLE_MASK | |
|
992 FATTR4_FILEID_MASK)) { |
|
993 |
|
994 if (ae & FATTR4_FILEHANDLE_MASK) { |
|
995 struct { |
|
996 uint_t len; |
|
997 char *val; |
|
998 char fh[NFS_FH4_LEN]; |
|
999 } fh; |
|
1000 fh.len = 0; |
|
1001 fh.val = fh.fh; |
|
1002 (void) makefh4((nfs_fh4 *)&fh, vp, |
|
1003 (newexi ? newexi : cs->exi)); |
|
1004 |
|
1005 if ((ptr + |
|
1006 (fh.len / BYTES_PER_XDR_UNIT) + 1) |
|
1007 > ptr_redzone) { |
|
1008 if (nents || |
|
1009 IS_MIN_ATTR_MASK(ar)) { |
|
1010 no_space = TRUE; |
|
1011 continue; |
|
1012 } |
|
1013 MINIMIZE_ATTR_MASK(ar); |
|
1014 ae = ar; |
|
1015 ptr = lastentry_ptr; |
|
1016 goto reencode_attrs; |
|
1017 } |
|
1018 IXDR_PUT_U_INT32(ptr, fh.len); |
|
1019 /* encode the RNDUP FILL first */ |
|
1020 rndup = RNDUP(fh.len) / |
|
1021 BYTES_PER_XDR_UNIT; |
|
1022 ptr[rndup - 1] = 0; |
|
1023 bcopy(fh.fh, ptr, fh.len); |
|
1024 ptr += rndup; |
|
1025 } |
|
1026 if (ae & FATTR4_FILEID_MASK) { |
|
1027 IXDR_PUT_HYPER(ptr, va.va_nodeid); |
|
1028 } |
|
1029 /* Check the redzone boundary */ |
|
1030 if (ptr > ptr_redzone) { |
|
1031 if (nents || IS_MIN_ATTR_MASK(ar)) { |
|
1032 no_space = TRUE; |
|
1033 continue; |
|
1034 } |
|
1035 MINIMIZE_ATTR_MASK(ar); |
|
1036 ae = ar; |
|
1037 ptr = lastentry_ptr; |
|
1038 goto reencode_attrs; |
|
1039 } |
|
1040 } |
|
1041 /* |
|
1042 * Redzone check is done at the end of this section. |
|
1043 * This particular section will encode a maximum of |
|
1044 * 15 * BYTES_PER_XDR_UNIT of data. |
|
1045 */ |
|
1046 if (ae & |
|
1047 (FATTR4_FILES_AVAIL_MASK | |
|
1048 FATTR4_FILES_FREE_MASK | |
|
1049 FATTR4_FILES_TOTAL_MASK | |
|
1050 FATTR4_FS_LOCATIONS_MASK | |
|
1051 FATTR4_HIDDEN_MASK | |
|
1052 FATTR4_HOMOGENEOUS_MASK | |
|
1053 FATTR4_MAXFILESIZE_MASK | |
|
1054 FATTR4_MAXLINK_MASK | |
|
1055 FATTR4_MAXNAME_MASK | |
|
1056 FATTR4_MAXREAD_MASK | |
|
1057 FATTR4_MAXWRITE_MASK)) { |
|
1058 |
|
1059 if (ae & FATTR4_FILES_AVAIL_MASK) { |
|
1060 IXDR_PUT_HYPER(ptr, sbe.fa); |
|
1061 } |
|
1062 if (ae & FATTR4_FILES_FREE_MASK) { |
|
1063 IXDR_PUT_HYPER(ptr, sbe.ff); |
|
1064 } |
|
1065 if (ae & FATTR4_FILES_TOTAL_MASK) { |
|
1066 IXDR_PUT_HYPER(ptr, sbe.ft); |
|
1067 } |
|
1068 if (ae & FATTR4_FS_LOCATIONS_MASK) { |
|
1069 ASSERT(0); |
|
1070 } |
|
1071 if (ae & FATTR4_HIDDEN_MASK) { |
|
1072 ASSERT(0); |
|
1073 } |
|
1074 if (ae & FATTR4_HOMOGENEOUS_MASK) { |
|
1075 IXDR_PUT_U_INT32(ptr, true); |
|
1076 } |
|
1077 if (ae & FATTR4_MAXFILESIZE_MASK) { |
|
1078 IXDR_PUT_HYPER(ptr, pce.maxfilesize); |
|
1079 } |
|
1080 if (ae & FATTR4_MAXLINK_MASK) { |
|
1081 IXDR_PUT_U_INT32(ptr, pce.maxlink); |
|
1082 } |
|
1083 if (ae & FATTR4_MAXNAME_MASK) { |
|
1084 IXDR_PUT_U_INT32(ptr, pce.maxname); |
|
1085 } |
|
1086 if (ae & FATTR4_MAXREAD_MASK) { |
|
1087 IXDR_PUT_HYPER(ptr, maxread); |
|
1088 } |
|
1089 if (ae & FATTR4_MAXWRITE_MASK) { |
|
1090 IXDR_PUT_HYPER(ptr, maxwrite); |
|
1091 } |
|
1092 /* Check the redzone boundary */ |
|
1093 if (ptr > ptr_redzone) { |
|
1094 if (nents || IS_MIN_ATTR_MASK(ar)) { |
|
1095 no_space = TRUE; |
|
1096 continue; |
|
1097 } |
|
1098 MINIMIZE_ATTR_MASK(ar); |
|
1099 ae = ar; |
|
1100 ptr = lastentry_ptr; |
|
1101 goto reencode_attrs; |
|
1102 } |
|
1103 } |
|
1104 } |
|
1105 if (ae & 0x00000000ffffffff) { |
|
1106 /* |
|
1107 * Redzone check is done at the end of this section. |
|
1108 * This particular section will encode a maximum of |
|
1109 * 3 * BYTES_PER_XDR_UNIT of data. |
|
1110 */ |
|
1111 if (ae & |
|
1112 (FATTR4_MIMETYPE_MASK | |
|
1113 FATTR4_MODE_MASK | |
|
1114 FATTR4_NO_TRUNC_MASK | |
|
1115 FATTR4_NUMLINKS_MASK)) { |
|
1116 |
|
1117 if (ae & FATTR4_MIMETYPE_MASK) { |
|
1118 ASSERT(0); |
|
1119 } |
|
1120 if (ae & FATTR4_MODE_MASK) { |
|
1121 uint_t m = va.va_mode; |
|
1122 IXDR_PUT_U_INT32(ptr, m); |
|
1123 } |
|
1124 if (ae & FATTR4_NO_TRUNC_MASK) { |
|
1125 IXDR_PUT_U_INT32(ptr, true); |
|
1126 } |
|
1127 if (ae & FATTR4_NUMLINKS_MASK) { |
|
1128 IXDR_PUT_U_INT32(ptr, va.va_nlink); |
|
1129 } |
|
1130 /* Check the redzone boundary */ |
|
1131 if (ptr > ptr_redzone) { |
|
1132 if (nents || IS_MIN_ATTR_MASK(ar)) { |
|
1133 no_space = TRUE; |
|
1134 continue; |
|
1135 } |
|
1136 MINIMIZE_ATTR_MASK(ar); |
|
1137 ae = ar; |
|
1138 ptr = lastentry_ptr; |
|
1139 goto reencode_attrs; |
|
1140 } |
|
1141 } |
|
1142 /* |
|
1143 * Redzone check is done before the encoding of the |
|
1144 * owner string since the length is indeterminate. |
|
1145 */ |
|
1146 if (ae & FATTR4_OWNER_MASK) { |
|
1147 if (!lu_set) { |
|
1148 owner_error = nfs_idmap_uid_str(va.va_uid, |
|
1149 &owner, TRUE); |
|
1150 if (!owner_error) { |
|
1151 lu_set = TRUE; |
|
1152 lastuid = va.va_uid; |
|
1153 } |
|
1154 } else { |
|
1155 if (va.va_uid != lastuid) { |
|
1156 if (owner.utf8string_len != 0) { |
|
1157 kmem_free(owner.utf8string_val, |
|
1158 owner.utf8string_len); |
|
1159 owner.utf8string_len = 0; |
|
1160 owner.utf8string_val = NULL; |
|
1161 } |
|
1162 owner_error = nfs_idmap_uid_str( |
|
1163 va.va_uid, |
|
1164 &owner, TRUE); |
|
1165 if (!owner_error) { |
|
1166 lastuid = va.va_uid; |
|
1167 } else { |
|
1168 lu_set = FALSE; |
|
1169 } |
|
1170 } |
|
1171 } |
|
1172 if (!owner_error) { |
|
1173 if ((ptr + |
|
1174 (owner.utf8string_len / |
|
1175 BYTES_PER_XDR_UNIT) |
|
1176 + 2) > ptr_redzone) { |
|
1177 if (nents || |
|
1178 IS_MIN_ATTR_MASK(ar)) { |
|
1179 no_space = TRUE; |
|
1180 continue; |
|
1181 } |
|
1182 MINIMIZE_ATTR_MASK(ar); |
|
1183 ae = ar; |
|
1184 ptr = lastentry_ptr; |
|
1185 goto reencode_attrs; |
|
1186 } |
|
1187 /* encode the LENGTH of owner string */ |
|
1188 IXDR_PUT_U_INT32(ptr, |
|
1189 owner.utf8string_len); |
|
1190 /* encode the RNDUP FILL first */ |
|
1191 rndup = RNDUP(owner.utf8string_len) / |
|
1192 BYTES_PER_XDR_UNIT; |
|
1193 ptr[rndup - 1] = 0; |
|
1194 /* encode the OWNER */ |
|
1195 bcopy(owner.utf8string_val, ptr, |
|
1196 owner.utf8string_len); |
|
1197 ptr += rndup; |
|
1198 } |
|
1199 } |
|
1200 /* |
|
1201 * Redzone check is done before the encoding of the |
|
1202 * group string since the length is indeterminate. |
|
1203 */ |
|
1204 if (ae & FATTR4_OWNER_GROUP_MASK) { |
|
1205 if (!lg_set) { |
|
1206 group_error = |
|
1207 nfs_idmap_gid_str(va.va_gid, |
|
1208 &group, TRUE); |
|
1209 if (!group_error) { |
|
1210 lg_set = TRUE; |
|
1211 lastgid = va.va_gid; |
|
1212 } |
|
1213 } else { |
|
1214 if (va.va_gid != lastgid) { |
|
1215 if (group.utf8string_len != 0) { |
|
1216 kmem_free(group.utf8string_val, |
|
1217 group.utf8string_len); |
|
1218 group.utf8string_len = 0; |
|
1219 group.utf8string_val = NULL; |
|
1220 } |
|
1221 group_error = |
|
1222 nfs_idmap_gid_str(va.va_gid, |
|
1223 &group, TRUE); |
|
1224 if (!group_error) |
|
1225 lastgid = va.va_gid; |
|
1226 else |
|
1227 lg_set = FALSE; |
|
1228 } |
|
1229 } |
|
1230 if (!group_error) { |
|
1231 if ((ptr + |
|
1232 (group.utf8string_len / |
|
1233 BYTES_PER_XDR_UNIT) |
|
1234 + 2) > ptr_redzone) { |
|
1235 if (nents || |
|
1236 IS_MIN_ATTR_MASK(ar)) { |
|
1237 no_space = TRUE; |
|
1238 continue; |
|
1239 } |
|
1240 MINIMIZE_ATTR_MASK(ar); |
|
1241 ae = ar; |
|
1242 ptr = lastentry_ptr; |
|
1243 goto reencode_attrs; |
|
1244 } |
|
1245 /* encode the LENGTH of owner string */ |
|
1246 IXDR_PUT_U_INT32(ptr, |
|
1247 group.utf8string_len); |
|
1248 /* encode the RNDUP FILL first */ |
|
1249 rndup = RNDUP(group.utf8string_len) / |
|
1250 BYTES_PER_XDR_UNIT; |
|
1251 ptr[rndup - 1] = 0; |
|
1252 /* encode the OWNER */ |
|
1253 bcopy(group.utf8string_val, ptr, |
|
1254 group.utf8string_len); |
|
1255 ptr += rndup; |
|
1256 } |
|
1257 } |
|
1258 if (ae & |
|
1259 (FATTR4_QUOTA_AVAIL_HARD_MASK | |
|
1260 FATTR4_QUOTA_AVAIL_SOFT_MASK | |
|
1261 FATTR4_QUOTA_USED_MASK)) { |
|
1262 if (ae & FATTR4_QUOTA_AVAIL_HARD_MASK) { |
|
1263 ASSERT(0); |
|
1264 } |
|
1265 if (ae & FATTR4_QUOTA_AVAIL_SOFT_MASK) { |
|
1266 ASSERT(0); |
|
1267 } |
|
1268 if (ae & FATTR4_QUOTA_USED_MASK) { |
|
1269 ASSERT(0); |
|
1270 } |
|
1271 } |
|
1272 /* |
|
1273 * Redzone check is done at the end of this section. |
|
1274 * This particular section will encode a maximum of |
|
1275 * 10 * BYTES_PER_XDR_UNIT of data. |
|
1276 */ |
|
1277 if (ae & |
|
1278 (FATTR4_RAWDEV_MASK | |
|
1279 FATTR4_SPACE_AVAIL_MASK | |
|
1280 FATTR4_SPACE_FREE_MASK | |
|
1281 FATTR4_SPACE_TOTAL_MASK | |
|
1282 FATTR4_SPACE_USED_MASK | |
|
1283 FATTR4_SYSTEM_MASK)) { |
|
1284 |
|
1285 if (ae & FATTR4_RAWDEV_MASK) { |
|
1286 fattr4_rawdev rd; |
|
1287 rd.specdata1 = |
|
1288 (uint32)getmajor(va.va_rdev); |
|
1289 rd.specdata2 = |
|
1290 (uint32)getminor(va.va_rdev); |
|
1291 IXDR_PUT_U_INT32(ptr, rd.specdata1); |
|
1292 IXDR_PUT_U_INT32(ptr, rd.specdata2); |
|
1293 } |
|
1294 if (ae & FATTR4_SPACE_AVAIL_MASK) { |
|
1295 IXDR_PUT_HYPER(ptr, sbe.space_avail); |
|
1296 } |
|
1297 if (ae & FATTR4_SPACE_FREE_MASK) { |
|
1298 IXDR_PUT_HYPER(ptr, sbe.space_free); |
|
1299 } |
|
1300 if (ae & FATTR4_SPACE_TOTAL_MASK) { |
|
1301 IXDR_PUT_HYPER(ptr, sbe.space_total); |
|
1302 } |
|
1303 if (ae & FATTR4_SPACE_USED_MASK) { |
|
1304 u_longlong_t su; |
|
1305 su = (fattr4_space_used) DEV_BSIZE * |
|
1306 (fattr4_space_used) va.va_nblocks; |
|
1307 IXDR_PUT_HYPER(ptr, su); |
|
1308 } |
|
1309 if (ae & FATTR4_SYSTEM_MASK) { |
|
1310 ASSERT(0); |
|
1311 } |
|
1312 /* Check the redzone boundary */ |
|
1313 if (ptr > ptr_redzone) { |
|
1314 if (nents || IS_MIN_ATTR_MASK(ar)) { |
|
1315 no_space = TRUE; |
|
1316 continue; |
|
1317 } |
|
1318 MINIMIZE_ATTR_MASK(ar); |
|
1319 ae = ar; |
|
1320 ptr = lastentry_ptr; |
|
1321 goto reencode_attrs; |
|
1322 } |
|
1323 } |
|
1324 /* |
|
1325 * Redzone check is done at the end of this section. |
|
1326 * This particular section will encode a maximum of |
|
1327 * 14 * BYTES_PER_XDR_UNIT of data. |
|
1328 */ |
|
1329 if (ae & |
|
1330 (FATTR4_TIME_ACCESS_MASK | |
|
1331 FATTR4_TIME_ACCESS_SET_MASK | |
|
1332 FATTR4_TIME_BACKUP_MASK | |
|
1333 FATTR4_TIME_CREATE_MASK | |
|
1334 FATTR4_TIME_DELTA_MASK | |
|
1335 FATTR4_TIME_METADATA_MASK | |
|
1336 FATTR4_TIME_MODIFY_MASK | |
|
1337 FATTR4_TIME_MODIFY_SET_MASK | |
|
1338 FATTR4_MOUNTED_ON_FILEID_MASK)) { |
|
1339 |
|
1340 if (ae & FATTR4_TIME_ACCESS_MASK) { |
|
1341 u_longlong_t sec = |
|
1342 (u_longlong_t)va.va_atime.tv_sec; |
|
1343 uint_t nsec = |
|
1344 (uint_t)va.va_atime.tv_nsec; |
|
1345 IXDR_PUT_HYPER(ptr, sec); |
|
1346 IXDR_PUT_INT32(ptr, nsec); |
|
1347 } |
|
1348 if (ae & FATTR4_TIME_ACCESS_SET_MASK) { |
|
1349 ASSERT(0); |
|
1350 } |
|
1351 if (ae & FATTR4_TIME_BACKUP_MASK) { |
|
1352 ASSERT(0); |
|
1353 } |
|
1354 if (ae & FATTR4_TIME_CREATE_MASK) { |
|
1355 ASSERT(0); |
|
1356 } |
|
1357 if (ae & FATTR4_TIME_DELTA_MASK) { |
|
1358 u_longlong_t sec = 0; |
|
1359 uint_t nsec = 1000; |
|
1360 IXDR_PUT_HYPER(ptr, sec); |
|
1361 IXDR_PUT_INT32(ptr, nsec); |
|
1362 } |
|
1363 if (ae & FATTR4_TIME_METADATA_MASK) { |
|
1364 u_longlong_t sec = |
|
1365 (u_longlong_t)va.va_ctime.tv_sec; |
|
1366 uint_t nsec = |
|
1367 (uint_t)va.va_ctime.tv_nsec; |
|
1368 IXDR_PUT_HYPER(ptr, sec); |
|
1369 IXDR_PUT_INT32(ptr, nsec); |
|
1370 } |
|
1371 if (ae & FATTR4_TIME_MODIFY_MASK) { |
|
1372 u_longlong_t sec = |
|
1373 (u_longlong_t)va.va_mtime.tv_sec; |
|
1374 uint_t nsec = |
|
1375 (uint_t)va.va_mtime.tv_nsec; |
|
1376 IXDR_PUT_HYPER(ptr, sec); |
|
1377 IXDR_PUT_INT32(ptr, nsec); |
|
1378 } |
|
1379 if (ae & FATTR4_TIME_MODIFY_SET_MASK) { |
|
1380 ASSERT(0); |
|
1381 } |
|
1382 if (ae & FATTR4_MOUNTED_ON_FILEID_MASK) { |
|
1383 IXDR_PUT_HYPER(ptr, dp->d_ino); |
|
1384 } |
|
1385 /* Check the redzone boundary */ |
|
1386 if (ptr > ptr_redzone) { |
|
1387 if (nents || IS_MIN_ATTR_MASK(ar)) { |
|
1388 no_space = TRUE; |
|
1389 continue; |
|
1390 } |
|
1391 MINIMIZE_ATTR_MASK(ar); |
|
1392 ae = ar; |
|
1393 ptr = lastentry_ptr; |
|
1394 goto reencode_attrs; |
|
1395 } |
|
1396 } |
|
1397 } |
|
1398 |
|
1399 /* Reset to directory's vfs info when encoding complete */ |
|
1400 if (vfs_different) { |
|
1401 dsbe = sbe; |
|
1402 dpce = pce; |
|
1403 vfs_different = 0; |
|
1404 } |
|
1405 |
|
1406 /* "go back" and encode the attributes' length */ |
|
1407 attr_length = |
|
1408 (char *)ptr - |
|
1409 (char *)attr_offset_ptr - |
|
1410 BYTES_PER_XDR_UNIT; |
|
1411 IXDR_PUT_U_INT32(attr_offset_ptr, attr_length); |
|
1412 |
|
1413 /* |
|
1414 * If there was trouble obtaining a mapping for either |
|
1415 * the owner or group attributes, then remove them from |
|
1416 * bitmap4 for this entry and reset the bitmap value |
|
1417 * in the data stream. |
|
1418 */ |
|
1419 if (owner_error || group_error) { |
|
1420 if (owner_error) |
|
1421 ae &= ~FATTR4_OWNER_MASK; |
|
1422 if (group_error) |
|
1423 ae &= ~FATTR4_OWNER_GROUP_MASK; |
|
1424 IXDR_PUT_HYPER(attrmask_ptr, ae); |
|
1425 } |
|
1426 |
|
1427 /* END OF ATTRIBUTE ENCODING */ |
|
1428 |
|
1429 lastentry_ptr = ptr; |
|
1430 nents++; |
|
1431 rddir_next_offset = dp->d_off; |
|
1432 } |
|
1433 |
|
1434 /* |
|
1435 * Check for the case that another VOP_READDIR() has to be done. |
|
1436 * - no space encoding error |
|
1437 * - no entry successfully encoded |
|
1438 * - still more directory to read |
|
1439 */ |
|
1440 if (!no_space && nents == 0 && !iseofdir) |
|
1441 goto readagain; |
|
1442 |
|
1443 *cs->statusp = resp->status = NFS4_OK; |
|
1444 |
|
1445 /* |
|
1446 * If no_space is set then we terminated prematurely, |
|
1447 * rewind to the last entry and this can never be EOF. |
|
1448 */ |
|
1449 if (no_space) { |
|
1450 ptr = lastentry_ptr; |
|
1451 eof = FALSE; /* ended encoded prematurely */ |
|
1452 } else { |
|
1453 eof = (iseofdir ? TRUE : FALSE); |
|
1454 } |
|
1455 |
|
1456 /* |
|
1457 * If we have entries, always return them, otherwise only error |
|
1458 * if we ran out of space. |
|
1459 */ |
|
1460 if (nents || !no_space) { |
|
1461 ASSERT(ptr != NULL); |
|
1462 /* encode the BOOLEAN marking no further entries */ |
|
1463 IXDR_PUT_U_INT32(ptr, false); |
|
1464 /* encode the BOOLEAN signifying end of directory */ |
|
1465 IXDR_PUT_U_INT32(ptr, eof); |
|
1466 |
|
1467 resp->data_len = (char *)ptr - (char *)beginning_ptr; |
|
1468 resp->mblk->b_wptr += resp->data_len; |
|
1469 } else { |
|
1470 freeb(mp); |
|
1471 resp->mblk = NULL; |
|
1472 resp->data_len = 0; |
|
1473 *cs->statusp = resp->status = NFS4ERR_TOOSMALL; |
|
1474 } |
|
1475 |
|
1476 kmem_free((caddr_t)rddir_data, rddir_data_len); |
|
1477 if (vp) |
|
1478 VN_RELE(vp); |
|
1479 if (owner.utf8string_len != 0) |
|
1480 kmem_free(owner.utf8string_val, owner.utf8string_len); |
|
1481 if (group.utf8string_len != 0) |
|
1482 kmem_free(group.utf8string_val, group.utf8string_len); |
|
1483 } |