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