cxgbe/t4_tom: Read the chip's DDP page sizes and save them in a
[freebsd-src.git] / sys / kern / vfs_extattr.c
blob0f82c2b1e49fa150b41162054a14eb2fee52a23d
1 /*-
2 * Copyright (c) 1999-2001 Robert N. M. Watson
3 * All rights reserved.
5 * This software was developed by Robert Watson for the TrustedBSD Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/capsicum.h>
35 #include <sys/lock.h>
36 #include <sys/mount.h>
37 #include <sys/mutex.h>
38 #include <sys/sysproto.h>
39 #include <sys/fcntl.h>
40 #include <sys/namei.h>
41 #include <sys/filedesc.h>
42 #include <sys/limits.h>
43 #include <sys/vnode.h>
44 #include <sys/proc.h>
45 #include <sys/extattr.h>
47 #include <security/audit/audit.h>
48 #include <security/mac/mac_framework.h>
51 * Syscall to push extended attribute configuration information into the VFS.
52 * Accepts a path, which it converts to a mountpoint, as well as a command
53 * (int cmd), and attribute name and misc data.
55 * Currently this is used only by UFS1 extended attributes.
57 int
58 sys_extattrctl(td, uap)
59 struct thread *td;
60 struct extattrctl_args /* {
61 const char *path;
62 int cmd;
63 const char *filename;
64 int attrnamespace;
65 const char *attrname;
66 } */ *uap;
68 struct vnode *filename_vp;
69 struct nameidata nd;
70 struct mount *mp, *mp_writable;
71 char attrname[EXTATTR_MAXNAMELEN];
72 int error;
74 AUDIT_ARG_CMD(uap->cmd);
75 AUDIT_ARG_VALUE(uap->attrnamespace);
77 * uap->attrname is not always defined. We check again later when we
78 * invoke the VFS call so as to pass in NULL there if needed.
80 if (uap->attrname != NULL) {
81 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN,
82 NULL);
83 if (error)
84 return (error);
86 AUDIT_ARG_TEXT(attrname);
88 mp = NULL;
89 filename_vp = NULL;
90 if (uap->filename != NULL) {
91 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE2,
92 UIO_USERSPACE, uap->filename, td);
93 error = namei(&nd);
94 if (error)
95 return (error);
96 filename_vp = nd.ni_vp;
97 NDFREE(&nd, NDF_NO_VP_RELE);
100 /* uap->path is always defined. */
101 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1,
102 UIO_USERSPACE, uap->path, td);
103 error = namei(&nd);
104 if (error)
105 goto out;
106 mp = nd.ni_vp->v_mount;
107 error = vfs_busy(mp, 0);
108 if (error) {
109 NDFREE(&nd, 0);
110 mp = NULL;
111 goto out;
113 VOP_UNLOCK(nd.ni_vp, 0);
114 error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
115 NDFREE(&nd, NDF_NO_VP_UNLOCK);
116 if (error)
117 goto out;
118 if (filename_vp != NULL) {
120 * uap->filename is not always defined. If it is,
121 * grab a vnode lock, which VFS_EXTATTRCTL() will
122 * later release.
124 error = vn_lock(filename_vp, LK_EXCLUSIVE);
125 if (error) {
126 vn_finished_write(mp_writable);
127 goto out;
131 error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
132 uap->attrname != NULL ? attrname : NULL);
134 vn_finished_write(mp_writable);
135 out:
136 if (mp != NULL)
137 vfs_unbusy(mp);
140 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp,
141 * so vrele it if it is defined.
143 if (filename_vp != NULL)
144 vrele(filename_vp);
145 return (error);
149 * Set a named extended attribute on a file or directory
151 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
152 * kernelspace string pointer "attrname", userspace buffer
153 * pointer "data", buffer length "nbytes", thread "td".
154 * Returns: 0 on success, an error number otherwise
155 * Locks: none
156 * References: vp must be a valid reference for the duration of the call
158 static int
159 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
160 void *data, size_t nbytes, struct thread *td)
162 struct mount *mp;
163 struct uio auio;
164 struct iovec aiov;
165 ssize_t cnt;
166 int error;
168 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
169 if (error)
170 return (error);
171 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
173 aiov.iov_base = data;
174 aiov.iov_len = nbytes;
175 auio.uio_iov = &aiov;
176 auio.uio_iovcnt = 1;
177 auio.uio_offset = 0;
178 if (nbytes > IOSIZE_MAX) {
179 error = EINVAL;
180 goto done;
182 auio.uio_resid = nbytes;
183 auio.uio_rw = UIO_WRITE;
184 auio.uio_segflg = UIO_USERSPACE;
185 auio.uio_td = td;
186 cnt = nbytes;
188 #ifdef MAC
189 error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace,
190 attrname);
191 if (error)
192 goto done;
193 #endif
195 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
196 td->td_ucred, td);
197 cnt -= auio.uio_resid;
198 td->td_retval[0] = cnt;
200 done:
201 VOP_UNLOCK(vp, 0);
202 vn_finished_write(mp);
203 return (error);
207 sys_extattr_set_fd(td, uap)
208 struct thread *td;
209 struct extattr_set_fd_args /* {
210 int fd;
211 int attrnamespace;
212 const char *attrname;
213 void *data;
214 size_t nbytes;
215 } */ *uap;
217 struct file *fp;
218 char attrname[EXTATTR_MAXNAMELEN];
219 cap_rights_t rights;
220 int error;
222 AUDIT_ARG_FD(uap->fd);
223 AUDIT_ARG_VALUE(uap->attrnamespace);
224 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
225 if (error)
226 return (error);
227 AUDIT_ARG_TEXT(attrname);
229 error = getvnode(td, uap->fd,
230 cap_rights_init(&rights, CAP_EXTATTR_SET), &fp);
231 if (error)
232 return (error);
234 error = extattr_set_vp(fp->f_vnode, uap->attrnamespace,
235 attrname, uap->data, uap->nbytes, td);
236 fdrop(fp, td);
238 return (error);
242 sys_extattr_set_file(td, uap)
243 struct thread *td;
244 struct extattr_set_file_args /* {
245 const char *path;
246 int attrnamespace;
247 const char *attrname;
248 void *data;
249 size_t nbytes;
250 } */ *uap;
252 struct nameidata nd;
253 char attrname[EXTATTR_MAXNAMELEN];
254 int error;
256 AUDIT_ARG_VALUE(uap->attrnamespace);
257 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
258 if (error)
259 return (error);
260 AUDIT_ARG_TEXT(attrname);
262 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE,
263 uap->path, td);
264 error = namei(&nd);
265 if (error)
266 return (error);
267 NDFREE(&nd, NDF_ONLY_PNBUF);
269 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
270 uap->data, uap->nbytes, td);
272 vrele(nd.ni_vp);
273 return (error);
277 sys_extattr_set_link(td, uap)
278 struct thread *td;
279 struct extattr_set_link_args /* {
280 const char *path;
281 int attrnamespace;
282 const char *attrname;
283 void *data;
284 size_t nbytes;
285 } */ *uap;
287 struct nameidata nd;
288 char attrname[EXTATTR_MAXNAMELEN];
289 int error;
291 AUDIT_ARG_VALUE(uap->attrnamespace);
292 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
293 if (error)
294 return (error);
295 AUDIT_ARG_TEXT(attrname);
297 NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
298 uap->path, td);
299 error = namei(&nd);
300 if (error)
301 return (error);
302 NDFREE(&nd, NDF_ONLY_PNBUF);
304 error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
305 uap->data, uap->nbytes, td);
307 vrele(nd.ni_vp);
308 return (error);
312 * Get a named extended attribute on a file or directory
314 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
315 * kernelspace string pointer "attrname", userspace buffer
316 * pointer "data", buffer length "nbytes", thread "td".
317 * Returns: 0 on success, an error number otherwise
318 * Locks: none
319 * References: vp must be a valid reference for the duration of the call
321 static int
322 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
323 void *data, size_t nbytes, struct thread *td)
325 struct uio auio, *auiop;
326 struct iovec aiov;
327 ssize_t cnt;
328 size_t size, *sizep;
329 int error;
331 vn_lock(vp, LK_SHARED | LK_RETRY);
334 * Slightly unusual semantics: if the user provides a NULL data
335 * pointer, they don't want to receive the data, just the maximum
336 * read length.
338 auiop = NULL;
339 sizep = NULL;
340 cnt = 0;
341 if (data != NULL) {
342 aiov.iov_base = data;
343 aiov.iov_len = nbytes;
344 auio.uio_iov = &aiov;
345 auio.uio_iovcnt = 1;
346 auio.uio_offset = 0;
347 if (nbytes > IOSIZE_MAX) {
348 error = EINVAL;
349 goto done;
351 auio.uio_resid = nbytes;
352 auio.uio_rw = UIO_READ;
353 auio.uio_segflg = UIO_USERSPACE;
354 auio.uio_td = td;
355 auiop = &auio;
356 cnt = nbytes;
357 } else
358 sizep = &size;
360 #ifdef MAC
361 error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace,
362 attrname);
363 if (error)
364 goto done;
365 #endif
367 error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
368 td->td_ucred, td);
370 if (auiop != NULL) {
371 cnt -= auio.uio_resid;
372 td->td_retval[0] = cnt;
373 } else
374 td->td_retval[0] = size;
376 done:
377 VOP_UNLOCK(vp, 0);
378 return (error);
382 sys_extattr_get_fd(td, uap)
383 struct thread *td;
384 struct extattr_get_fd_args /* {
385 int fd;
386 int attrnamespace;
387 const char *attrname;
388 void *data;
389 size_t nbytes;
390 } */ *uap;
392 struct file *fp;
393 char attrname[EXTATTR_MAXNAMELEN];
394 cap_rights_t rights;
395 int error;
397 AUDIT_ARG_FD(uap->fd);
398 AUDIT_ARG_VALUE(uap->attrnamespace);
399 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
400 if (error)
401 return (error);
402 AUDIT_ARG_TEXT(attrname);
404 error = getvnode(td, uap->fd,
405 cap_rights_init(&rights, CAP_EXTATTR_GET), &fp);
406 if (error)
407 return (error);
409 error = extattr_get_vp(fp->f_vnode, uap->attrnamespace,
410 attrname, uap->data, uap->nbytes, td);
412 fdrop(fp, td);
413 return (error);
417 sys_extattr_get_file(td, uap)
418 struct thread *td;
419 struct extattr_get_file_args /* {
420 const char *path;
421 int attrnamespace;
422 const char *attrname;
423 void *data;
424 size_t nbytes;
425 } */ *uap;
427 struct nameidata nd;
428 char attrname[EXTATTR_MAXNAMELEN];
429 int error;
431 AUDIT_ARG_VALUE(uap->attrnamespace);
432 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
433 if (error)
434 return (error);
435 AUDIT_ARG_TEXT(attrname);
437 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
438 error = namei(&nd);
439 if (error)
440 return (error);
441 NDFREE(&nd, NDF_ONLY_PNBUF);
443 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
444 uap->data, uap->nbytes, td);
446 vrele(nd.ni_vp);
447 return (error);
451 sys_extattr_get_link(td, uap)
452 struct thread *td;
453 struct extattr_get_link_args /* {
454 const char *path;
455 int attrnamespace;
456 const char *attrname;
457 void *data;
458 size_t nbytes;
459 } */ *uap;
461 struct nameidata nd;
462 char attrname[EXTATTR_MAXNAMELEN];
463 int error;
465 AUDIT_ARG_VALUE(uap->attrnamespace);
466 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
467 if (error)
468 return (error);
469 AUDIT_ARG_TEXT(attrname);
471 NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
472 td);
473 error = namei(&nd);
474 if (error)
475 return (error);
476 NDFREE(&nd, NDF_ONLY_PNBUF);
478 error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
479 uap->data, uap->nbytes, td);
481 vrele(nd.ni_vp);
482 return (error);
486 * extattr_delete_vp(): Delete a named extended attribute on a file or
487 * directory
489 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
490 * kernelspace string pointer "attrname", proc "p"
491 * Returns: 0 on success, an error number otherwise
492 * Locks: none
493 * References: vp must be a valid reference for the duration of the call
495 static int
496 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
497 struct thread *td)
499 struct mount *mp;
500 int error;
502 error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
503 if (error)
504 return (error);
505 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
507 #ifdef MAC
508 error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace,
509 attrname);
510 if (error)
511 goto done;
512 #endif
514 error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
515 td);
516 if (error == EOPNOTSUPP)
517 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
518 td->td_ucred, td);
519 #ifdef MAC
520 done:
521 #endif
522 VOP_UNLOCK(vp, 0);
523 vn_finished_write(mp);
524 return (error);
528 sys_extattr_delete_fd(td, uap)
529 struct thread *td;
530 struct extattr_delete_fd_args /* {
531 int fd;
532 int attrnamespace;
533 const char *attrname;
534 } */ *uap;
536 struct file *fp;
537 char attrname[EXTATTR_MAXNAMELEN];
538 cap_rights_t rights;
539 int error;
541 AUDIT_ARG_FD(uap->fd);
542 AUDIT_ARG_VALUE(uap->attrnamespace);
543 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
544 if (error)
545 return (error);
546 AUDIT_ARG_TEXT(attrname);
548 error = getvnode(td, uap->fd,
549 cap_rights_init(&rights, CAP_EXTATTR_DELETE), &fp);
550 if (error)
551 return (error);
553 error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace,
554 attrname, td);
555 fdrop(fp, td);
556 return (error);
560 sys_extattr_delete_file(td, uap)
561 struct thread *td;
562 struct extattr_delete_file_args /* {
563 const char *path;
564 int attrnamespace;
565 const char *attrname;
566 } */ *uap;
568 struct nameidata nd;
569 char attrname[EXTATTR_MAXNAMELEN];
570 int error;
572 AUDIT_ARG_VALUE(uap->attrnamespace);
573 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
574 if (error)
575 return(error);
576 AUDIT_ARG_TEXT(attrname);
578 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
579 error = namei(&nd);
580 if (error)
581 return(error);
582 NDFREE(&nd, NDF_ONLY_PNBUF);
584 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
585 vrele(nd.ni_vp);
586 return(error);
590 sys_extattr_delete_link(td, uap)
591 struct thread *td;
592 struct extattr_delete_link_args /* {
593 const char *path;
594 int attrnamespace;
595 const char *attrname;
596 } */ *uap;
598 struct nameidata nd;
599 char attrname[EXTATTR_MAXNAMELEN];
600 int error;
602 AUDIT_ARG_VALUE(uap->attrnamespace);
603 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
604 if (error)
605 return(error);
606 AUDIT_ARG_TEXT(attrname);
608 NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
609 error = namei(&nd);
610 if (error)
611 return(error);
612 NDFREE(&nd, NDF_ONLY_PNBUF);
614 error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
615 vrele(nd.ni_vp);
616 return(error);
620 * Retrieve a list of extended attributes on a file or directory.
622 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
623 * userspace buffer pointer "data", buffer length "nbytes",
624 * thread "td".
625 * Returns: 0 on success, an error number otherwise
626 * Locks: none
627 * References: vp must be a valid reference for the duration of the call
629 static int
630 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data,
631 size_t nbytes, struct thread *td)
633 struct uio auio, *auiop;
634 size_t size, *sizep;
635 struct iovec aiov;
636 ssize_t cnt;
637 int error;
639 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
641 auiop = NULL;
642 sizep = NULL;
643 cnt = 0;
644 if (data != NULL) {
645 aiov.iov_base = data;
646 aiov.iov_len = nbytes;
647 auio.uio_iov = &aiov;
648 auio.uio_iovcnt = 1;
649 auio.uio_offset = 0;
650 if (nbytes > IOSIZE_MAX) {
651 error = EINVAL;
652 goto done;
654 auio.uio_resid = nbytes;
655 auio.uio_rw = UIO_READ;
656 auio.uio_segflg = UIO_USERSPACE;
657 auio.uio_td = td;
658 auiop = &auio;
659 cnt = nbytes;
660 } else
661 sizep = &size;
663 #ifdef MAC
664 error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace);
665 if (error)
666 goto done;
667 #endif
669 error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
670 td->td_ucred, td);
672 if (auiop != NULL) {
673 cnt -= auio.uio_resid;
674 td->td_retval[0] = cnt;
675 } else
676 td->td_retval[0] = size;
678 done:
679 VOP_UNLOCK(vp, 0);
680 return (error);
685 sys_extattr_list_fd(td, uap)
686 struct thread *td;
687 struct extattr_list_fd_args /* {
688 int fd;
689 int attrnamespace;
690 void *data;
691 size_t nbytes;
692 } */ *uap;
694 struct file *fp;
695 cap_rights_t rights;
696 int error;
698 AUDIT_ARG_FD(uap->fd);
699 AUDIT_ARG_VALUE(uap->attrnamespace);
700 error = getvnode(td, uap->fd,
701 cap_rights_init(&rights, CAP_EXTATTR_LIST), &fp);
702 if (error)
703 return (error);
705 error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data,
706 uap->nbytes, td);
708 fdrop(fp, td);
709 return (error);
713 sys_extattr_list_file(td, uap)
714 struct thread*td;
715 struct extattr_list_file_args /* {
716 const char *path;
717 int attrnamespace;
718 void *data;
719 size_t nbytes;
720 } */ *uap;
722 struct nameidata nd;
723 int error;
725 AUDIT_ARG_VALUE(uap->attrnamespace);
726 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
727 error = namei(&nd);
728 if (error)
729 return (error);
730 NDFREE(&nd, NDF_ONLY_PNBUF);
732 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
733 uap->nbytes, td);
735 vrele(nd.ni_vp);
736 return (error);
740 sys_extattr_list_link(td, uap)
741 struct thread*td;
742 struct extattr_list_link_args /* {
743 const char *path;
744 int attrnamespace;
745 void *data;
746 size_t nbytes;
747 } */ *uap;
749 struct nameidata nd;
750 int error;
752 AUDIT_ARG_VALUE(uap->attrnamespace);
753 NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
754 td);
755 error = namei(&nd);
756 if (error)
757 return (error);
758 NDFREE(&nd, NDF_ONLY_PNBUF);
760 error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
761 uap->nbytes, td);
763 vrele(nd.ni_vp);
764 return (error);