PageRenderTime 364ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/sys/ufs/ufs/ufs_extattr.c

https://bitbucket.org/gthummalapalle/minix
C | 1551 lines | 978 code | 228 blank | 345 comment | 233 complexity | 98715d3fdd22bc08b2c1701ecfb3e4f1 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, WTFPL, AGPL-1.0
  1. /* $NetBSD: ufs_extattr.c,v 1.35 2011/07/07 14:56:45 manu Exp $ */
  2. /*-
  3. * Copyright (c) 1999-2002 Robert N. M. Watson
  4. * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
  5. * All rights reserved.
  6. *
  7. * This software was developed by Robert Watson for the TrustedBSD Project.
  8. *
  9. * This software was developed for the FreeBSD Project in part by Network
  10. * Associates Laboratories, the Security Research Division of Network
  11. * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
  12. * as part of the DARPA CHATS research program.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions
  16. * are met:
  17. * 1. Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. * 2. Redistributions in binary form must reproduce the above copyright
  20. * notice, this list of conditions and the following disclaimer in the
  21. * documentation and/or other materials provided with the distribution.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  24. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  27. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33. * SUCH DAMAGE.
  34. *
  35. */
  36. /*
  37. * Support for file system extended attributes on the UFS1 file system.
  38. *
  39. * Extended attributes are defined in the form name=value, where name is
  40. * a nul-terminated string in the style of a file name, and value is a
  41. * binary blob of zero or more bytes. The UFS1 extended attribute service
  42. * layers support for extended attributes onto a backing file, in the style
  43. * of the quota implementation, meaning that it requires no underlying format
  44. * changes to the file system. This design choice exchanges simplicity,
  45. * usability, and easy deployment for performance.
  46. */
  47. #include <sys/cdefs.h>
  48. __KERNEL_RCSID(0, "$NetBSD: ufs_extattr.c,v 1.35 2011/07/07 14:56:45 manu Exp $");
  49. #ifdef _KERNEL_OPT
  50. #include "opt_ffs.h"
  51. #endif
  52. #include <sys/param.h>
  53. #include <sys/systm.h>
  54. #include <sys/reboot.h>
  55. #include <sys/kauth.h>
  56. #include <sys/kernel.h>
  57. #include <sys/namei.h>
  58. #include <sys/malloc.h>
  59. #include <sys/fcntl.h>
  60. #include <sys/lwp.h>
  61. #include <sys/vnode.h>
  62. #include <sys/mount.h>
  63. #include <sys/lock.h>
  64. #include <sys/dirent.h>
  65. #include <sys/extattr.h>
  66. #include <sys/sysctl.h>
  67. #include <ufs/ufs/dir.h>
  68. #include <ufs/ufs/extattr.h>
  69. #include <ufs/ufs/ufsmount.h>
  70. #include <ufs/ufs/inode.h>
  71. #include <ufs/ufs/ufs_bswap.h>
  72. #include <ufs/ufs/ufs_extern.h>
  73. static MALLOC_JUSTDEFINE(M_UFS_EXTATTR, "ufs_extattr","ufs extended attribute");
  74. int ufs_extattr_sync = 1;
  75. int ufs_extattr_autocreate = 1024;
  76. static int ufs_extattr_valid_attrname(int attrnamespace,
  77. const char *attrname);
  78. static int ufs_extattr_enable_with_open(struct ufsmount *ump,
  79. struct vnode *vp, int attrnamespace, const char *attrname,
  80. struct lwp *l);
  81. static int ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
  82. const char *attrname, struct vnode *backing_vnode,
  83. struct lwp *l);
  84. static int ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
  85. const char *attrname, struct lwp *l);
  86. static int ufs_extattr_get(struct vnode *vp, int attrnamespace,
  87. const char *name, struct uio *uio, size_t *size,
  88. kauth_cred_t cred, struct lwp *l);
  89. static int ufs_extattr_list(struct vnode *vp, int attrnamespace,
  90. struct uio *uio, size_t *size, int flag,
  91. kauth_cred_t cred, struct lwp *l);
  92. static int ufs_extattr_set(struct vnode *vp, int attrnamespace,
  93. const char *name, struct uio *uio, kauth_cred_t cred,
  94. struct lwp *l);
  95. static int ufs_extattr_rm(struct vnode *vp, int attrnamespace,
  96. const char *name, kauth_cred_t cred, struct lwp *l);
  97. static struct ufs_extattr_list_entry *ufs_extattr_find_attr(struct ufsmount *,
  98. int, const char *);
  99. static int ufs_extattr_get_header(struct vnode *,
  100. struct ufs_extattr_list_entry *,
  101. struct ufs_extattr_header *, off_t *);
  102. /*
  103. * Per-FS attribute lock protecting attribute operations.
  104. * XXX Right now there is a lot of lock contention due to having a single
  105. * lock per-FS; really, this should be far more fine-grained.
  106. */
  107. static void
  108. ufs_extattr_uepm_lock(struct ufsmount *ump)
  109. {
  110. /* XXX Why does this need to be recursive? */
  111. if (mutex_owned(&ump->um_extattr.uepm_lock)) {
  112. ump->um_extattr.uepm_lockcnt++;
  113. return;
  114. }
  115. mutex_enter(&ump->um_extattr.uepm_lock);
  116. }
  117. static void
  118. ufs_extattr_uepm_unlock(struct ufsmount *ump)
  119. {
  120. if (ump->um_extattr.uepm_lockcnt != 0) {
  121. KASSERT(mutex_owned(&ump->um_extattr.uepm_lock));
  122. ump->um_extattr.uepm_lockcnt--;
  123. return;
  124. }
  125. mutex_exit(&ump->um_extattr.uepm_lock);
  126. }
  127. /*-
  128. * Determine whether the name passed is a valid name for an actual
  129. * attribute.
  130. *
  131. * Invalid currently consists of:
  132. * NULL pointer for attrname
  133. * zero-length attrname (used to retrieve application attribute list)
  134. */
  135. static int
  136. ufs_extattr_valid_attrname(int attrnamespace, const char *attrname)
  137. {
  138. if (attrname == NULL)
  139. return (0);
  140. if (strlen(attrname) == 0)
  141. return (0);
  142. return (1);
  143. }
  144. /*
  145. * Autocreate an attribute storage
  146. */
  147. static struct ufs_extattr_list_entry *
  148. ufs_extattr_autocreate_attr(struct vnode *vp, int attrnamespace,
  149. const char *attrname, struct lwp *l)
  150. {
  151. struct mount *mp = vp->v_mount;
  152. struct ufsmount *ump = VFSTOUFS(mp);
  153. struct vnode *backing_vp;
  154. struct nameidata nd;
  155. struct pathbuf *pb;
  156. char *path;
  157. struct ufs_extattr_fileheader uef;
  158. struct ufs_extattr_list_entry *uele;
  159. int error;
  160. path = PNBUF_GET();
  161. /*
  162. * We only support system and user namespace autocreation
  163. */
  164. switch (attrnamespace) {
  165. case EXTATTR_NAMESPACE_SYSTEM:
  166. (void)snprintf(path, PATH_MAX, "%s/%s/%s/%s",
  167. mp->mnt_stat.f_mntonname,
  168. UFS_EXTATTR_FSROOTSUBDIR,
  169. UFS_EXTATTR_SUBDIR_SYSTEM,
  170. attrname);
  171. break;
  172. case EXTATTR_NAMESPACE_USER:
  173. (void)snprintf(path, PATH_MAX, "%s/%s/%s/%s",
  174. mp->mnt_stat.f_mntonname,
  175. UFS_EXTATTR_FSROOTSUBDIR,
  176. UFS_EXTATTR_SUBDIR_USER,
  177. attrname);
  178. break;
  179. default:
  180. PNBUF_PUT(path);
  181. return NULL;
  182. break;
  183. }
  184. /*
  185. * When setting attribute on the root vnode, we get it
  186. * already locked, and vn_open/namei/VFS_ROOT will try to
  187. * look it, causing a panic. Unlock it first.
  188. */
  189. if (vp->v_vflag && VV_ROOT) {
  190. KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
  191. VOP_UNLOCK(vp);
  192. }
  193. KASSERT(VOP_ISLOCKED(vp) == 0);
  194. pb = pathbuf_create(path);
  195. NDINIT(&nd, CREATE, LOCKPARENT, pb);
  196. error = vn_open(&nd, O_CREAT|O_RDWR, 0600);
  197. /*
  198. * Reacquire the lock on the vnode if it was root.
  199. */
  200. KASSERT(VOP_ISLOCKED(vp) == 0);
  201. if (vp->v_vflag && VV_ROOT)
  202. vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  203. KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
  204. if (error != 0) {
  205. pathbuf_destroy(pb);
  206. PNBUF_PUT(path);
  207. return NULL;
  208. }
  209. KASSERT(nd.ni_vp != NULL);
  210. KASSERT(VOP_ISLOCKED(nd.ni_vp) == LK_EXCLUSIVE);
  211. KASSERT(VOP_ISLOCKED(nd.ni_dvp) == 0);
  212. /*
  213. * backing_vp is the backing store.
  214. */
  215. backing_vp = nd.ni_vp;
  216. pathbuf_destroy(pb);
  217. PNBUF_PUT(path);
  218. uef.uef_magic = UFS_EXTATTR_MAGIC;
  219. uef.uef_version = UFS_EXTATTR_VERSION;
  220. uef.uef_size = ufs_extattr_autocreate;
  221. error = vn_rdwr(UIO_WRITE, backing_vp, &uef, sizeof(uef), 0,
  222. UIO_SYSSPACE, IO_NODELOCKED|IO_APPEND,
  223. l->l_cred, NULL, l);
  224. VOP_UNLOCK(backing_vp);
  225. if (error != 0) {
  226. printf("%s: write uef header failed for %s, error = %d\n",
  227. __func__, attrname, error);
  228. vn_close(backing_vp, FREAD|FWRITE, l->l_cred);
  229. return NULL;
  230. }
  231. /*
  232. * ufs_extattr_enable_with_open increases the vnode reference
  233. * count. Not sure why, but do the same here.
  234. */
  235. vref(vp);
  236. /*
  237. * Now enable attribute.
  238. */
  239. error = ufs_extattr_enable(ump,attrnamespace, attrname, backing_vp, l);
  240. KASSERT(VOP_ISLOCKED(backing_vp) == 0);
  241. if (error != 0) {
  242. printf("%s: enable %s failed, error %d\n",
  243. __func__, attrname, error);
  244. vn_close(backing_vp, FREAD|FWRITE, l->l_cred);
  245. return NULL;
  246. }
  247. uele = ufs_extattr_find_attr(ump, attrnamespace, attrname);
  248. if (uele == NULL) {
  249. printf("%s: atttribute %s created but not found!\n",
  250. __func__, attrname);
  251. vn_close(backing_vp, FREAD|FWRITE, l->l_cred);
  252. return NULL;
  253. }
  254. printf("%s: EA backing store autocreated for %s\n",
  255. mp->mnt_stat.f_mntonname, attrname);
  256. return uele;
  257. }
  258. /*
  259. * Locate an attribute given a name and mountpoint.
  260. * Must be holding uepm lock for the mount point.
  261. */
  262. static struct ufs_extattr_list_entry *
  263. ufs_extattr_find_attr(struct ufsmount *ump, int attrnamespace,
  264. const char *attrname)
  265. {
  266. struct ufs_extattr_list_entry *search_attribute;
  267. for (search_attribute = LIST_FIRST(&ump->um_extattr.uepm_list);
  268. search_attribute != NULL;
  269. search_attribute = LIST_NEXT(search_attribute, uele_entries)) {
  270. if (!(strncmp(attrname, search_attribute->uele_attrname,
  271. UFS_EXTATTR_MAXEXTATTRNAME)) &&
  272. (attrnamespace == search_attribute->uele_attrnamespace)) {
  273. return (search_attribute);
  274. }
  275. }
  276. return (0);
  277. }
  278. /*
  279. * Initialize per-FS structures supporting extended attributes. Do not
  280. * start extended attributes yet.
  281. */
  282. void
  283. ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm)
  284. {
  285. uepm->uepm_flags = 0;
  286. uepm->uepm_lockcnt = 0;
  287. LIST_INIT(&uepm->uepm_list);
  288. mutex_init(&uepm->uepm_lock, MUTEX_DEFAULT, IPL_NONE);
  289. uepm->uepm_flags |= UFS_EXTATTR_UEPM_INITIALIZED;
  290. }
  291. /*
  292. * Destroy per-FS structures supporting extended attributes. Assumes
  293. * that EAs have already been stopped, and will panic if not.
  294. */
  295. void
  296. ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm)
  297. {
  298. if (!(uepm->uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
  299. panic("ufs_extattr_uepm_destroy: not initialized");
  300. if ((uepm->uepm_flags & UFS_EXTATTR_UEPM_STARTED))
  301. panic("ufs_extattr_uepm_destroy: called while still started");
  302. /*
  303. * It's not clear that either order for the next two lines is
  304. * ideal, and it should never be a problem if this is only called
  305. * during unmount, and with vfs_busy().
  306. */
  307. uepm->uepm_flags &= ~UFS_EXTATTR_UEPM_INITIALIZED;
  308. mutex_destroy(&uepm->uepm_lock);
  309. }
  310. /*
  311. * Start extended attribute support on an FS.
  312. */
  313. int
  314. ufs_extattr_start(struct mount *mp, struct lwp *l)
  315. {
  316. struct ufsmount *ump;
  317. int error = 0;
  318. ump = VFSTOUFS(mp);
  319. ufs_extattr_uepm_lock(ump);
  320. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)) {
  321. error = EOPNOTSUPP;
  322. goto unlock;
  323. }
  324. if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED) {
  325. error = EBUSY;
  326. goto unlock;
  327. }
  328. ump->um_extattr.uepm_flags |= UFS_EXTATTR_UEPM_STARTED;
  329. ump->um_extattr.uepm_ucred = l->l_cred;
  330. kauth_cred_hold(ump->um_extattr.uepm_ucred);
  331. unlock:
  332. ufs_extattr_uepm_unlock(ump);
  333. return (error);
  334. }
  335. /*
  336. * Helper routine: given a locked parent directory and filename, return
  337. * the locked vnode of the inode associated with the name. Will not
  338. * follow symlinks, may return any type of vnode. Lock on parent will
  339. * be released even in the event of a failure. In the event that the
  340. * target is the parent (i.e., "."), there will be two references and
  341. * one lock, requiring the caller to possibly special-case.
  342. */
  343. static int
  344. ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, const char *dirname,
  345. struct vnode **vp, struct lwp *l)
  346. {
  347. struct vop_lookup_args vargs;
  348. struct componentname cnp;
  349. struct vnode *target_vp;
  350. char *pnbuf;
  351. int error;
  352. KASSERT(VOP_ISLOCKED(start_dvp) == LK_EXCLUSIVE);
  353. pnbuf = PNBUF_GET();
  354. memset(&cnp, 0, sizeof(cnp));
  355. cnp.cn_nameiop = LOOKUP;
  356. cnp.cn_flags = ISLASTCN | lockparent;
  357. cnp.cn_cred = l->l_cred;
  358. cnp.cn_nameptr = pnbuf;
  359. error = copystr(dirname, pnbuf, MAXPATHLEN, &cnp.cn_namelen);
  360. if (error) {
  361. if (lockparent == 0) {
  362. VOP_UNLOCK(start_dvp);
  363. }
  364. PNBUF_PUT(pnbuf);
  365. printf("ufs_extattr_lookup: copystr failed\n");
  366. return (error);
  367. }
  368. cnp.cn_namelen--; /* trim nul termination */
  369. vargs.a_desc = NULL;
  370. vargs.a_dvp = start_dvp;
  371. vargs.a_vpp = &target_vp;
  372. vargs.a_cnp = &cnp;
  373. error = ufs_lookup(&vargs);
  374. PNBUF_PUT(pnbuf);
  375. if (error) {
  376. if (lockparent == 0) {
  377. VOP_UNLOCK(start_dvp);
  378. }
  379. return (error);
  380. }
  381. #if 0
  382. if (target_vp == start_dvp)
  383. panic("ufs_extattr_lookup: target_vp == start_dvp");
  384. #endif
  385. if ((target_vp != start_dvp) && (lockparent == 0))
  386. VOP_UNLOCK(start_dvp);
  387. KASSERT(VOP_ISLOCKED(target_vp) == LK_EXCLUSIVE);
  388. *vp = target_vp;
  389. return (0);
  390. }
  391. /*
  392. * Enable an EA using the passed filesystem, backing vnode, attribute name,
  393. * namespace, and proc. Will perform a VOP_OPEN() on the vp, so expects vp
  394. * to be locked when passed in. The vnode will be returned unlocked,
  395. * regardless of success/failure of the function. As a result, the caller
  396. * will always need to vrele(), but not vput().
  397. */
  398. static int
  399. ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp,
  400. int attrnamespace, const char *attrname, struct lwp *l)
  401. {
  402. int error;
  403. error = VOP_OPEN(vp, FREAD|FWRITE, l->l_cred);
  404. if (error) {
  405. printf("ufs_extattr_enable_with_open.VOP_OPEN(): failed "
  406. "with %d\n", error);
  407. VOP_UNLOCK(vp);
  408. return (error);
  409. }
  410. mutex_enter(vp->v_interlock);
  411. vp->v_writecount++;
  412. mutex_exit(vp->v_interlock);
  413. vref(vp);
  414. VOP_UNLOCK(vp);
  415. error = ufs_extattr_enable(ump, attrnamespace, attrname, vp, l);
  416. if (error != 0)
  417. vn_close(vp, FREAD|FWRITE, l->l_cred);
  418. return (error);
  419. }
  420. /*
  421. * Given a locked directory vnode, iterate over the names in the directory
  422. * and use ufs_extattr_lookup() to retrieve locked vnodes of potential
  423. * attribute files. Then invoke ufs_extattr_enable_with_open() on each
  424. * to attempt to start the attribute. Leaves the directory locked on
  425. * exit.
  426. */
  427. static int
  428. ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp,
  429. int attrnamespace, struct lwp *l)
  430. {
  431. struct vop_readdir_args vargs;
  432. struct statvfs *sbp = &ump->um_mountp->mnt_stat;
  433. struct dirent *dp, *edp;
  434. struct vnode *attr_vp;
  435. struct uio auio;
  436. struct iovec aiov;
  437. char *dirbuf;
  438. int error, eofflag = 0;
  439. if (dvp->v_type != VDIR)
  440. return (ENOTDIR);
  441. dirbuf = malloc(DIRBLKSIZ, M_TEMP, M_WAITOK);
  442. auio.uio_iov = &aiov;
  443. auio.uio_iovcnt = 1;
  444. auio.uio_rw = UIO_READ;
  445. auio.uio_offset = 0;
  446. UIO_SETUP_SYSSPACE(&auio);
  447. vargs.a_desc = NULL;
  448. vargs.a_vp = dvp;
  449. vargs.a_uio = &auio;
  450. vargs.a_cred = l->l_cred;
  451. vargs.a_eofflag = &eofflag;
  452. vargs.a_ncookies = NULL;
  453. vargs.a_cookies = NULL;
  454. while (!eofflag) {
  455. auio.uio_resid = DIRBLKSIZ;
  456. aiov.iov_base = dirbuf;
  457. aiov.iov_len = DIRBLKSIZ;
  458. error = ufs_readdir(&vargs);
  459. if (error) {
  460. printf("ufs_extattr_iterate_directory: ufs_readdir "
  461. "%d\n", error);
  462. return (error);
  463. }
  464. /*
  465. * XXXRW: While in UFS, we always get DIRBLKSIZ returns from
  466. * the directory code on success, on other file systems this
  467. * may not be the case. For portability, we should check the
  468. * read length on return from ufs_readdir().
  469. */
  470. edp = (struct dirent *)&dirbuf[DIRBLKSIZ];
  471. for (dp = (struct dirent *)dirbuf; dp < edp; ) {
  472. if (dp->d_reclen == 0)
  473. break;
  474. /* Skip "." and ".." */
  475. if (dp->d_name[0] == '.' &&
  476. (dp->d_name[1] == '\0' ||
  477. (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
  478. goto next;
  479. error = ufs_extattr_lookup(dvp, LOCKPARENT,
  480. dp->d_name, &attr_vp, l);
  481. if (error == ENOENT) {
  482. goto next; /* keep silent */
  483. } else if (error) {
  484. printf("ufs_extattr_iterate_directory: lookup "
  485. "%s %d\n", dp->d_name, error);
  486. } else if (attr_vp == dvp) {
  487. vrele(attr_vp);
  488. } else if (attr_vp->v_type != VREG) {
  489. vput(attr_vp);
  490. } else {
  491. error = ufs_extattr_enable_with_open(ump,
  492. attr_vp, attrnamespace, dp->d_name, l);
  493. vrele(attr_vp);
  494. if (error) {
  495. printf("ufs_extattr_iterate_directory: "
  496. "enable %s %d\n", dp->d_name,
  497. error);
  498. } else if (bootverbose) {
  499. printf("%s: EA %s loaded\n",
  500. sbp->f_mntonname, dp->d_name);
  501. }
  502. }
  503. next:
  504. dp = (struct dirent *) ((char *)dp + dp->d_reclen);
  505. if (dp >= edp)
  506. break;
  507. }
  508. }
  509. free(dirbuf, M_TEMP);
  510. return (0);
  511. }
  512. /*
  513. * Auto-start of extended attributes, to be executed (optionally) at
  514. * mount-time.
  515. */
  516. int
  517. ufs_extattr_autostart(struct mount *mp, struct lwp *l)
  518. {
  519. struct vnode *rvp, *attr_dvp, *attr_system_dvp, *attr_user_dvp;
  520. int error;
  521. /*
  522. * Does UFS_EXTATTR_FSROOTSUBDIR exist off the filesystem root?
  523. * If so, automatically start EA's.
  524. */
  525. error = VFS_ROOT(mp, &rvp);
  526. if (error) {
  527. printf("ufs_extattr_autostart.VFS_ROOT() returned %d\n",
  528. error);
  529. return (error);
  530. }
  531. KASSERT(VOP_ISLOCKED(rvp) == LK_EXCLUSIVE);
  532. error = ufs_extattr_lookup(rvp, 0,
  533. UFS_EXTATTR_FSROOTSUBDIR, &attr_dvp, l);
  534. if (error) {
  535. /* rvp ref'd but now unlocked */
  536. KASSERT(VOP_ISLOCKED(rvp) == 0);
  537. vrele(rvp);
  538. return (error);
  539. }
  540. if (rvp == attr_dvp) {
  541. /* Should never happen. */
  542. KASSERT(VOP_ISLOCKED(rvp) == LK_EXCLUSIVE);
  543. vrele(attr_dvp);
  544. vput(rvp);
  545. return (EINVAL);
  546. }
  547. KASSERT(VOP_ISLOCKED(rvp) == 0);
  548. vrele(rvp);
  549. KASSERT(VOP_ISLOCKED(attr_dvp) == LK_EXCLUSIVE);
  550. if (attr_dvp->v_type != VDIR) {
  551. printf("ufs_extattr_autostart: %s != VDIR\n",
  552. UFS_EXTATTR_FSROOTSUBDIR);
  553. goto return_vput_attr_dvp;
  554. }
  555. error = ufs_extattr_start(mp, l);
  556. if (error) {
  557. printf("ufs_extattr_autostart: ufs_extattr_start failed (%d)\n",
  558. error);
  559. goto return_vput_attr_dvp;
  560. }
  561. /*
  562. * Look for two subdirectories: UFS_EXTATTR_SUBDIR_SYSTEM,
  563. * UFS_EXTATTR_SUBDIR_USER. For each, iterate over the sub-directory,
  564. * and start with appropriate type. Failures in either don't
  565. * result in an over-all failure. attr_dvp is left locked to
  566. * be cleaned up on exit.
  567. */
  568. error = ufs_extattr_lookup(attr_dvp, LOCKPARENT,
  569. UFS_EXTATTR_SUBDIR_SYSTEM, &attr_system_dvp, l);
  570. KASSERT(VOP_ISLOCKED(attr_dvp) == LK_EXCLUSIVE);
  571. if (error == 0) {
  572. KASSERT(VOP_ISLOCKED(attr_system_dvp) == LK_EXCLUSIVE);
  573. error = ufs_extattr_iterate_directory(VFSTOUFS(mp),
  574. attr_system_dvp, EXTATTR_NAMESPACE_SYSTEM, l);
  575. if (error)
  576. printf("ufs_extattr_iterate_directory returned %d\n",
  577. error);
  578. KASSERT(VOP_ISLOCKED(attr_system_dvp) == LK_EXCLUSIVE);
  579. vput(attr_system_dvp);
  580. }
  581. error = ufs_extattr_lookup(attr_dvp, LOCKPARENT,
  582. UFS_EXTATTR_SUBDIR_USER, &attr_user_dvp, l);
  583. KASSERT(VOP_ISLOCKED(attr_dvp) == LK_EXCLUSIVE);
  584. if (error == 0) {
  585. KASSERT(VOP_ISLOCKED(attr_user_dvp) == LK_EXCLUSIVE);
  586. error = ufs_extattr_iterate_directory(VFSTOUFS(mp),
  587. attr_user_dvp, EXTATTR_NAMESPACE_USER, l);
  588. if (error)
  589. printf("ufs_extattr_iterate_directory returned %d\n",
  590. error);
  591. KASSERT(VOP_ISLOCKED(attr_user_dvp) == LK_EXCLUSIVE);
  592. vput(attr_user_dvp);
  593. }
  594. /* Mask startup failures in sub-directories. */
  595. error = 0;
  596. return_vput_attr_dvp:
  597. KASSERT(VOP_ISLOCKED(attr_dvp) == LK_EXCLUSIVE);
  598. vput(attr_dvp);
  599. return (error);
  600. }
  601. /*
  602. * Stop extended attribute support on an FS.
  603. */
  604. void
  605. ufs_extattr_stop(struct mount *mp, struct lwp *l)
  606. {
  607. struct ufs_extattr_list_entry *uele;
  608. struct ufsmount *ump = VFSTOUFS(mp);
  609. ufs_extattr_uepm_lock(ump);
  610. /*
  611. * If we haven't been started, no big deal. Just short-circuit
  612. * the processing work.
  613. */
  614. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
  615. goto unlock;
  616. }
  617. while (LIST_FIRST(&ump->um_extattr.uepm_list) != NULL) {
  618. uele = LIST_FIRST(&ump->um_extattr.uepm_list);
  619. ufs_extattr_disable(ump, uele->uele_attrnamespace,
  620. uele->uele_attrname, l);
  621. }
  622. ump->um_extattr.uepm_flags &= ~UFS_EXTATTR_UEPM_STARTED;
  623. kauth_cred_free(ump->um_extattr.uepm_ucred);
  624. ump->um_extattr.uepm_ucred = NULL;
  625. unlock:
  626. ufs_extattr_uepm_unlock(ump);
  627. }
  628. /*
  629. * Enable a named attribute on the specified filesystem; provide an
  630. * unlocked backing vnode to hold the attribute data.
  631. */
  632. static int
  633. ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
  634. const char *attrname, struct vnode *backing_vnode, struct lwp *l)
  635. {
  636. struct ufs_extattr_list_entry *attribute;
  637. struct iovec aiov;
  638. struct uio auio;
  639. int error = 0;
  640. if (!ufs_extattr_valid_attrname(attrnamespace, attrname))
  641. return (EINVAL);
  642. if (backing_vnode->v_type != VREG)
  643. return (EINVAL);
  644. attribute = malloc(sizeof(*attribute), M_UFS_EXTATTR,
  645. M_WAITOK | M_ZERO);
  646. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
  647. error = EOPNOTSUPP;
  648. goto free_exit;
  649. }
  650. if (ufs_extattr_find_attr(ump, attrnamespace, attrname)) {
  651. error = EEXIST;
  652. goto free_exit;
  653. }
  654. strncpy(attribute->uele_attrname, attrname,
  655. UFS_EXTATTR_MAXEXTATTRNAME);
  656. attribute->uele_attrnamespace = attrnamespace;
  657. memset(&attribute->uele_fileheader, 0,
  658. sizeof(struct ufs_extattr_fileheader));
  659. attribute->uele_backing_vnode = backing_vnode;
  660. auio.uio_iov = &aiov;
  661. auio.uio_iovcnt = 1;
  662. aiov.iov_base = (void *) &attribute->uele_fileheader;
  663. aiov.iov_len = sizeof(struct ufs_extattr_fileheader);
  664. auio.uio_resid = sizeof(struct ufs_extattr_fileheader);
  665. auio.uio_offset = (off_t) 0;
  666. auio.uio_rw = UIO_READ;
  667. UIO_SETUP_SYSSPACE(&auio);
  668. vn_lock(backing_vnode, LK_SHARED | LK_RETRY);
  669. error = VOP_READ(backing_vnode, &auio, IO_NODELOCKED,
  670. ump->um_extattr.uepm_ucred);
  671. if (error)
  672. goto unlock_free_exit;
  673. if (auio.uio_resid != 0) {
  674. printf("ufs_extattr_enable: malformed attribute header\n");
  675. error = EINVAL;
  676. goto unlock_free_exit;
  677. }
  678. /*
  679. * Try to determine the byte order of the attribute file.
  680. */
  681. if (attribute->uele_fileheader.uef_magic != UFS_EXTATTR_MAGIC) {
  682. attribute->uele_flags |= UELE_F_NEEDSWAP;
  683. attribute->uele_fileheader.uef_magic =
  684. ufs_rw32(attribute->uele_fileheader.uef_magic,
  685. UELE_NEEDSWAP(attribute));
  686. if (attribute->uele_fileheader.uef_magic != UFS_EXTATTR_MAGIC) {
  687. printf("ufs_extattr_enable: invalid attribute header "
  688. "magic\n");
  689. error = EINVAL;
  690. goto unlock_free_exit;
  691. }
  692. }
  693. attribute->uele_fileheader.uef_version =
  694. ufs_rw32(attribute->uele_fileheader.uef_version,
  695. UELE_NEEDSWAP(attribute));
  696. attribute->uele_fileheader.uef_size =
  697. ufs_rw32(attribute->uele_fileheader.uef_size,
  698. UELE_NEEDSWAP(attribute));
  699. if (attribute->uele_fileheader.uef_version != UFS_EXTATTR_VERSION) {
  700. printf("ufs_extattr_enable: incorrect attribute header "
  701. "version\n");
  702. error = EINVAL;
  703. goto unlock_free_exit;
  704. }
  705. LIST_INSERT_HEAD(&ump->um_extattr.uepm_list, attribute,
  706. uele_entries);
  707. VOP_UNLOCK(backing_vnode);
  708. return (0);
  709. unlock_free_exit:
  710. VOP_UNLOCK(backing_vnode);
  711. free_exit:
  712. free(attribute, M_UFS_EXTATTR);
  713. return (error);
  714. }
  715. /*
  716. * Disable extended attribute support on an FS.
  717. */
  718. static int
  719. ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
  720. const char *attrname, struct lwp *l)
  721. {
  722. struct ufs_extattr_list_entry *uele;
  723. int error = 0;
  724. if (!ufs_extattr_valid_attrname(attrnamespace, attrname))
  725. return (EINVAL);
  726. uele = ufs_extattr_find_attr(ump, attrnamespace, attrname);
  727. if (!uele)
  728. return (ENOATTR);
  729. LIST_REMOVE(uele, uele_entries);
  730. error = vn_close(uele->uele_backing_vnode, FREAD|FWRITE,
  731. l->l_cred);
  732. free(uele, M_UFS_EXTATTR);
  733. return (error);
  734. }
  735. /*
  736. * VFS call to manage extended attributes in UFS. If filename_vp is
  737. * non-NULL, it must be passed in locked, and regardless of errors in
  738. * processing, will be unlocked.
  739. */
  740. int
  741. ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
  742. int attrnamespace, const char *attrname)
  743. {
  744. struct lwp *l = curlwp;
  745. struct ufsmount *ump = VFSTOUFS(mp);
  746. int error;
  747. /*
  748. * Only privileged processes can configure extended attributes.
  749. */
  750. if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
  751. NULL)) != 0) {
  752. if (filename_vp != NULL)
  753. VOP_UNLOCK(filename_vp);
  754. return (error);
  755. }
  756. switch(cmd) {
  757. case UFS_EXTATTR_CMD_START:
  758. if (filename_vp != NULL) {
  759. VOP_UNLOCK(filename_vp);
  760. return (EINVAL);
  761. }
  762. if (attrname != NULL)
  763. return (EINVAL);
  764. error = ufs_extattr_autostart(mp, l);
  765. return (error);
  766. case UFS_EXTATTR_CMD_STOP:
  767. if (filename_vp != NULL) {
  768. VOP_UNLOCK(filename_vp);
  769. return (EINVAL);
  770. }
  771. if (attrname != NULL)
  772. return (EINVAL);
  773. ufs_extattr_stop(mp, l);
  774. return (0);
  775. case UFS_EXTATTR_CMD_ENABLE:
  776. if (filename_vp == NULL)
  777. return (EINVAL);
  778. if (attrname == NULL) {
  779. VOP_UNLOCK(filename_vp);
  780. return (EINVAL);
  781. }
  782. /*
  783. * ufs_extattr_enable_with_open() will always unlock the
  784. * vnode, regardless of failure.
  785. */
  786. ufs_extattr_uepm_lock(ump);
  787. error = ufs_extattr_enable_with_open(ump, filename_vp,
  788. attrnamespace, attrname, l);
  789. ufs_extattr_uepm_unlock(ump);
  790. return (error);
  791. case UFS_EXTATTR_CMD_DISABLE:
  792. if (filename_vp != NULL) {
  793. VOP_UNLOCK(filename_vp);
  794. return (EINVAL);
  795. }
  796. if (attrname == NULL)
  797. return (EINVAL);
  798. ufs_extattr_uepm_lock(ump);
  799. error = ufs_extattr_disable(ump, attrnamespace, attrname, l);
  800. ufs_extattr_uepm_unlock(ump);
  801. return (error);
  802. default:
  803. return (EINVAL);
  804. }
  805. }
  806. /*
  807. * Read extended attribute header for a given vnode and attribute.
  808. * Backing vnode should be locked and unlocked by caller.
  809. */
  810. static int
  811. ufs_extattr_get_header(struct vnode *vp, struct ufs_extattr_list_entry *uele,
  812. struct ufs_extattr_header *ueh, off_t *bap)
  813. {
  814. struct mount *mp = vp->v_mount;
  815. struct ufsmount *ump = VFSTOUFS(mp);
  816. struct inode *ip = VTOI(vp);
  817. off_t base_offset;
  818. struct iovec aiov;
  819. struct uio aio;
  820. int error;
  821. /*
  822. * Find base offset of header in file based on file header size, and
  823. * data header size + maximum data size, indexed by inode number.
  824. */
  825. base_offset = sizeof(struct ufs_extattr_fileheader) +
  826. ip->i_number * (sizeof(struct ufs_extattr_header) +
  827. uele->uele_fileheader.uef_size);
  828. /*
  829. * Read in the data header to see if the data is defined, and if so
  830. * how much.
  831. */
  832. memset(ueh, 0, sizeof(struct ufs_extattr_header));
  833. aiov.iov_base = ueh;
  834. aiov.iov_len = sizeof(struct ufs_extattr_header);
  835. aio.uio_iov = &aiov;
  836. aio.uio_iovcnt = 1;
  837. aio.uio_rw = UIO_READ;
  838. aio.uio_offset = base_offset;
  839. aio.uio_resid = sizeof(struct ufs_extattr_header);
  840. UIO_SETUP_SYSSPACE(&aio);
  841. error = VOP_READ(uele->uele_backing_vnode, &aio,
  842. IO_NODELOCKED, ump->um_extattr.uepm_ucred);
  843. if (error)
  844. return error;
  845. /*
  846. * Attribute headers are kept in file system byte order.
  847. * XXX What about the blob of data?
  848. */
  849. ueh->ueh_flags = ufs_rw32(ueh->ueh_flags, UELE_NEEDSWAP(uele));
  850. ueh->ueh_len = ufs_rw32(ueh->ueh_len, UELE_NEEDSWAP(uele));
  851. ueh->ueh_i_gen = ufs_rw32(ueh->ueh_i_gen, UELE_NEEDSWAP(uele));
  852. /* Defined? */
  853. if ((ueh->ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0)
  854. return ENOATTR;
  855. /* Valid for the current inode generation? */
  856. if (ueh->ueh_i_gen != ip->i_gen) {
  857. /*
  858. * The inode itself has a different generation number
  859. * than the uele data. For now, the best solution
  860. * is to coerce this to undefined, and let it get cleaned
  861. * up by the next write or extattrctl clean.
  862. */
  863. printf("%s (%s): inode gen inconsistency (%u, %jd)\n",
  864. __func__, mp->mnt_stat.f_mntonname, ueh->ueh_i_gen,
  865. (intmax_t)ip->i_gen);
  866. return ENOATTR;
  867. }
  868. /* Local size consistency check. */
  869. if (ueh->ueh_len > uele->uele_fileheader.uef_size)
  870. return ENXIO;
  871. /* Return base offset */
  872. if (bap != NULL)
  873. *bap = base_offset;
  874. return 0;
  875. }
  876. /*
  877. * Vnode operation to retrieve a named extended attribute.
  878. */
  879. int
  880. ufs_getextattr(struct vop_getextattr_args *ap)
  881. /*
  882. vop_getextattr {
  883. IN struct vnode *a_vp;
  884. IN int a_attrnamespace;
  885. IN const char *a_name;
  886. INOUT struct uio *a_uio;
  887. OUT size_t *a_size;
  888. IN kauth_cred_t a_cred;
  889. };
  890. */
  891. {
  892. struct mount *mp = ap->a_vp->v_mount;
  893. struct ufsmount *ump = VFSTOUFS(mp);
  894. int error;
  895. ufs_extattr_uepm_lock(ump);
  896. error = ufs_extattr_get(ap->a_vp, ap->a_attrnamespace, ap->a_name,
  897. ap->a_uio, ap->a_size, ap->a_cred, curlwp);
  898. ufs_extattr_uepm_unlock(ump);
  899. return (error);
  900. }
  901. /*
  902. * Real work associated with retrieving a named attribute--assumes that
  903. * the attribute lock has already been grabbed.
  904. */
  905. static int
  906. ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
  907. struct uio *uio, size_t *size, kauth_cred_t cred, struct lwp *l)
  908. {
  909. struct ufs_extattr_list_entry *attribute;
  910. struct ufs_extattr_header ueh;
  911. struct mount *mp = vp->v_mount;
  912. struct ufsmount *ump = VFSTOUFS(mp);
  913. off_t base_offset;
  914. size_t len, old_len;
  915. int error = 0;
  916. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
  917. return (EOPNOTSUPP);
  918. if (strlen(name) == 0)
  919. return (EINVAL);
  920. error = extattr_check_cred(vp, attrnamespace, cred, l, IREAD);
  921. if (error)
  922. return (error);
  923. attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
  924. if (!attribute)
  925. return (ENOATTR);
  926. /*
  927. * Allow only offsets of zero to encourage the read/replace
  928. * extended attribute semantic. Otherwise we can't guarantee
  929. * atomicity, as we don't provide locks for extended attributes.
  930. */
  931. if (uio != NULL && uio->uio_offset != 0)
  932. return (ENXIO);
  933. /*
  934. * Don't need to get a lock on the backing file if the getattr is
  935. * being applied to the backing file, as the lock is already held.
  936. */
  937. if (attribute->uele_backing_vnode != vp)
  938. vn_lock(attribute->uele_backing_vnode, LK_SHARED | LK_RETRY);
  939. error = ufs_extattr_get_header(vp, attribute, &ueh, &base_offset);
  940. if (error)
  941. goto vopunlock_exit;
  942. /* Return full data size if caller requested it. */
  943. if (size != NULL)
  944. *size = ueh.ueh_len;
  945. /* Return data if the caller requested it. */
  946. if (uio != NULL) {
  947. /* Allow for offset into the attribute data. */
  948. uio->uio_offset = base_offset + sizeof(struct
  949. ufs_extattr_header);
  950. /*
  951. * Figure out maximum to transfer -- use buffer size and
  952. * local data limit.
  953. */
  954. len = MIN(uio->uio_resid, ueh.ueh_len);
  955. old_len = uio->uio_resid;
  956. uio->uio_resid = len;
  957. error = VOP_READ(attribute->uele_backing_vnode, uio,
  958. IO_NODELOCKED, ump->um_extattr.uepm_ucred);
  959. if (error)
  960. goto vopunlock_exit;
  961. uio->uio_resid = old_len - (len - uio->uio_resid);
  962. }
  963. vopunlock_exit:
  964. if (uio != NULL)
  965. uio->uio_offset = 0;
  966. if (attribute->uele_backing_vnode != vp)
  967. VOP_UNLOCK(attribute->uele_backing_vnode);
  968. return (error);
  969. }
  970. /*
  971. * Vnode operation to list extended attribute for a vnode
  972. */
  973. int
  974. ufs_listextattr(struct vop_listextattr_args *ap)
  975. /*
  976. vop_listextattr {
  977. IN struct vnode *a_vp;
  978. IN int a_attrnamespace;
  979. INOUT struct uio *a_uio;
  980. OUT size_t *a_size;
  981. IN int flag;
  982. IN kauth_cred_t a_cred;
  983. struct proc *a_p;
  984. };
  985. */
  986. {
  987. struct mount *mp = ap->a_vp->v_mount;
  988. struct ufsmount *ump = VFSTOUFS(mp);
  989. int error;
  990. ufs_extattr_uepm_lock(ump);
  991. error = ufs_extattr_list(ap->a_vp, ap->a_attrnamespace,
  992. ap->a_uio, ap->a_size, ap->a_flag, ap->a_cred, curlwp);
  993. ufs_extattr_uepm_unlock(ump);
  994. return (error);
  995. }
  996. /*
  997. * Real work associated with retrieving list of attributes--assumes that
  998. * the attribute lock has already been grabbed.
  999. */
  1000. static int
  1001. ufs_extattr_list(struct vnode *vp, int attrnamespace,
  1002. struct uio *uio, size_t *size, int flag,
  1003. kauth_cred_t cred, struct lwp *l)
  1004. {
  1005. struct ufs_extattr_list_entry *uele;
  1006. struct ufs_extattr_header ueh;
  1007. struct mount *mp = vp->v_mount;
  1008. struct ufsmount *ump = VFSTOUFS(mp);
  1009. size_t listsize = 0;
  1010. int error = 0;
  1011. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
  1012. return (EOPNOTSUPP);
  1013. error = extattr_check_cred(vp, attrnamespace, cred, l, IREAD);
  1014. if (error)
  1015. return (error);
  1016. LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries) {
  1017. unsigned char attrnamelen;
  1018. if (uele->uele_attrnamespace != attrnamespace)
  1019. continue;
  1020. error = ufs_extattr_get_header(vp, uele, &ueh, NULL);
  1021. if (error == ENOATTR)
  1022. continue;
  1023. if (error != 0)
  1024. return error;
  1025. /*
  1026. * Don't need to get a lock on the backing file if
  1027. * the listattr is being applied to the backing file,
  1028. * as the lock is already held.
  1029. */
  1030. if (uele->uele_backing_vnode != vp)
  1031. vn_lock(uele->uele_backing_vnode, LK_SHARED | LK_RETRY);
  1032. /*
  1033. * +1 for trailing NUL (listxattr flavor)
  1034. * or leading name length (extattr_list_file flavor)
  1035. */
  1036. attrnamelen = strlen(uele->uele_attrname);
  1037. listsize += attrnamelen + 1;
  1038. /* Return data if the caller requested it. */
  1039. if (uio != NULL) {
  1040. /*
  1041. * We support two flavors. Either NUL-terminated
  1042. * strings (a la listxattr), or non NUL-terminated,
  1043. * one byte length prefixed strings (for
  1044. * extattr_list_file). EXTATTR_LIST_LENPREFIX switches
  1045. * that second behavior.
  1046. */
  1047. if (flag & EXTATTR_LIST_LENPREFIX) {
  1048. uint8_t len = (uint8_t)attrnamelen;
  1049. /* Copy leading name length */
  1050. error = uiomove(&len, sizeof(len), uio);
  1051. if (error != 0)
  1052. break;
  1053. } else {
  1054. /* Include trailing NULL */
  1055. attrnamelen++;
  1056. }
  1057. error = uiomove(uele->uele_attrname,
  1058. (size_t)attrnamelen, uio);
  1059. if (error != 0)
  1060. break;
  1061. }
  1062. if (uele->uele_backing_vnode != vp)
  1063. VOP_UNLOCK(uele->uele_backing_vnode);
  1064. if (error != 0)
  1065. return error;
  1066. }
  1067. if (uio != NULL)
  1068. uio->uio_offset = 0;
  1069. /* Return full data size if caller requested it. */
  1070. if (size != NULL)
  1071. *size = listsize;
  1072. return 0;
  1073. }
  1074. /*
  1075. * Vnode operation to remove a named attribute.
  1076. */
  1077. int
  1078. ufs_deleteextattr(struct vop_deleteextattr_args *ap)
  1079. /*
  1080. vop_deleteextattr {
  1081. IN struct vnode *a_vp;
  1082. IN int a_attrnamespace;
  1083. IN const char *a_name;
  1084. IN kauth_cred_t a_cred;
  1085. };
  1086. */
  1087. {
  1088. struct mount *mp = ap->a_vp->v_mount;
  1089. struct ufsmount *ump = VFSTOUFS(mp);
  1090. int error;
  1091. ufs_extattr_uepm_lock(ump);
  1092. error = ufs_extattr_rm(ap->a_vp, ap->a_attrnamespace, ap->a_name,
  1093. ap->a_cred, curlwp);
  1094. ufs_extattr_uepm_unlock(ump);
  1095. return (error);
  1096. }
  1097. /*
  1098. * Vnode operation to set a named attribute.
  1099. */
  1100. int
  1101. ufs_setextattr(struct vop_setextattr_args *ap)
  1102. /*
  1103. vop_setextattr {
  1104. IN struct vnode *a_vp;
  1105. IN int a_attrnamespace;
  1106. IN const char *a_name;
  1107. INOUT struct uio *a_uio;
  1108. IN kauth_cred_t a_cred;
  1109. };
  1110. */
  1111. {
  1112. struct mount *mp = ap->a_vp->v_mount;
  1113. struct ufsmount *ump = VFSTOUFS(mp);
  1114. int error;
  1115. ufs_extattr_uepm_lock(ump);
  1116. /*
  1117. * XXX: No longer a supported way to delete extended attributes.
  1118. */
  1119. if (ap->a_uio == NULL) {
  1120. ufs_extattr_uepm_unlock(ump);
  1121. return (EINVAL);
  1122. }
  1123. error = ufs_extattr_set(ap->a_vp, ap->a_attrnamespace, ap->a_name,
  1124. ap->a_uio, ap->a_cred, curlwp);
  1125. ufs_extattr_uepm_unlock(ump);
  1126. return (error);
  1127. }
  1128. /*
  1129. * Real work associated with setting a vnode's extended attributes;
  1130. * assumes that the attribute lock has already been grabbed.
  1131. */
  1132. static int
  1133. ufs_extattr_set(struct vnode *vp, int attrnamespace, const char *name,
  1134. struct uio *uio, kauth_cred_t cred, struct lwp *l)
  1135. {
  1136. struct ufs_extattr_list_entry *attribute;
  1137. struct ufs_extattr_header ueh;
  1138. struct iovec local_aiov;
  1139. struct uio local_aio;
  1140. struct mount *mp = vp->v_mount;
  1141. struct ufsmount *ump = VFSTOUFS(mp);
  1142. struct inode *ip = VTOI(vp);
  1143. off_t base_offset;
  1144. int error = 0, ioflag;
  1145. if (vp->v_mount->mnt_flag & MNT_RDONLY)
  1146. return (EROFS);
  1147. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
  1148. return (EOPNOTSUPP);
  1149. if (!ufs_extattr_valid_attrname(attrnamespace, name))
  1150. return (EINVAL);
  1151. error = extattr_check_cred(vp, attrnamespace, cred, l, IWRITE);
  1152. if (error)
  1153. return (error);
  1154. attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
  1155. if (!attribute) {
  1156. attribute = ufs_extattr_autocreate_attr(vp, attrnamespace,
  1157. name, l);
  1158. if (!attribute)
  1159. return (ENOATTR);
  1160. }
  1161. /*
  1162. * Early rejection of invalid offsets/length.
  1163. * Reject: any offset but 0 (replace)
  1164. * Any size greater than attribute size limit
  1165. */
  1166. if (uio->uio_offset != 0 ||
  1167. uio->uio_resid > attribute->uele_fileheader.uef_size)
  1168. return (ENXIO);
  1169. /*
  1170. * Find base offset of header in file based on file header size, and
  1171. * data header size + maximum data size, indexed by inode number.
  1172. */
  1173. base_offset = sizeof(struct ufs_extattr_fileheader) +
  1174. ip->i_number * (sizeof(struct ufs_extattr_header) +
  1175. attribute->uele_fileheader.uef_size);
  1176. /*
  1177. * Write out a data header for the data.
  1178. */
  1179. ueh.ueh_len = ufs_rw32((uint32_t) uio->uio_resid,
  1180. UELE_NEEDSWAP(attribute));
  1181. ueh.ueh_flags = ufs_rw32(UFS_EXTATTR_ATTR_FLAG_INUSE,
  1182. UELE_NEEDSWAP(attribute));
  1183. ueh.ueh_i_gen = ufs_rw32(ip->i_gen, UELE_NEEDSWAP(attribute));
  1184. local_aiov.iov_base = &ueh;
  1185. local_aiov.iov_len = sizeof(struct ufs_extattr_header);
  1186. local_aio.uio_iov = &local_aiov;
  1187. local_aio.uio_iovcnt = 1;
  1188. local_aio.uio_rw = UIO_WRITE;
  1189. local_aio.uio_offset = base_offset;
  1190. local_aio.uio_resid = sizeof(struct ufs_extattr_header);
  1191. UIO_SETUP_SYSSPACE(&local_aio);
  1192. /*
  1193. * Don't need to get a lock on the backing file if the setattr is
  1194. * being applied to the backing file, as the lock is already held.
  1195. */
  1196. if (attribute->uele_backing_vnode != vp)
  1197. vn_lock(attribute->uele_backing_vnode,
  1198. LK_EXCLUSIVE | LK_RETRY);
  1199. ioflag = IO_NODELOCKED;
  1200. if (ufs_extattr_sync)
  1201. ioflag |= IO_SYNC;
  1202. error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
  1203. ump->um_extattr.uepm_ucred);
  1204. if (error)
  1205. goto vopunlock_exit;
  1206. if (local_aio.uio_resid != 0) {
  1207. error = ENXIO;
  1208. goto vopunlock_exit;
  1209. }
  1210. /*
  1211. * Write out user data.
  1212. * XXX NOT ATOMIC WITH RESPECT TO THE HEADER.
  1213. */
  1214. uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header);
  1215. ioflag = IO_NODELOCKED;
  1216. if (ufs_extattr_sync)
  1217. ioflag |= IO_SYNC;
  1218. error = VOP_WRITE(attribute->uele_backing_vnode, uio, ioflag,
  1219. ump->um_extattr.uepm_ucred);
  1220. vopunlock_exit:
  1221. uio->uio_offset = 0;
  1222. if (attribute->uele_backing_vnode != vp)
  1223. VOP_UNLOCK(attribute->uele_backing_vnode);
  1224. return (error);
  1225. }
  1226. /*
  1227. * Real work associated with removing an extended attribute from a vnode.
  1228. * Assumes the attribute lock has already been grabbed.
  1229. */
  1230. static int
  1231. ufs_extattr_rm(struct vnode *vp, int attrnamespace, const char *name,
  1232. kauth_cred_t cred, struct lwp *l)
  1233. {
  1234. struct ufs_extattr_list_entry *attribute;
  1235. struct ufs_extattr_header ueh;
  1236. struct mount *mp = vp->v_mount;
  1237. struct ufsmount *ump = VFSTOUFS(mp);
  1238. struct iovec local_aiov;
  1239. struct uio local_aio;
  1240. off_t base_offset;
  1241. int error = 0, ioflag;
  1242. if (vp->v_mount->mnt_flag & MNT_RDONLY)
  1243. return (EROFS);
  1244. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
  1245. return (EOPNOTSUPP);
  1246. if (!ufs_extattr_valid_attrname(attrnamespace, name))
  1247. return (EINVAL);
  1248. error = extattr_check_cred(vp, attrnamespace, cred, l, IWRITE);
  1249. if (error)
  1250. return (error);
  1251. attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
  1252. if (!attribute)
  1253. return (ENOATTR);
  1254. /*
  1255. * Don't need to get a lock on the backing file if the getattr is
  1256. * being applied to the backing file, as the lock is already held.
  1257. */
  1258. if (attribute->uele_backing_vnode != vp)
  1259. vn_lock(attribute->uele_backing_vnode, LK_EXCLUSIVE | LK_RETRY);
  1260. error = ufs_extattr_get_header(vp, attribute, &ueh, &base_offset);
  1261. if (error)
  1262. goto vopunlock_exit;
  1263. /* Flag it as not in use. */
  1264. ueh.ueh_flags = 0; /* No need to byte swap 0 */
  1265. ueh.ueh_len = 0; /* ...ditto... */
  1266. local_aiov.iov_base = &ueh;
  1267. local_aiov.iov_len = sizeof(struct ufs_extattr_header);
  1268. local_aio.uio_iov = &local_aiov;
  1269. local_aio.uio_iovcnt = 1;
  1270. local_aio.uio_rw = UIO_WRITE;
  1271. local_aio.uio_offset = base_offset;
  1272. local_aio.uio_resid = sizeof(struct ufs_extattr_header);
  1273. UIO_SETUP_SYSSPACE(&local_aio);
  1274. ioflag = IO_NODELOCKED;
  1275. if (ufs_extattr_sync)
  1276. ioflag |= IO_SYNC;
  1277. error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
  1278. ump->um_extattr.uepm_ucred);
  1279. if (error)
  1280. goto vopunlock_exit;
  1281. if (local_aio.uio_resid != 0)
  1282. error = ENXIO;
  1283. vopunlock_exit:
  1284. VOP_UNLOCK(attribute->uele_backing_vnode);
  1285. return (error);
  1286. }
  1287. /*
  1288. * Called by UFS when an inode is no longer active and should have its
  1289. * attributes stripped.
  1290. */
  1291. void
  1292. ufs_extattr_vnode_inactive(struct vnode *vp, struct lwp *l)
  1293. {
  1294. struct ufs_extattr_list_entry *uele;
  1295. struct mount *mp = vp->v_mount;
  1296. struct ufsmount *ump = VFSTOUFS(mp);
  1297. /*
  1298. * In that case, we cannot lock. We should not have any active vnodes
  1299. * on the fs if this is not yet initialized but is going to be, so
  1300. * this can go unlocked.
  1301. */
  1302. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
  1303. return;
  1304. ufs_extattr_uepm_lock(ump);
  1305. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
  1306. ufs_extattr_uepm_unlock(ump);
  1307. return;
  1308. }
  1309. LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries)
  1310. ufs_extattr_rm(vp, uele->uele_attrnamespace,
  1311. uele->uele_attrname, lwp0.l_cred, l);
  1312. ufs_extattr_uepm_unlock(ump);
  1313. }
  1314. void
  1315. ufs_extattr_init(void)
  1316. {
  1317. malloc_type_attach(M_UFS_EXTATTR);
  1318. }
  1319. void
  1320. ufs_extattr_done(void)
  1321. {
  1322. malloc_type_detach(M_UFS_EXTATTR);
  1323. }