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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/param.h>
26 #include <sys/isa_defs.h>
27 #include <sys/types.h>
28 #include <sys/sysmacros.h>
29 #include <sys/cred.h>
30 #include <sys/systm.h>
31 #include <sys/errno.h>
32 #include <sys/fcntl.h>
33 #include <sys/pathname.h>
34 #include <sys/stat.h>
35 #include <sys/vfs.h>
36 #include <sys/acl.h>
37 #include <sys/file.h>
38 #include <sys/sunddi.h>
39 #include <sys/debug.h>
40 #include <sys/cmn_err.h>
41 #include <sys/vnode.h>
42 #include <sys/mode.h>
43 #include <sys/nvpair.h>
44 #include <sys/attr.h>
45 #include <sys/gfs.h>
46 #include <sys/mutex.h>
47 #include <fs/fs_subr.h>
48 #include <sys/kidmap.h>
49
50 typedef struct {
51 gfs_file_t xattr_gfs_private;
52 xattr_view_t xattr_view;
53 } xattr_file_t;
54
55 typedef struct {
56 gfs_dir_t xattr_gfs_private;
57 vnode_t *xattr_realvp;
58 } xattr_dir_t;
59
60 /* ARGSUSED */
61 static int
62 xattr_file_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
63 {
64 xattr_file_t *np = (*vpp)->v_data;
65
66 if ((np->xattr_view == XATTR_VIEW_READONLY) && (flags & FWRITE))
67 return (EACCES);
68
69 return (0);
70 }
71
72 /* ARGSUSED */
73 static int
74 xattr_file_access(vnode_t *vp, int mode, int flags, cred_t *cr,
75 caller_context_t *ct)
76 {
77 xattr_file_t *np = vp->v_data;
78
79 if ((np->xattr_view == XATTR_VIEW_READONLY) && (mode & VWRITE))
80 return (EACCES);
81
82 return (0);
83 }
84
85 /* ARGSUSED */
86 static int
87 xattr_file_close(vnode_t *vp, int flags, int count, offset_t off,
88 cred_t *cr, caller_context_t *ct)
89 {
90 cleanlocks(vp, ddi_get_pid(), 0);
91 cleanshares(vp, ddi_get_pid());
92 return (0);
93 }
94
95 static int
96 xattr_common_fid(vnode_t *vp, fid_t *fidp, caller_context_t *ct)
97 {
98 xattr_fid_t *xfidp;
99 vnode_t *pvp, *savevp;
100 int error;
101 uint16_t orig_len;
102
103 if (fidp->fid_len < XATTR_FIDSZ) {
104 fidp->fid_len = XATTR_FIDSZ;
105 return (ENOSPC);
106 }
107
108 savevp = pvp = gfs_file_parent(vp);
109 mutex_enter(&savevp->v_lock);
110 if (pvp->v_flag & V_XATTRDIR) {
111 pvp = gfs_file_parent(pvp);
112 }
113 mutex_exit(&savevp->v_lock);
114
115 xfidp = (xattr_fid_t *)fidp;
116 orig_len = fidp->fid_len;
117 fidp->fid_len = sizeof (xfidp->parent_fid);
118
119 error = VOP_FID(pvp, fidp, ct);
120 if (error) {
121 fidp->fid_len = orig_len;
122 return (error);
123 }
124
125 xfidp->parent_len = fidp->fid_len;
126 fidp->fid_len = XATTR_FIDSZ;
127 xfidp->dir_offset = gfs_file_inode(vp);
128
129 return (0);
130 }
131
132 /* ARGSUSED */
133 static int
134 xattr_fill_nvlist(vnode_t *vp, xattr_view_t xattr_view, nvlist_t *nvlp,
135 cred_t *cr, caller_context_t *ct)
136 {
137 int error;
138 f_attr_t attr;
139 uint64_t fsid;
140 xvattr_t xvattr;
141 xoptattr_t *xoap; /* Pointer to optional attributes */
142 vnode_t *ppvp;
143 const char *domain;
144 uint32_t rid;
145
146 xva_init(&xvattr);
147
148 if ((xoap = xva_getxoptattr(&xvattr)) == NULL)
149 return (EINVAL);
150
151 /*
152 * For detecting ephemeral uid/gid
153 */
154 xvattr.xva_vattr.va_mask |= (AT_UID|AT_GID);
155
156 /*
157 * We need to access the real fs object.
158 * vp points to a GFS file; ppvp points to the real object.
159 */
160 ppvp = gfs_file_parent(gfs_file_parent(vp));
161
162 /*
163 * Iterate through the attrs associated with this view
164 */
165
166 for (attr = 0; attr < F_ATTR_ALL; attr++) {
167 if (xattr_view != attr_to_xattr_view(attr)) {
168 continue;
169 }
170
171 switch (attr) {
172 case F_SYSTEM:
173 XVA_SET_REQ(&xvattr, XAT_SYSTEM);
174 break;
175 case F_READONLY:
176 XVA_SET_REQ(&xvattr, XAT_READONLY);
177 break;
178 case F_HIDDEN:
179 XVA_SET_REQ(&xvattr, XAT_HIDDEN);
180 break;
181 case F_ARCHIVE:
182 XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
183 break;
184 case F_IMMUTABLE:
185 XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
186 break;
187 case F_APPENDONLY:
188 XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
189 break;
190 case F_NOUNLINK:
191 XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
192 break;
193 case F_OPAQUE:
194 XVA_SET_REQ(&xvattr, XAT_OPAQUE);
195 break;
196 case F_NODUMP:
197 XVA_SET_REQ(&xvattr, XAT_NODUMP);
198 break;
199 case F_AV_QUARANTINED:
200 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
201 break;
202 case F_AV_MODIFIED:
203 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
204 break;
205 case F_AV_SCANSTAMP:
206 if (ppvp->v_type == VREG)
207 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
208 break;
209 case F_CRTIME:
210 XVA_SET_REQ(&xvattr, XAT_CREATETIME);
211 break;
212 case F_FSID:
213 fsid = (((uint64_t)vp->v_vfsp->vfs_fsid.val[0] << 32) |
214 (uint64_t)(vp->v_vfsp->vfs_fsid.val[1] &
215 0xffffffff));
216 VERIFY(nvlist_add_uint64(nvlp, attr_to_name(attr),
217 fsid) == 0);
218 break;
219 case F_REPARSE:
220 XVA_SET_REQ(&xvattr, XAT_REPARSE);
221 break;
222 case F_GEN:
223 XVA_SET_REQ(&xvattr, XAT_GEN);
224 break;
225 case F_OFFLINE:
226 XVA_SET_REQ(&xvattr, XAT_OFFLINE);
227 break;
228 case F_SPARSE:
229 XVA_SET_REQ(&xvattr, XAT_SPARSE);
230 break;
231 default:
232 break;
233 }
234 }
235
236 error = VOP_GETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
237 if (error)
238 return (error);
239
240 /*
241 * Process all the optional attributes together here. Notice that
242 * xoap was set when the optional attribute bits were set above.
243 */
244 if ((xvattr.xva_vattr.va_mask & AT_XVATTR) && xoap) {
245 if (XVA_ISSET_RTN(&xvattr, XAT_READONLY)) {
246 VERIFY(nvlist_add_boolean_value(nvlp,
247 attr_to_name(F_READONLY),
248 xoap->xoa_readonly) == 0);
249 }
250 if (XVA_ISSET_RTN(&xvattr, XAT_HIDDEN)) {
251 VERIFY(nvlist_add_boolean_value(nvlp,
252 attr_to_name(F_HIDDEN),
253 xoap->xoa_hidden) == 0);
254 }
255 if (XVA_ISSET_RTN(&xvattr, XAT_SYSTEM)) {
256 VERIFY(nvlist_add_boolean_value(nvlp,
257 attr_to_name(F_SYSTEM),
258 xoap->xoa_system) == 0);
259 }
260 if (XVA_ISSET_RTN(&xvattr, XAT_ARCHIVE)) {
261 VERIFY(nvlist_add_boolean_value(nvlp,
262 attr_to_name(F_ARCHIVE),
263 xoap->xoa_archive) == 0);
264 }
265 if (XVA_ISSET_RTN(&xvattr, XAT_IMMUTABLE)) {
266 VERIFY(nvlist_add_boolean_value(nvlp,
267 attr_to_name(F_IMMUTABLE),
268 xoap->xoa_immutable) == 0);
269 }
270 if (XVA_ISSET_RTN(&xvattr, XAT_NOUNLINK)) {
271 VERIFY(nvlist_add_boolean_value(nvlp,
272 attr_to_name(F_NOUNLINK),
273 xoap->xoa_nounlink) == 0);
274 }
275 if (XVA_ISSET_RTN(&xvattr, XAT_APPENDONLY)) {
276 VERIFY(nvlist_add_boolean_value(nvlp,
277 attr_to_name(F_APPENDONLY),
278 xoap->xoa_appendonly) == 0);
279 }
280 if (XVA_ISSET_RTN(&xvattr, XAT_NODUMP)) {
281 VERIFY(nvlist_add_boolean_value(nvlp,
282 attr_to_name(F_NODUMP),
283 xoap->xoa_nodump) == 0);
284 }
285 if (XVA_ISSET_RTN(&xvattr, XAT_OPAQUE)) {
286 VERIFY(nvlist_add_boolean_value(nvlp,
287 attr_to_name(F_OPAQUE),
288 xoap->xoa_opaque) == 0);
289 }
290 if (XVA_ISSET_RTN(&xvattr, XAT_AV_QUARANTINED)) {
291 VERIFY(nvlist_add_boolean_value(nvlp,
292 attr_to_name(F_AV_QUARANTINED),
293 xoap->xoa_av_quarantined) == 0);
294 }
295 if (XVA_ISSET_RTN(&xvattr, XAT_AV_MODIFIED)) {
296 VERIFY(nvlist_add_boolean_value(nvlp,
297 attr_to_name(F_AV_MODIFIED),
298 xoap->xoa_av_modified) == 0);
299 }
300 if (XVA_ISSET_RTN(&xvattr, XAT_AV_SCANSTAMP)) {
301 VERIFY(nvlist_add_uint8_array(nvlp,
302 attr_to_name(F_AV_SCANSTAMP),
303 xoap->xoa_av_scanstamp,
304 sizeof (xoap->xoa_av_scanstamp)) == 0);
305 }
306 if (XVA_ISSET_RTN(&xvattr, XAT_CREATETIME)) {
307 VERIFY(nvlist_add_uint64_array(nvlp,
308 attr_to_name(F_CRTIME),
309 (uint64_t *)&(xoap->xoa_createtime),
310 sizeof (xoap->xoa_createtime) /
311 sizeof (uint64_t)) == 0);
312 }
313 if (XVA_ISSET_RTN(&xvattr, XAT_REPARSE)) {
314 VERIFY(nvlist_add_boolean_value(nvlp,
315 attr_to_name(F_REPARSE),
316 xoap->xoa_reparse) == 0);
317 }
318 if (XVA_ISSET_RTN(&xvattr, XAT_GEN)) {
319 VERIFY(nvlist_add_uint64(nvlp,
320 attr_to_name(F_GEN),
321 xoap->xoa_generation) == 0);
322 }
323 if (XVA_ISSET_RTN(&xvattr, XAT_OFFLINE)) {
324 VERIFY(nvlist_add_boolean_value(nvlp,
325 attr_to_name(F_OFFLINE),
326 xoap->xoa_offline) == 0);
327 }
328 if (XVA_ISSET_RTN(&xvattr, XAT_SPARSE)) {
329 VERIFY(nvlist_add_boolean_value(nvlp,
330 attr_to_name(F_SPARSE),
331 xoap->xoa_sparse) == 0);
332 }
333 }
334 /*
335 * Check for optional ownersid/groupsid
336 */
337
338 if (xvattr.xva_vattr.va_uid > MAXUID) {
339 nvlist_t *nvl_sid;
340
341 if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP))
342 return (ENOMEM);
343
344 if (kidmap_getsidbyuid(crgetzone(cr), xvattr.xva_vattr.va_uid,
345 &domain, &rid) == 0) {
346 VERIFY(nvlist_add_string(nvl_sid,
347 SID_DOMAIN, domain) == 0);
348 VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0);
349 VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_OWNERSID),
350 nvl_sid) == 0);
351 }
352 nvlist_free(nvl_sid);
353 }
354 if (xvattr.xva_vattr.va_gid > MAXUID) {
355 nvlist_t *nvl_sid;
356
357 if (nvlist_alloc(&nvl_sid, NV_UNIQUE_NAME, KM_SLEEP))
358 return (ENOMEM);
359
360 if (kidmap_getsidbygid(crgetzone(cr), xvattr.xva_vattr.va_gid,
361 &domain, &rid) == 0) {
362 VERIFY(nvlist_add_string(nvl_sid,
363 SID_DOMAIN, domain) == 0);
364 VERIFY(nvlist_add_uint32(nvl_sid, SID_RID, rid) == 0);
365 VERIFY(nvlist_add_nvlist(nvlp, attr_to_name(F_GROUPSID),
366 nvl_sid) == 0);
367 }
368 nvlist_free(nvl_sid);
369 }
370
371 return (0);
372 }
373
374 /*
375 * The size of a sysattr file is the size of the nvlist that will be
376 * returned by xattr_file_read(). A call to xattr_file_write() could
377 * change the size of that nvlist. That size is not stored persistently
378 * so xattr_fill_nvlist() calls VOP_GETATTR so that it can be calculated.
379 */
380 static int
381 xattr_file_size(vnode_t *vp, xattr_view_t xattr_view, size_t *size,
382 cred_t *cr, caller_context_t *ct)
383 {
384 nvlist_t *nvl;
385
386 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) {
387 return (ENOMEM);
388 }
389
390 if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) {
391 nvlist_free(nvl);
392 return (EFAULT);
393 }
394
395 VERIFY(nvlist_size(nvl, size, NV_ENCODE_XDR) == 0);
396 nvlist_free(nvl);
397 return (0);
398 }
399
400 /* ARGSUSED */
401 static int
402 xattr_file_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
403 caller_context_t *ct)
404 {
405 xattr_file_t *np = vp->v_data;
406 timestruc_t now;
407 size_t size;
408 int error;
409 vnode_t *pvp;
410 vattr_t pvattr;
411
412 vap->va_type = VREG;
413 vap->va_mode = MAKEIMODE(vap->va_type,
414 (np->xattr_view == XATTR_VIEW_READONLY ? 0444 : 0644));
415 vap->va_nodeid = gfs_file_inode(vp);
416 vap->va_nlink = 1;
417 pvp = gfs_file_parent(vp);
418 (void) memset(&pvattr, 0, sizeof (pvattr));
419 pvattr.va_mask = AT_CTIME|AT_MTIME;
420 error = VOP_GETATTR(pvp, &pvattr, flags, cr, ct);
421 if (error) {
422 return (error);
423 }
424 vap->va_ctime = pvattr.va_ctime;
425 vap->va_mtime = pvattr.va_mtime;
426 gethrestime(&now);
427 vap->va_atime = now;
428 vap->va_uid = 0;
429 vap->va_gid = 0;
430 vap->va_rdev = 0;
431 vap->va_blksize = DEV_BSIZE;
432 vap->va_seq = 0;
433 vap->va_fsid = vp->v_vfsp->vfs_dev;
434 error = xattr_file_size(vp, np->xattr_view, &size, cr, ct);
435 vap->va_size = size;
436 vap->va_nblocks = howmany(vap->va_size, vap->va_blksize);
437 return (error);
438 }
439
440 /* ARGSUSED */
441 static int
442 xattr_file_read(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
443 caller_context_t *ct)
444 {
445 xattr_file_t *np = vp->v_data;
446 xattr_view_t xattr_view = np->xattr_view;
447 char *buf;
448 size_t filesize;
449 nvlist_t *nvl;
450 int error;
451
452 /*
453 * Validate file offset and fasttrack empty reads
454 */
455 if (uiop->uio_loffset < (offset_t)0)
456 return (EINVAL);
457
458 if (uiop->uio_resid == 0)
459 return (0);
460
461 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP))
462 return (ENOMEM);
463
464 if (xattr_fill_nvlist(vp, xattr_view, nvl, cr, ct)) {
465 nvlist_free(nvl);
466 return (EFAULT);
467 }
468
469 VERIFY(nvlist_size(nvl, &filesize, NV_ENCODE_XDR) == 0);
470
471 if (uiop->uio_loffset >= filesize) {
472 nvlist_free(nvl);
473 return (0);
474 }
475
476 buf = kmem_alloc(filesize, KM_SLEEP);
477 VERIFY(nvlist_pack(nvl, &buf, &filesize, NV_ENCODE_XDR,
478 KM_SLEEP) == 0);
479
480 error = uiomove((caddr_t)buf, filesize, UIO_READ, uiop);
481 kmem_free(buf, filesize);
482 nvlist_free(nvl);
483 return (error);
484 }
485
486 /* ARGSUSED */
487 static int
488 xattr_file_write(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr,
489 caller_context_t *ct)
490 {
491 int error = 0;
492 char *buf;
493 char *domain;
494 uint32_t rid;
495 ssize_t size = uiop->uio_resid;
496 nvlist_t *nvp;
497 nvpair_t *pair = NULL;
498 vnode_t *ppvp;
499 xvattr_t xvattr;
500 xoptattr_t *xoap = NULL; /* Pointer to optional attributes */
501
502 if (vfs_has_feature(vp->v_vfsp, VFSFT_XVATTR) == 0)
503 return (EINVAL);
504
505 /*
506 * Validate file offset and size.
507 */
508 if (uiop->uio_loffset < (offset_t)0)
509 return (EINVAL);
510
511 if (size == 0)
512 return (EINVAL);
513
514 xva_init(&xvattr);
515
516 if ((xoap = xva_getxoptattr(&xvattr)) == NULL) {
517 return (EINVAL);
518 }
519
520 /*
521 * Copy and unpack the nvlist
522 */
523 buf = kmem_alloc(size, KM_SLEEP);
524 if (uiomove((caddr_t)buf, size, UIO_WRITE, uiop)) {
525 return (EFAULT);
526 }
527
528 if (nvlist_unpack(buf, size, &nvp, KM_SLEEP) != 0) {
529 kmem_free(buf, size);
530 uiop->uio_resid = size;
531 return (EINVAL);
532 }
533 kmem_free(buf, size);
534
535 /*
536 * Fasttrack empty writes (nvlist with no nvpairs)
537 */
538 if (nvlist_next_nvpair(nvp, NULL) == 0)
539 return (0);
540
541 ppvp = gfs_file_parent(gfs_file_parent(vp));
542
543 while (pair = nvlist_next_nvpair(nvp, pair)) {
544 data_type_t type;
545 f_attr_t attr;
546 boolean_t value;
547 uint64_t *time, *times;
548 uint_t elem, nelems;
549 nvlist_t *nvp_sid;
550 uint8_t *scanstamp;
551
552 /*
553 * Validate the name and type of each attribute.
554 * Log any unknown names and continue. This will
555 * help if additional attributes are added later.
556 */
557 type = nvpair_type(pair);
558 if ((attr = name_to_attr(nvpair_name(pair))) == F_ATTR_INVAL) {
559 cmn_err(CE_WARN, "Unknown attribute %s",
560 nvpair_name(pair));
561 continue;
562 }
563
564 /*
565 * Verify nvlist type matches required type and view is OK
566 */
567
568 if (type != attr_to_data_type(attr) ||
569 (attr_to_xattr_view(attr) == XATTR_VIEW_READONLY)) {
570 nvlist_free(nvp);
571 return (EINVAL);
572 }
573
574 /*
575 * For OWNERSID/GROUPSID make sure the target
576 * file system support ephemeral ID's
577 */
578 if ((attr == F_OWNERSID || attr == F_GROUPSID) &&
579 (!(vp->v_vfsp->vfs_flag & VFS_XID))) {
580 nvlist_free(nvp);
581 return (EINVAL);
582 }
583
584 /*
585 * Retrieve data from nvpair
586 */
587 switch (type) {
588 case DATA_TYPE_BOOLEAN_VALUE:
589 if (nvpair_value_boolean_value(pair, &value)) {
590 nvlist_free(nvp);
591 return (EINVAL);
592 }
593 break;
594 case DATA_TYPE_UINT64_ARRAY:
595 if (nvpair_value_uint64_array(pair, ×, &nelems)) {
596 nvlist_free(nvp);
597 return (EINVAL);
598 }
599 break;
600 case DATA_TYPE_NVLIST:
601 if (nvpair_value_nvlist(pair, &nvp_sid)) {
602 nvlist_free(nvp);
603 return (EINVAL);
604 }
605 break;
606 case DATA_TYPE_UINT8_ARRAY:
607 if (nvpair_value_uint8_array(pair,
608 &scanstamp, &nelems)) {
609 nvlist_free(nvp);
610 return (EINVAL);
611 }
612 break;
613 default:
614 nvlist_free(nvp);
615 return (EINVAL);
616 }
617
618 switch (attr) {
619 /*
620 * If we have several similar optional attributes to
621 * process then we should do it all together here so that
622 * xoap and the requested bitmap can be set in one place.
623 */
624 case F_READONLY:
625 XVA_SET_REQ(&xvattr, XAT_READONLY);
626 xoap->xoa_readonly = value;
627 break;
628 case F_HIDDEN:
629 XVA_SET_REQ(&xvattr, XAT_HIDDEN);
630 xoap->xoa_hidden = value;
631 break;
632 case F_SYSTEM:
633 XVA_SET_REQ(&xvattr, XAT_SYSTEM);
634 xoap->xoa_system = value;
635 break;
636 case F_ARCHIVE:
637 XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
638 xoap->xoa_archive = value;
639 break;
640 case F_IMMUTABLE:
641 XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
642 xoap->xoa_immutable = value;
643 break;
644 case F_NOUNLINK:
645 XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
646 xoap->xoa_nounlink = value;
647 break;
648 case F_APPENDONLY:
649 XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
650 xoap->xoa_appendonly = value;
651 break;
652 case F_NODUMP:
653 XVA_SET_REQ(&xvattr, XAT_NODUMP);
654 xoap->xoa_nodump = value;
655 break;
656 case F_AV_QUARANTINED:
657 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
658 xoap->xoa_av_quarantined = value;
659 break;
660 case F_AV_MODIFIED:
661 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
662 xoap->xoa_av_modified = value;
663 break;
664 case F_CRTIME:
665 XVA_SET_REQ(&xvattr, XAT_CREATETIME);
666 time = (uint64_t *)&(xoap->xoa_createtime);
667 for (elem = 0; elem < nelems; elem++)
668 *time++ = times[elem];
669 break;
670 case F_OWNERSID:
671 case F_GROUPSID:
672 if (nvlist_lookup_string(nvp_sid, SID_DOMAIN,
673 &domain) || nvlist_lookup_uint32(nvp_sid, SID_RID,
674 &rid)) {
675 nvlist_free(nvp);
676 return (EINVAL);
677 }
678
679 /*
680 * Now map domain+rid to ephemeral id's
681 *
682 * If mapping fails, then the uid/gid will
683 * be set to UID_NOBODY by Winchester.
684 */
685
686 if (attr == F_OWNERSID) {
687 (void) kidmap_getuidbysid(crgetzone(cr), domain,
688 rid, &xvattr.xva_vattr.va_uid);
689 xvattr.xva_vattr.va_mask |= AT_UID;
690 } else {
691 (void) kidmap_getgidbysid(crgetzone(cr), domain,
692 rid, &xvattr.xva_vattr.va_gid);
693 xvattr.xva_vattr.va_mask |= AT_GID;
694 }
695 break;
696 case F_AV_SCANSTAMP:
697 if (ppvp->v_type == VREG) {
698 XVA_SET_REQ(&xvattr, XAT_AV_SCANSTAMP);
699 (void) memcpy(xoap->xoa_av_scanstamp,
700 scanstamp, nelems);
701 } else {
702 nvlist_free(nvp);
703 return (EINVAL);
704 }
705 break;
706 case F_REPARSE:
707 XVA_SET_REQ(&xvattr, XAT_REPARSE);
708 xoap->xoa_reparse = value;
709 break;
710 case F_OFFLINE:
711 XVA_SET_REQ(&xvattr, XAT_OFFLINE);
712 xoap->xoa_offline = value;
713 break;
714 case F_SPARSE:
715 XVA_SET_REQ(&xvattr, XAT_SPARSE);
716 xoap->xoa_sparse = value;
717 break;
718 default:
719 break;
720 }
721 }
722
723 ppvp = gfs_file_parent(gfs_file_parent(vp));
724 error = VOP_SETATTR(ppvp, &xvattr.xva_vattr, 0, cr, ct);
725 if (error)
726 uiop->uio_resid = size;
727
728 nvlist_free(nvp);
729 return (error);
730 }
731
732 static int
733 xattr_file_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
734 caller_context_t *ct)
735 {
736 switch (cmd) {
737 case _PC_XATTR_EXISTS:
738 case _PC_SATTR_ENABLED:
739 case _PC_SATTR_EXISTS:
740 *valp = 0;
741 return (0);
742 default:
743 return (fs_pathconf(vp, cmd, valp, cr, ct));
744 }
745 }
746
747 vnodeops_t *xattr_file_ops;
748
749 static const fs_operation_def_t xattr_file_tops[] = {
750 { VOPNAME_OPEN, { .vop_open = xattr_file_open } },
751 { VOPNAME_CLOSE, { .vop_close = xattr_file_close } },
752 { VOPNAME_READ, { .vop_read = xattr_file_read } },
753 { VOPNAME_WRITE, { .vop_write = xattr_file_write } },
754 { VOPNAME_IOCTL, { .error = fs_ioctl } },
755 { VOPNAME_GETATTR, { .vop_getattr = xattr_file_getattr } },
756 { VOPNAME_ACCESS, { .vop_access = xattr_file_access } },
757 { VOPNAME_READDIR, { .error = fs_notdir } },
758 { VOPNAME_SEEK, { .vop_seek = fs_seek } },
759 { VOPNAME_INACTIVE, { .vop_inactive = gfs_vop_inactive } },
760 { VOPNAME_FID, { .vop_fid = xattr_common_fid } },
761 { VOPNAME_PATHCONF, { .vop_pathconf = xattr_file_pathconf } },
762 { VOPNAME_PUTPAGE, { .error = fs_putpage } },
763 { VOPNAME_FSYNC, { .error = fs_fsync } },
764 { NULL }
765 };
766
767 vnode_t *
768 xattr_mkfile(vnode_t *pvp, xattr_view_t xattr_view)
769 {
770 vnode_t *vp;
771 xattr_file_t *np;
772
773 vp = gfs_file_create(sizeof (xattr_file_t), pvp, xattr_file_ops);
774 np = vp->v_data;
775 np->xattr_view = xattr_view;
776 vp->v_flag |= V_SYSATTR;
777 return (vp);
778 }
779
780 vnode_t *
781 xattr_mkfile_ro(vnode_t *pvp)
782 {
783 return (xattr_mkfile(pvp, XATTR_VIEW_READONLY));
784 }
785
786 vnode_t *
787 xattr_mkfile_rw(vnode_t *pvp)
788 {
789 return (xattr_mkfile(pvp, XATTR_VIEW_READWRITE));
790 }
791
792 vnodeops_t *xattr_dir_ops;
793
794 static gfs_dirent_t xattr_dirents[] = {
795 { VIEW_READONLY, xattr_mkfile_ro, GFS_CACHE_VNODE, },
796 { VIEW_READWRITE, xattr_mkfile_rw, GFS_CACHE_VNODE, },
797 { NULL },
798 };
799
800 #define XATTRDIR_NENTS ((sizeof (xattr_dirents) / sizeof (gfs_dirent_t)) - 1)
801
802 static int
803 is_sattr_name(char *s)
804 {
805 int i;
806
807 for (i = 0; i < XATTRDIR_NENTS; ++i) {
808 if (strcmp(s, xattr_dirents[i].gfse_name) == 0) {
809 return (1);
810 }
811 }
812 return (0);
813 }
814
815 /*
816 * Given the name of an extended attribute file, determine if there is a
817 * normalization conflict with a sysattr view name.
818 */
819 int
820 xattr_sysattr_casechk(char *s)
821 {
822 int i;
823
824 for (i = 0; i < XATTRDIR_NENTS; ++i) {
825 if (strcasecmp(s, xattr_dirents[i].gfse_name) == 0)
826 return (1);
827 }
828 return (0);
829 }
830
831 static int
832 xattr_copy(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
833 cred_t *cr, caller_context_t *ct)
834 {
835 xvattr_t xvattr;
836 vnode_t *pdvp;
837 int error;
838
839 /*
840 * Only copy system attrs if the views are the same
841 */
842 if (strcmp(snm, tnm) != 0)
843 return (EINVAL);
844
845 xva_init(&xvattr);
846
847 XVA_SET_REQ(&xvattr, XAT_SYSTEM);
848 XVA_SET_REQ(&xvattr, XAT_READONLY);
849 XVA_SET_REQ(&xvattr, XAT_HIDDEN);
850 XVA_SET_REQ(&xvattr, XAT_ARCHIVE);
851 XVA_SET_REQ(&xvattr, XAT_APPENDONLY);
852 XVA_SET_REQ(&xvattr, XAT_NOUNLINK);
853 XVA_SET_REQ(&xvattr, XAT_IMMUTABLE);
854 XVA_SET_REQ(&xvattr, XAT_NODUMP);
855 XVA_SET_REQ(&xvattr, XAT_AV_MODIFIED);
856 XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
857 XVA_SET_REQ(&xvattr, XAT_CREATETIME);
858 XVA_SET_REQ(&xvattr, XAT_REPARSE);
859 XVA_SET_REQ(&xvattr, XAT_OFFLINE);
860 XVA_SET_REQ(&xvattr, XAT_SPARSE);
861
862 pdvp = gfs_file_parent(sdvp);
863 error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
864 if (error)
865 return (error);
866
867 pdvp = gfs_file_parent(tdvp);
868 error = VOP_SETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
869 return (error);
870 }
871
872 static int
873 xattr_dir_realdir(vnode_t *dvp, vnode_t **realdvp, int lookup_flags,
874 cred_t *cr, caller_context_t *ct)
875 {
876 xattr_dir_t *xattr_dir;
877 int error;
878
879 *realdvp = NULL;
880
881 if (dvp->v_type != VDIR)
882 return (EINVAL);
883
884 mutex_enter(&dvp->v_lock);
885 xattr_dir = dvp->v_data;
886 *realdvp = xattr_dir->xattr_realvp;
887 mutex_exit(&dvp->v_lock);
888
889 if (*realdvp != NULL) {
890 VN_HOLD(*realdvp);
891 error = 0;
892 } else
893 error = ENOENT;
894
895 return (error);
896 }
897
898 /* ARGSUSED */
899 static int
900 xattr_dir_open(vnode_t **vpp, int flags, cred_t *cr, caller_context_t *ct)
901 {
902 vnode_t *realvp;
903 int error;
904
905 if (flags & FWRITE) {
906 return (EACCES);
907 }
908
909 /*
910 * The underlying FS may need this VOP call.
911 */
912 error = xattr_dir_realdir(*vpp, &realvp, LOOKUP_XATTR, cr, ct);
913 if (error == 0) {
914 error = VOP_OPEN(&realvp, flags, cr, ct);
915 VN_RELE(realvp);
916 if (error)
917 return (error);
918 } /* else ignore this error */
919
920 return (0);
921 }
922
923 /* ARGSUSED */
924 static int
925 xattr_dir_close(vnode_t *vp, int flags, int count, offset_t off, cred_t *cr,
926 caller_context_t *ct)
927 {
928 vnode_t *realvp;
929 int error;
930
931 /*
932 * The underlying FS may need this VOP call.
933 */
934 error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
935 if (error == 0) {
936 error = VOP_CLOSE(realvp, flags, count, off, cr, ct);
937 VN_RELE(realvp);
938 if (error)
939 return (error);
940 } /* else ignore this error */
941
942 return (0);
943 }
944
945 /*
946 * Retrieve the attributes on an xattr directory. If there is a "real"
947 * xattr directory, use that. Otherwise, get the attributes (represented
948 * by PARENT_ATTRMASK) from the "parent" node and fill in the rest. Note
949 * that VOP_GETATTR() could turn off bits in the va_mask.
950 */
951
952 #define PARENT_ATTRMASK (AT_UID|AT_GID|AT_RDEV|AT_CTIME|AT_MTIME)
953
954 /* ARGSUSED */
955 static int
956 xattr_dir_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
957 caller_context_t *ct)
958 {
959 timestruc_t now;
960 vnode_t *pvp;
961 int error;
962
963 error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR, cr, ct);
964 if (error == 0) {
965 error = VOP_GETATTR(pvp, vap, 0, cr, ct);
966 VN_RELE(pvp);
967 if (error) {
968 return (error);
969 }
970 vap->va_nlink += XATTRDIR_NENTS;
971 vap->va_size += XATTRDIR_NENTS;
972 return (0);
973 }
974
975 /*
976 * There is no real xattr directory. Cobble together
977 * an entry using info from the parent object (if needed)
978 * plus information common to all xattrs.
979 */
980 if (vap->va_mask & PARENT_ATTRMASK) {
981 vattr_t pvattr;
982 uint_t off_bits;
983
984 pvp = gfs_file_parent(vp);
985 (void) memset(&pvattr, 0, sizeof (pvattr));
986 pvattr.va_mask = PARENT_ATTRMASK;
987 error = VOP_GETATTR(pvp, &pvattr, 0, cr, ct);
988 if (error) {
989 return (error);
990 }
991
992 /*
993 * VOP_GETATTR() might have turned off some bits in
994 * pvattr.va_mask. This means that the underlying
995 * file system couldn't process those attributes.
996 * We need to make sure those bits get turned off
997 * in the vattr_t structure that gets passed back
998 * to the caller. Figure out which bits were turned
999 * off (if any) then set pvattr.va_mask before it
1000 * gets copied to the vattr_t that the caller sees.
1001 */
1002 off_bits = (pvattr.va_mask ^ PARENT_ATTRMASK) & PARENT_ATTRMASK;
1003 pvattr.va_mask = vap->va_mask & ~off_bits;
1004 *vap = pvattr;
1005 }
1006
1007 vap->va_type = VDIR;
1008 vap->va_mode = MAKEIMODE(vap->va_type, S_ISVTX | 0777);
1009 vap->va_fsid = vp->v_vfsp->vfs_dev;
1010 vap->va_nodeid = gfs_file_inode(vp);
1011 vap->va_nlink = XATTRDIR_NENTS+2;
1012 vap->va_size = vap->va_nlink;
1013 gethrestime(&now);
1014 vap->va_atime = now;
1015 vap->va_blksize = 0;
1016 vap->va_nblocks = 0;
1017 vap->va_seq = 0;
1018 return (0);
1019 }
1020
1021 static int
1022 xattr_dir_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
1023 caller_context_t *ct)
1024 {
1025 vnode_t *realvp;
1026 int error;
1027
1028 /*
1029 * If there is a real xattr directory, do the setattr there.
1030 * Otherwise, just return success. The GFS directory is transient,
1031 * and any setattr changes can disappear anyway.
1032 */
1033 error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
1034 if (error == 0) {
1035 error = VOP_SETATTR(realvp, vap, flags, cr, ct);
1036 VN_RELE(realvp);
1037 }
1038 if (error == ENOENT) {
1039 error = 0;
1040 }
1041 return (error);
1042 }
1043
1044 /* ARGSUSED */
1045 static int
1046 xattr_dir_access(vnode_t *vp, int mode, int flags, cred_t *cr,
1047 caller_context_t *ct)
1048 {
1049 int error;
1050 vnode_t *realvp = NULL;
1051
1052 if (mode & VWRITE) {
1053 return (EACCES);
1054 }
1055
1056 error = xattr_dir_realdir(vp, &realvp, LOOKUP_XATTR, cr, ct);
1057
1058 if (realvp)
1059 VN_RELE(realvp);
1060
1061 /*
1062 * No real xattr dir isn't an error
1063 * an error of EINVAL indicates attributes on attributes
1064 * are not supported. In that case just allow access to the
1065 * transient directory.
1066 */
1067 return ((error == ENOENT || error == EINVAL) ? 0 : error);
1068 }
1069
1070 static int
1071 xattr_dir_create(vnode_t *dvp, char *name, vattr_t *vap, vcexcl_t excl,
1072 int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
1073 vsecattr_t *vsecp)
1074 {
1075 vnode_t *pvp;
1076 int error;
1077
1078 *vpp = NULL;
1079
1080 /*
1081 * Don't allow creation of extended attributes with sysattr names.
1082 */
1083 if (is_sattr_name(name)) {
1084 return (gfs_dir_lookup(dvp, name, vpp, cr, 0, NULL, NULL));
1085 }
1086
1087 error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR,
1088 cr, ct);
1089 if (error == 0) {
1090 error = VOP_CREATE(pvp, name, vap, excl, mode, vpp, cr, flag,
1091 ct, vsecp);
1092 VN_RELE(pvp);
1093 }
1094 return (error);
1095 }
1096
1097 static int
1098 xattr_dir_remove(vnode_t *dvp, char *name, cred_t *cr, caller_context_t *ct,
1099 int flags)
1100 {
1101 vnode_t *pvp;
1102 int error;
1103
1104 if (is_sattr_name(name)) {
1105 return (EACCES);
1106 }
1107
1108 error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct);
1109 if (error == 0) {
1110 error = VOP_REMOVE(pvp, name, cr, ct, flags);
1111 VN_RELE(pvp);
1112 }
1113 return (error);
1114 }
1115
1116 static int
1117 xattr_dir_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr,
1118 caller_context_t *ct, int flags)
1119 {
1120 vnode_t *pvp;
1121 int error;
1122
1123 if (svp->v_flag & V_SYSATTR) {
1124 return (EINVAL);
1125 }
1126
1127 error = xattr_dir_realdir(tdvp, &pvp, LOOKUP_XATTR, cr, ct);
1128 if (error == 0) {
1129 error = VOP_LINK(pvp, svp, name, cr, ct, flags);
1130 VN_RELE(pvp);
1131 }
1132 return (error);
1133 }
1134
1135 static int
1136 xattr_dir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
1137 cred_t *cr, caller_context_t *ct, int flags)
1138 {
1139 vnode_t *spvp, *tpvp;
1140 int error;
1141 int held_tgt;
1142
1143 if (is_sattr_name(snm) || is_sattr_name(tnm))
1144 return (xattr_copy(sdvp, snm, tdvp, tnm, cr, ct));
1145 /*
1146 * We know that sdvp is a GFS dir, or we wouldn't be here.
1147 * Get the real unnamed directory.
1148 */
1149 error = xattr_dir_realdir(sdvp, &spvp, LOOKUP_XATTR, cr, ct);
1150 if (error) {
1151 return (error);
1152 }
1153
1154 if (sdvp == tdvp) {
1155 /*
1156 * If the source and target are the same GFS directory, the
1157 * underlying unnamed source and target dir will be the same.
1158 */
1159 tpvp = spvp;
1160 VN_HOLD(tpvp);
1161 held_tgt = 1;
1162 } else if (tdvp->v_flag & V_SYSATTR) {
1163 /*
1164 * If the target dir is a different GFS directory,
1165 * find its underlying unnamed dir.
1166 */
1167 error = xattr_dir_realdir(tdvp, &tpvp, LOOKUP_XATTR, cr, ct);
1168 if (error) {
1169 VN_RELE(spvp);
1170 return (error);
1171 }
1172 held_tgt = 1;
1173 } else {
1174 /*
1175 * Target dir is outside of GFS, pass it on through.
1176 */
1177 tpvp = tdvp;
1178 held_tgt = 0;
1179 }
1180
1181 error = VOP_RENAME(spvp, snm, tpvp, tnm, cr, ct, flags);
1182
1183 if (held_tgt) {
1184 VN_RELE(tpvp);
1185 }
1186 VN_RELE(spvp);
1187
1188 return (error);
1189 }
1190
1191 /*
1192 * readdir_xattr_casecmp: given a system attribute name, see if there
1193 * is a real xattr with the same normalized name.
1194 */
1195 static int
1196 readdir_xattr_casecmp(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
1197 int *eflags)
1198 {
1199 int error;
1200 vnode_t *vp;
1201 struct pathname pn;
1202
1203 *eflags = 0;
1204
1205 error = pn_get(nm, UIO_SYSSPACE, &pn);
1206 if (error == 0) {
1207 error = VOP_LOOKUP(dvp, nm, &vp, &pn,
1208 FIGNORECASE, rootvp, cr, ct, NULL, NULL);
1209 if (error == 0) {
1210 *eflags = ED_CASE_CONFLICT;
1211 VN_RELE(vp);
1212 } else if (error == ENOENT) {
1213 error = 0;
1214 }
1215 pn_free(&pn);
1216 }
1217
1218 return (error);
1219 }
1220
1221 static int
1222 xattr_dir_readdir(vnode_t *dvp, uio_t *uiop, cred_t *cr, int *eofp,
1223 caller_context_t *ct, int flags)
1224 {
1225 vnode_t *pvp;
1226 int error;
1227 int local_eof;
1228 int reset_off = 0;
1229 int has_xattrs = 0;
1230
1231 if (eofp == NULL) {
1232 eofp = &local_eof;
1233 }
1234 *eofp = 0;
1235
1236 /*
1237 * See if there is a real extended attribute directory.
1238 */
1239 error = xattr_dir_realdir(dvp, &pvp, LOOKUP_XATTR, cr, ct);
1240 if (error == 0) {
1241 has_xattrs = 1;
1242 }
1243
1244 /*
1245 * Start by reading up the static entries.
1246 */
1247 if (uiop->uio_loffset == 0) {
1248 ino64_t pino, ino;
1249 offset_t off;
1250 gfs_dir_t *dp = dvp->v_data;
1251 gfs_readdir_state_t gstate;
1252
1253 if (has_xattrs) {
1254 /*
1255 * If there is a real xattr dir, skip . and ..
1256 * in the GFS dir. We'll pick them up below
1257 * when we call into the underlying fs.
1258 */
1259 uiop->uio_loffset = GFS_STATIC_ENTRY_OFFSET;
1260 }
1261 error = gfs_get_parent_ino(dvp, cr, ct, &pino, &ino);
1262 if (error == 0) {
1263 error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1,
1264 uiop, pino, ino, flags);
1265 }
1266 if (error) {
1267 if (has_xattrs)
1268 VN_RELE(pvp);
1269 return (error);
1270 }
1271
1272 while ((error = gfs_readdir_pred(&gstate, uiop, &off)) == 0 &&
1273 !*eofp) {
1274 if (off >= 0 && off < dp->gfsd_nstatic) {
1275 int eflags;
1276
1277 /*
1278 * Check to see if this sysattr set name has a
1279 * case-insensitive conflict with a real xattr
1280 * name.
1281 */
1282 eflags = 0;
1283 if ((flags & V_RDDIR_ENTFLAGS) && has_xattrs) {
1284 error = readdir_xattr_casecmp(pvp,
1285 dp->gfsd_static[off].gfse_name,
1286 cr, ct, &eflags);
1287 if (error)
1288 break;
1289 }
1290 ino = dp->gfsd_inode(dvp, off);
1291
1292 error = gfs_readdir_emit(&gstate, uiop, off,
1293 ino, dp->gfsd_static[off].gfse_name,
1294 eflags);
1295 if (error)
1296 break;
1297 } else {
1298 *eofp = 1;
1299 }
1300 }
1301
1302 error = gfs_readdir_fini(&gstate, error, eofp, *eofp);
1303 if (error) {
1304 if (has_xattrs)
1305 VN_RELE(pvp);
1306 return (error);
1307 }
1308
1309 /*
1310 * We must read all of the static entries in the first
1311 * call. Otherwise we won't know if uio_loffset in a
1312 * subsequent call refers to the static entries or to those
1313 * in an underlying fs.
1314 */
1315 if (*eofp == 0)
1316 return (EINVAL);
1317 reset_off = 1;
1318 }
1319
1320 if (!has_xattrs) {
1321 *eofp = 1;
1322 return (0);
1323 }
1324
1325 *eofp = 0;
1326 if (reset_off) {
1327 uiop->uio_loffset = 0;
1328 }
1329 (void) VOP_RWLOCK(pvp, V_WRITELOCK_FALSE, NULL);
1330 error = VOP_READDIR(pvp, uiop, cr, eofp, ct, flags);
1331 VOP_RWUNLOCK(pvp, V_WRITELOCK_FALSE, NULL);
1332 VN_RELE(pvp);
1333
1334 return (error);
1335 }
1336
1337 /* ARGSUSED */
1338 static void
1339 xattr_dir_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1340 {
1341 gfs_file_t *fp;
1342 xattr_dir_t *xattr_dir;
1343
1344 mutex_enter(&vp->v_lock);
1345 xattr_dir = vp->v_data;
1346 if (xattr_dir->xattr_realvp) {
1347 VN_RELE(xattr_dir->xattr_realvp);
1348 xattr_dir->xattr_realvp = NULL;
1349 }
1350 mutex_exit(&vp->v_lock);
1351 fp = gfs_dir_inactive(vp);
1352 if (fp != NULL) {
1353 kmem_free(fp, fp->gfs_size);
1354 }
1355 }
1356
1357 static int
1358 xattr_dir_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
1359 caller_context_t *ct)
1360 {
1361 switch (cmd) {
1362 case _PC_XATTR_EXISTS:
1363 case _PC_SATTR_ENABLED:
1364 case _PC_SATTR_EXISTS:
1365 *valp = 0;
1366 return (0);
1367 default:
1368 return (fs_pathconf(vp, cmd, valp, cr, ct));
1369 }
1370 }
1371
1372 /* ARGSUSED */
1373 static int
1374 xattr_dir_realvp(vnode_t *vp, vnode_t **realvp, caller_context_t *ct)
1375 {
1376 int error;
1377
1378 error = xattr_dir_realdir(vp, realvp, LOOKUP_XATTR, kcred, NULL);
1379 return (error);
1380
1381 }
1382
1383 static const fs_operation_def_t xattr_dir_tops[] = {
1384 { VOPNAME_OPEN, { .vop_open = xattr_dir_open } },
1385 { VOPNAME_CLOSE, { .vop_close = xattr_dir_close } },
1386 { VOPNAME_IOCTL, { .error = fs_inval } },
1387 { VOPNAME_GETATTR, { .vop_getattr = xattr_dir_getattr } },
1388 { VOPNAME_SETATTR, { .vop_setattr = xattr_dir_setattr } },
1389 { VOPNAME_ACCESS, { .vop_access = xattr_dir_access } },
1390 { VOPNAME_READDIR, { .vop_readdir = xattr_dir_readdir } },
1391 { VOPNAME_LOOKUP, { .vop_lookup = gfs_vop_lookup } },
1392 { VOPNAME_CREATE, { .vop_create = xattr_dir_create } },
1393 { VOPNAME_REMOVE, { .vop_remove = xattr_dir_remove } },
1394 { VOPNAME_LINK, { .vop_link = xattr_dir_link } },
1395 { VOPNAME_RENAME, { .vop_rename = xattr_dir_rename } },
1396 { VOPNAME_MKDIR, { .error = fs_inval } },
1397 { VOPNAME_SEEK, { .vop_seek = fs_seek } },
1398 { VOPNAME_INACTIVE, { .vop_inactive = xattr_dir_inactive } },
1399 { VOPNAME_FID, { .vop_fid = xattr_common_fid } },
1400 { VOPNAME_PATHCONF, { .vop_pathconf = xattr_dir_pathconf } },
1401 { VOPNAME_REALVP, { .vop_realvp = xattr_dir_realvp } },
1402 { NULL, NULL }
1403 };
1404
1405 static gfs_opsvec_t xattr_opsvec[] = {
1406 { "xattr dir", xattr_dir_tops, &xattr_dir_ops },
1407 { "system attributes", xattr_file_tops, &xattr_file_ops },
1408 { NULL, NULL, NULL }
1409 };
1410
1411 static int
1412 xattr_lookup_cb(vnode_t *vp, const char *nm, vnode_t **vpp, ino64_t *inop,
1413 cred_t *cr, int flags, int *deflags, pathname_t *rpnp)
1414 {
1415 vnode_t *pvp;
1416 struct pathname pn;
1417 int error;
1418
1419 *vpp = NULL;
1420 *inop = 0;
1421
1422 error = xattr_dir_realdir(vp, &pvp, LOOKUP_XATTR|CREATE_XATTR_DIR,
1423 cr, NULL);
1424
1425 /*
1426 * Return ENOENT for EACCES requests during lookup. Once an
1427 * attribute create is attempted EACCES will be returned.
1428 */
1429 if (error) {
1430 if (error == EACCES)
1431 return (ENOENT);
1432 return (error);
1433 }
1434
1435 error = pn_get((char *)nm, UIO_SYSSPACE, &pn);
1436 if (error == 0) {
1437 error = VOP_LOOKUP(pvp, (char *)nm, vpp, &pn, flags, rootvp,
1438 cr, NULL, deflags, rpnp);
1439 pn_free(&pn);
1440 }
1441 VN_RELE(pvp);
1442
1443 return (error);
1444 }
1445
1446 /* ARGSUSED */
1447 static ino64_t
1448 xattrdir_do_ino(vnode_t *vp, int index)
1449 {
1450 /*
1451 * We use index 0 for the directory fid. Start
1452 * the file numbering at 1.
1453 */
1454 return ((ino64_t)index+1);
1455 }
1456
1457 void
1458 xattr_init(void)
1459 {
1460 VERIFY(gfs_make_opsvec(xattr_opsvec) == 0);
1461 }
1462
1463 /* See vnode.c: fop_lookup() */
1464 int
1465 xattr_dir_lookup(vnode_t *dvp, vnode_t **vpp, int flags, cred_t *cr)
1466 {
1467 int error = 0;
1468 vnode_t *gfs_vp = NULL;
1469 vnode_t *real_vp = NULL;
1470 xattr_dir_t *xattr_dir;
1471 struct pathname pn;
1472 char *nm = "";
1473
1474 *vpp = NULL;
1475
1476 if (dvp->v_type != VDIR && dvp->v_type != VREG)
1477 return (EINVAL);
1478
1479 mutex_enter(&dvp->v_lock);
1480
1481 /*
1482 * If we're already in sysattr space, don't allow creation
1483 * of another level of sysattrs.
1484 */
1485 if (dvp->v_flag & V_SYSATTR) {
1486 mutex_exit(&dvp->v_lock);
1487 return (EINVAL);
1488 }
1489
1490 if (dvp->v_xattrdir != NULL) {
1491 gfs_vp = dvp->v_xattrdir;
1492 VN_HOLD(gfs_vp);
1493 } else {
1494 ulong_t val;
1495 int xattrs_allowed = dvp->v_vfsp->vfs_flag & VFS_XATTR;
1496 int sysattrs_allowed = 1;
1497
1498 /*
1499 * We have to drop the lock on dvp. gfs_dir_create will
1500 * grab it for a VN_HOLD.
1501 */
1502 mutex_exit(&dvp->v_lock);
1503
1504 /*
1505 * If dvp allows xattr creation, but not sysattr
1506 * creation, return the real xattr dir vp. We can't
1507 * use the vfs feature mask here because _PC_SATTR_ENABLED
1508 * has vnode-level granularity (e.g. .zfs).
1509 */
1510 error = VOP_PATHCONF(dvp, _PC_SATTR_ENABLED, &val, cr, NULL);
1511 if (error != 0 || val == 0)
1512 sysattrs_allowed = 0;
1513
1514 if (!xattrs_allowed && !sysattrs_allowed)
1515 return (EINVAL);
1516
1517 if (!sysattrs_allowed) {
1518 error = pn_get(nm, UIO_SYSSPACE, &pn);
1519 if (error)
1520 return (error);
1521 error = VOP_LOOKUP(dvp, nm, vpp, &pn,
1522 flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL,
1523 NULL, NULL);
1524 pn_free(&pn);
1525 return (error);
1526 }
1527
1528 /*
1529 * Note that we act as if we were given CREATE_XATTR_DIR,
1530 * but only for creation of the GFS directory.
1531 */
1532 gfs_vp = gfs_dir_create(
1533 sizeof (xattr_dir_t), dvp, xattr_dir_ops, xattr_dirents,
1534 xattrdir_do_ino, MAXNAMELEN, NULL, xattr_lookup_cb);
1535 mutex_enter(&dvp->v_lock);
1536 if (dvp->v_xattrdir != NULL) {
1537 /*
1538 * We lost the race to create the xattr dir.
1539 * Destroy this one, use the winner. We can't
1540 * just call VN_RELE(*vpp), because the vnode
1541 * is only partially initialized.
1542 */
1543 gfs_dir_t *dp = gfs_vp->v_data;
1544
1545 ASSERT(gfs_vp->v_count == 1);
1546 vn_free(gfs_vp);
1547
1548 mutex_destroy(&dp->gfsd_lock);
1549 kmem_free(dp->gfsd_static,
1550 dp->gfsd_nstatic * sizeof (gfs_dirent_t));
1551 kmem_free(dp, dp->gfsd_file.gfs_size);
1552
1553 /*
1554 * There is an implied VN_HOLD(dvp) here. We should
1555 * be doing a VN_RELE(dvp) to clean up the reference
1556 * from gfs_vp, and then a VN_HOLD(dvp) for the new
1557 * reference. Instead, we just leave the count alone.
1558 */
1559
1560 gfs_vp = dvp->v_xattrdir;
1561 VN_HOLD(gfs_vp);
1562 } else {
1563 gfs_vp->v_flag |= (V_XATTRDIR|V_SYSATTR);
1564 dvp->v_xattrdir = gfs_vp;
1565 }
1566 }
1567 mutex_exit(&dvp->v_lock);
1568
1569 /*
1570 * In order to make this module relatively transparent
1571 * to the underlying filesystem, we need to lookup the
1572 * xattr dir in the lower filesystem and (if found)
1573 * keep a hold on it for as long as there is a hold
1574 * on the gfs_vp we're about to return. This hold is
1575 * released in xattr_dir_inactive.
1576 */
1577 xattr_dir = gfs_vp->v_data;
1578 if ((dvp->v_vfsp->vfs_flag & VFS_XATTR) &&
1579 (xattr_dir->xattr_realvp == NULL)) {
1580 error = pn_get(nm, UIO_SYSSPACE, &pn);
1581 if (error == 0) {
1582 error = VOP_LOOKUP(dvp, nm, &real_vp, &pn,
1583 flags|LOOKUP_HAVE_SYSATTR_DIR, rootvp, cr, NULL,
1584 NULL, NULL);
1585 pn_free(&pn);
1586 }
1587 if (error == 0) {
1588 mutex_enter(&gfs_vp->v_lock);
1589 if (xattr_dir->xattr_realvp == NULL)
1590 xattr_dir->xattr_realvp = real_vp;
1591 else
1592 VN_RELE(real_vp);
1593 mutex_exit(&gfs_vp->v_lock);
1594 }
1595 }
1596
1597 *vpp = gfs_vp;
1598 return (0);
1599 }
1600
1601 int
1602 xattr_dir_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
1603 {
1604 int error;
1605 vnode_t *pvp, *dvp;
1606 xattr_fid_t *xfidp;
1607 struct pathname pn;
1608 char *nm;
1609 uint16_t orig_len;
1610
1611 *vpp = NULL;
1612
1613 if (fidp->fid_len < XATTR_FIDSZ)
1614 return (EINVAL);
1615
1616 xfidp = (xattr_fid_t *)fidp;
1617 orig_len = fidp->fid_len;
1618 fidp->fid_len = xfidp->parent_len;
1619
1620 error = VFS_VGET(vfsp, &pvp, fidp);
1621 fidp->fid_len = orig_len;
1622 if (error)
1623 return (error);
1624
1625 /*
1626 * Start by getting the GFS sysattr directory. We might need
1627 * to recreate it during the VOP_LOOKUP.
1628 */
1629 nm = "";
1630 error = pn_get(nm, UIO_SYSSPACE, &pn);
1631 if (error) {
1632 VN_RELE(pvp);
1633 return (EINVAL);
1634 }
1635
1636 error = VOP_LOOKUP(pvp, nm, &dvp, &pn, LOOKUP_XATTR|CREATE_XATTR_DIR,
1637 rootvp, CRED(), NULL, NULL, NULL);
1638 pn_free(&pn);
1639 VN_RELE(pvp);
1640 if (error)
1641 return (error);
1642
1643 if (xfidp->dir_offset == 0) {
1644 /*
1645 * If we were looking for the directory, we're done.
1646 */
1647 *vpp = dvp;
1648 return (0);
1649 }
1650
1651 if (xfidp->dir_offset > XATTRDIR_NENTS) {
1652 VN_RELE(dvp);
1653 return (EINVAL);
1654 }
1655
1656 nm = xattr_dirents[xfidp->dir_offset - 1].gfse_name;
1657
1658 error = pn_get(nm, UIO_SYSSPACE, &pn);
1659 if (error) {
1660 VN_RELE(dvp);
1661 return (EINVAL);
1662 }
1663
1664 error = VOP_LOOKUP(dvp, nm, vpp, &pn, 0, rootvp, CRED(), NULL,
1665 NULL, NULL);
1666
1667 pn_free(&pn);
1668 VN_RELE(dvp);
1669
1670 return (error);
1671 }