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