ufs_extattr.c 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280
  1. /*-
  2. * Copyright (c) 1999-2002 Robert N. M. Watson
  3. * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
  4. * All rights reserved.
  5. *
  6. * This software was developed by Robert Watson for the TrustedBSD Project.
  7. *
  8. * This software was developed for the FreeBSD Project in part by Network
  9. * Associates Laboratories, the Security Research Division of Network
  10. * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
  11. * as part of the DARPA CHATS research program.
  12. *
  13. * Redistribution and use in source and binary forms, with or without
  14. * modification, are permitted provided that the following conditions
  15. * are met:
  16. * 1. Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. * 2. Redistributions in binary form must reproduce the above copyright
  19. * notice, this list of conditions and the following disclaimer in the
  20. * documentation and/or other materials provided with the distribution.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  23. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  26. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32. * SUCH DAMAGE.
  33. *
  34. */
  35. /*
  36. * Support for filesystem extended attribute: UFS-specific support functions.
  37. */
  38. #include <u.h>
  39. #include <libc.h>
  40. #include <ufs/ufs/dir.h>
  41. #include <ufs/ufs/extattr.h>
  42. #include <ufs/ufs/quota.h>
  43. #include <ufs/ufs/ufsmount.h>
  44. #include <ufs/ufs/inode.h>
  45. #include <ufs/ufs/ufs_extern.h>
  46. #ifdef UFS_EXTATTR
  47. FEATURE(ufs_extattr, "ufs extended attribute support");
  48. static MALLOC_DEFINE(M_UFS_EXTATTR, "ufs_extattr", "ufs extended attribute");
  49. static int ufs_extattr_sync = 0;
  50. SYSCTL_INT(_debug, OID_AUTO, ufs_extattr_sync, CTLFLAG_RW, &ufs_extattr_sync,
  51. 0, "");
  52. static int ufs_extattr_valid_attrname(int attrnamespace,
  53. const char *attrname);
  54. static int ufs_extattr_enable_with_open(struct ufsmount *ump,
  55. struct vnode *vp, int attrnamespace, const char *attrname,
  56. struct thread *td);
  57. static int ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
  58. const char *attrname, struct vnode *backing_vnode,
  59. struct thread *td);
  60. static int ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
  61. const char *attrname, struct thread *td);
  62. static int ufs_extattr_get(struct vnode *vp, int attrnamespace,
  63. const char *name, struct uio *uio, size_t *size,
  64. struct ucred *cred, struct thread *td);
  65. static int ufs_extattr_set(struct vnode *vp, int attrnamespace,
  66. const char *name, struct uio *uio, struct ucred *cred,
  67. struct thread *td);
  68. static int ufs_extattr_rm(struct vnode *vp, int attrnamespace,
  69. const char *name, struct ucred *cred, struct thread *td);
  70. #ifdef UFS_EXTATTR_AUTOSTART
  71. static int ufs_extattr_autostart_locked(struct mount *mp,
  72. struct thread *td);
  73. #endif
  74. static int ufs_extattr_start_locked(struct ufsmount *ump,
  75. struct thread *td);
  76. /*
  77. * Per-FS attribute lock protecting attribute operations.
  78. *
  79. * XXXRW: Perhaps something more fine-grained would be appropriate, but at
  80. * the end of the day we're going to contend on the vnode lock for the
  81. * backing file anyway.
  82. */
  83. static void
  84. ufs_extattr_uepm_lock(struct ufsmount *ump)
  85. {
  86. sx_xlock(&ump->um_extattr.uepm_lock);
  87. }
  88. static void
  89. ufs_extattr_uepm_unlock(struct ufsmount *ump)
  90. {
  91. sx_xunlock(&ump->um_extattr.uepm_lock);
  92. }
  93. /*-
  94. * Determine whether the name passed is a valid name for an actual
  95. * attribute.
  96. *
  97. * Invalid currently consists of:
  98. * NULL pointer for attrname
  99. * zero-length attrname (used to retrieve application attribute list)
  100. */
  101. static int
  102. ufs_extattr_valid_attrname(int attrnamespace, const char *attrname)
  103. {
  104. if (attrname == nil)
  105. return (0);
  106. if (strlen(attrname) == 0)
  107. return (0);
  108. return (1);
  109. }
  110. /*
  111. * Locate an attribute given a name and mountpoint.
  112. * Must be holding uepm lock for the mount point.
  113. */
  114. static struct ufs_extattr_list_entry *
  115. ufs_extattr_find_attr(struct ufsmount *ump, int attrnamespace,
  116. const char *attrname)
  117. {
  118. struct ufs_extattr_list_entry *search_attribute;
  119. sx_assert(&ump->um_extattr.uepm_lock, SA_XLOCKED);
  120. for (search_attribute = LIST_FIRST(&ump->um_extattr.uepm_list);
  121. search_attribute != nil;
  122. search_attribute = LIST_NEXT(search_attribute, uele_entries)) {
  123. if (!(strncmp(attrname, search_attribute->uele_attrname,
  124. UFS_EXTATTR_MAXEXTATTRNAME)) &&
  125. (attrnamespace == search_attribute->uele_attrnamespace)) {
  126. return (search_attribute);
  127. }
  128. }
  129. return (0);
  130. }
  131. /*
  132. * Initialize per-FS structures supporting extended attributes. Do not
  133. * start extended attributes yet.
  134. */
  135. void
  136. ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm)
  137. {
  138. uepm->uepm_flags = 0;
  139. LIST_INIT(&uepm->uepm_list);
  140. sx_init(&uepm->uepm_lock, "ufs_extattr_sx");
  141. uepm->uepm_flags |= UFS_EXTATTR_UEPM_INITIALIZED;
  142. }
  143. /*
  144. * Destroy per-FS structures supporting extended attributes. Assumes
  145. * that EAs have already been stopped, and will panic if not.
  146. */
  147. void
  148. ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm)
  149. {
  150. if (!(uepm->uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
  151. panic("ufs_extattr_uepm_destroy: not initialized");
  152. if ((uepm->uepm_flags & UFS_EXTATTR_UEPM_STARTED))
  153. panic("ufs_extattr_uepm_destroy: called while still started");
  154. /*
  155. * It's not clear that either order for the next two lines is
  156. * ideal, and it should never be a problem if this is only called
  157. * during unmount, and with vfs_busy().
  158. */
  159. uepm->uepm_flags &= ~UFS_EXTATTR_UEPM_INITIALIZED;
  160. sx_destroy(&uepm->uepm_lock);
  161. }
  162. /*
  163. * Start extended attribute support on an FS.
  164. */
  165. int
  166. ufs_extattr_start(struct mount *mp, struct thread *td)
  167. {
  168. struct ufsmount *ump;
  169. int error = 0;
  170. ump = VFSTOUFS(mp);
  171. ufs_extattr_uepm_lock(ump);
  172. error = ufs_extattr_start_locked(ump, td);
  173. ufs_extattr_uepm_unlock(ump);
  174. return (error);
  175. }
  176. static int
  177. ufs_extattr_start_locked(struct ufsmount *ump, struct thread *td)
  178. {
  179. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
  180. return (EOPNOTSUPP);
  181. if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)
  182. return (EBUSY);
  183. ump->um_extattr.uepm_flags |= UFS_EXTATTR_UEPM_STARTED;
  184. ump->um_extattr.uepm_ucred = crhold(td->td_ucred);
  185. return (0);
  186. }
  187. #ifdef UFS_EXTATTR_AUTOSTART
  188. /*
  189. * Helper routine: given a locked parent directory and filename, return
  190. * the locked vnode of the inode associated with the name. Will not
  191. * follow symlinks, may return any type of vnode. Lock on parent will
  192. * be released even in the event of a failure. In the event that the
  193. * target is the parent (i.e., "."), there will be two references and
  194. * one lock, requiring the caller to possibly special-case.
  195. */
  196. #define UE_GETDIR_LOCKPARENT 1
  197. #define UE_GETDIR_LOCKPARENT_DONT 2
  198. static int
  199. ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, char *dirname,
  200. struct vnode **vp, struct thread *td)
  201. {
  202. struct vop_cachedlookup_args vargs;
  203. struct componentname cnp;
  204. struct vnode *target_vp;
  205. int error;
  206. bzero(&cnp, sizeof(cnp));
  207. cnp.cn_nameiop = LOOKUP;
  208. cnp.cn_flags = ISLASTCN;
  209. if (lockparent == UE_GETDIR_LOCKPARENT)
  210. cnp.cn_flags |= LOCKPARENT;
  211. cnp.cn_lkflags = LK_EXCLUSIVE;
  212. cnp.cn_thread = td;
  213. cnp.cn_cred = td->td_ucred;
  214. cnp.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
  215. cnp.cn_nameptr = cnp.cn_pnbuf;
  216. error = copystr(dirname, cnp.cn_pnbuf, MAXPATHLEN,
  217. (size_t *) &cnp.cn_namelen);
  218. if (error) {
  219. if (lockparent == UE_GETDIR_LOCKPARENT_DONT) {
  220. VOP_UNLOCK(start_dvp, 0);
  221. }
  222. uma_zfree(namei_zone, cnp.cn_pnbuf);
  223. printf("ufs_extattr_lookup: copystr failed\n");
  224. return (error);
  225. }
  226. cnp.cn_namelen--; /* trim nul termination */
  227. vargs.a_gen.a_desc = nil;
  228. vargs.a_dvp = start_dvp;
  229. vargs.a_vpp = &target_vp;
  230. vargs.a_cnp = &cnp;
  231. error = ufs_lookup(&vargs);
  232. uma_zfree(namei_zone, cnp.cn_pnbuf);
  233. if (error) {
  234. /*
  235. * Error condition, may have to release the lock on the parent
  236. * if ufs_lookup() didn't.
  237. */
  238. if (lockparent == UE_GETDIR_LOCKPARENT_DONT)
  239. VOP_UNLOCK(start_dvp, 0);
  240. /*
  241. * Check that ufs_lookup() didn't release the lock when we
  242. * didn't want it to.
  243. */
  244. if (lockparent == UE_GETDIR_LOCKPARENT)
  245. ASSERT_VOP_LOCKED(start_dvp, "ufs_extattr_lookup");
  246. return (error);
  247. }
  248. /*
  249. if (target_vp == start_dvp)
  250. panic("ufs_extattr_lookup: target_vp == start_dvp");
  251. */
  252. if (target_vp != start_dvp && lockparent == UE_GETDIR_LOCKPARENT_DONT)
  253. VOP_UNLOCK(start_dvp, 0);
  254. if (lockparent == UE_GETDIR_LOCKPARENT)
  255. ASSERT_VOP_LOCKED(start_dvp, "ufs_extattr_lookup");
  256. /* printf("ufs_extattr_lookup: success\n"); */
  257. *vp = target_vp;
  258. return (0);
  259. }
  260. #endif /* !UFS_EXTATTR_AUTOSTART */
  261. /*
  262. * Enable an EA using the passed filesystem, backing vnode, attribute name,
  263. * namespace, and proc. Will perform a VOP_OPEN() on the vp, so expects vp
  264. * to be locked when passed in. The vnode will be returned unlocked,
  265. * regardless of success/failure of the function. As a result, the caller
  266. * will always need to vrele(), but not vput().
  267. */
  268. static int
  269. ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp,
  270. int attrnamespace, const char *attrname, struct thread *td)
  271. {
  272. int error;
  273. error = VOP_OPEN(vp, FREAD|FWRITE, td->td_ucred, td, nil);
  274. if (error) {
  275. printf("ufs_extattr_enable_with_open.VOP_OPEN(): failed "
  276. "with %d\n", error);
  277. VOP_UNLOCK(vp, 0);
  278. return (error);
  279. }
  280. VOP_ADD_WRITECOUNT(vp, 1);
  281. CTR3(KTR_VFS, "%s: vp %p v_writecount increased to %d", __func__, vp,
  282. vp->v_writecount);
  283. vref(vp);
  284. VOP_UNLOCK(vp, 0);
  285. error = ufs_extattr_enable(ump, attrnamespace, attrname, vp, td);
  286. if (error != 0)
  287. vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
  288. return (error);
  289. }
  290. #ifdef UFS_EXTATTR_AUTOSTART
  291. /*
  292. * Given a locked directory vnode, iterate over the names in the directory
  293. * and use ufs_extattr_lookup() to retrieve locked vnodes of potential
  294. * attribute files. Then invoke ufs_extattr_enable_with_open() on each
  295. * to attempt to start the attribute. Leaves the directory locked on
  296. * exit.
  297. */
  298. static int
  299. ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp,
  300. int attrnamespace, struct thread *td)
  301. {
  302. struct vop_readdir_args vargs;
  303. struct dirent *dp, *edp;
  304. struct vnode *attr_vp;
  305. struct uio auio;
  306. struct iovec aiov;
  307. char *dirbuf;
  308. int error, eofflag = 0;
  309. if (dvp->v_type != VDIR)
  310. return (ENOTDIR);
  311. dirbuf = malloc(DIRBLKSIZ, M_TEMP, M_WAITOK);
  312. auio.uio_iov = &aiov;
  313. auio.uio_iovcnt = 1;
  314. auio.uio_rw = UIO_READ;
  315. auio.uio_segflg = UIO_SYSSPACE;
  316. auio.uio_td = td;
  317. auio.uio_offset = 0;
  318. vargs.a_gen.a_desc = nil;
  319. vargs.a_vp = dvp;
  320. vargs.a_uio = &auio;
  321. vargs.a_cred = td->td_ucred;
  322. vargs.a_eofflag = &eofflag;
  323. vargs.a_ncookies = nil;
  324. vargs.a_cookies = nil;
  325. while (!eofflag) {
  326. auio.uio_resid = DIRBLKSIZ;
  327. aiov.iov_base = dirbuf;
  328. aiov.iov_len = DIRBLKSIZ;
  329. error = ufs_readdir(&vargs);
  330. if (error) {
  331. printf("ufs_extattr_iterate_directory: ufs_readdir "
  332. "%d\n", error);
  333. return (error);
  334. }
  335. edp = (struct dirent *)&dirbuf[DIRBLKSIZ - auio.uio_resid];
  336. for (dp = (struct dirent *)dirbuf; dp < edp; ) {
  337. if (dp->d_reclen == 0)
  338. break;
  339. error = ufs_extattr_lookup(dvp, UE_GETDIR_LOCKPARENT,
  340. dp->d_name, &attr_vp, td);
  341. if (error) {
  342. printf("ufs_extattr_iterate_directory: lookup "
  343. "%s %d\n", dp->d_name, error);
  344. } else if (attr_vp == dvp) {
  345. vrele(attr_vp);
  346. } else if (attr_vp->v_type != VREG) {
  347. vput(attr_vp);
  348. } else {
  349. error = ufs_extattr_enable_with_open(ump,
  350. attr_vp, attrnamespace, dp->d_name, td);
  351. vrele(attr_vp);
  352. if (error) {
  353. printf("ufs_extattr_iterate_directory: "
  354. "enable %s %d\n", dp->d_name,
  355. error);
  356. } else if (bootverbose) {
  357. printf("UFS autostarted EA %s\n",
  358. dp->d_name);
  359. }
  360. }
  361. dp = (struct dirent *) ((char *)dp + dp->d_reclen);
  362. if (dp >= edp)
  363. break;
  364. }
  365. }
  366. free(dirbuf, M_TEMP);
  367. return (0);
  368. }
  369. /*
  370. * Auto-start of extended attributes, to be executed (optionally) at
  371. * mount-time.
  372. */
  373. int
  374. ufs_extattr_autostart(struct mount *mp, struct thread *td)
  375. {
  376. struct ufsmount *ump;
  377. int error;
  378. ump = VFSTOUFS(mp);
  379. ufs_extattr_uepm_lock(ump);
  380. error = ufs_extattr_autostart_locked(mp, td);
  381. ufs_extattr_uepm_unlock(ump);
  382. return (error);
  383. }
  384. static int
  385. ufs_extattr_autostart_locked(struct mount *mp, struct thread *td)
  386. {
  387. struct vnode *rvp, *attr_dvp, *attr_system_dvp, *attr_user_dvp;
  388. struct ufsmount *ump = VFSTOUFS(mp);
  389. int error;
  390. /*
  391. * UFS_EXTATTR applies only to UFS1, as UFS2 uses native extended
  392. * attributes, so don't autostart.
  393. */
  394. if (ump->um_fstype != UFS1)
  395. return (0);
  396. /*
  397. * Does UFS_EXTATTR_FSROOTSUBDIR exist off the filesystem root?
  398. * If so, automatically start EA's.
  399. */
  400. error = VFS_ROOT(mp, LK_EXCLUSIVE, &rvp);
  401. if (error) {
  402. printf("ufs_extattr_autostart.VFS_ROOT() returned %d\n",
  403. error);
  404. return (error);
  405. }
  406. error = ufs_extattr_lookup(rvp, UE_GETDIR_LOCKPARENT_DONT,
  407. UFS_EXTATTR_FSROOTSUBDIR, &attr_dvp, td);
  408. if (error) {
  409. /* rvp ref'd but now unlocked */
  410. vrele(rvp);
  411. return (error);
  412. }
  413. if (rvp == attr_dvp) {
  414. /* Should never happen. */
  415. vput(rvp);
  416. vrele(attr_dvp);
  417. return (EINVAL);
  418. }
  419. vrele(rvp);
  420. if (attr_dvp->v_type != VDIR) {
  421. printf("ufs_extattr_autostart: %s != VDIR\n",
  422. UFS_EXTATTR_FSROOTSUBDIR);
  423. goto return_vput_attr_dvp;
  424. }
  425. error = ufs_extattr_start_locked(ump, td);
  426. if (error) {
  427. printf("ufs_extattr_autostart: ufs_extattr_start failed (%d)\n",
  428. error);
  429. goto return_vput_attr_dvp;
  430. }
  431. /*
  432. * Look for two subdirectories: UFS_EXTATTR_SUBDIR_SYSTEM,
  433. * UFS_EXTATTR_SUBDIR_USER. For each, iterate over the sub-directory,
  434. * and start with appropriate type. Failures in either don't
  435. * result in an over-all failure. attr_dvp is left locked to
  436. * be cleaned up on exit.
  437. */
  438. error = ufs_extattr_lookup(attr_dvp, UE_GETDIR_LOCKPARENT,
  439. UFS_EXTATTR_SUBDIR_SYSTEM, &attr_system_dvp, td);
  440. if (!error) {
  441. error = ufs_extattr_iterate_directory(VFSTOUFS(mp),
  442. attr_system_dvp, EXTATTR_NAMESPACE_SYSTEM, td);
  443. if (error)
  444. printf("ufs_extattr_iterate_directory returned %d\n",
  445. error);
  446. vput(attr_system_dvp);
  447. }
  448. error = ufs_extattr_lookup(attr_dvp, UE_GETDIR_LOCKPARENT,
  449. UFS_EXTATTR_SUBDIR_USER, &attr_user_dvp, td);
  450. if (!error) {
  451. error = ufs_extattr_iterate_directory(VFSTOUFS(mp),
  452. attr_user_dvp, EXTATTR_NAMESPACE_USER, td);
  453. if (error)
  454. printf("ufs_extattr_iterate_directory returned %d\n",
  455. error);
  456. vput(attr_user_dvp);
  457. }
  458. /* Mask startup failures in sub-directories. */
  459. error = 0;
  460. return_vput_attr_dvp:
  461. vput(attr_dvp);
  462. return (error);
  463. }
  464. #endif /* !UFS_EXTATTR_AUTOSTART */
  465. /*
  466. * Stop extended attribute support on an FS.
  467. */
  468. int
  469. ufs_extattr_stop(struct mount *mp, struct thread *td)
  470. {
  471. struct ufs_extattr_list_entry *uele;
  472. struct ufsmount *ump = VFSTOUFS(mp);
  473. int error = 0;
  474. ufs_extattr_uepm_lock(ump);
  475. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
  476. error = EOPNOTSUPP;
  477. goto unlock;
  478. }
  479. while ((uele = LIST_FIRST(&ump->um_extattr.uepm_list)) != nil) {
  480. ufs_extattr_disable(ump, uele->uele_attrnamespace,
  481. uele->uele_attrname, td);
  482. }
  483. ump->um_extattr.uepm_flags &= ~UFS_EXTATTR_UEPM_STARTED;
  484. crfree(ump->um_extattr.uepm_ucred);
  485. ump->um_extattr.uepm_ucred = nil;
  486. unlock:
  487. ufs_extattr_uepm_unlock(ump);
  488. return (error);
  489. }
  490. /*
  491. * Enable a named attribute on the specified filesystem; provide an
  492. * unlocked backing vnode to hold the attribute data.
  493. */
  494. static int
  495. ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
  496. const char *attrname, struct vnode *backing_vnode, struct thread *td)
  497. {
  498. struct ufs_extattr_list_entry *attribute;
  499. struct iovec aiov;
  500. struct uio auio;
  501. int error = 0;
  502. if (!ufs_extattr_valid_attrname(attrnamespace, attrname))
  503. return (EINVAL);
  504. if (backing_vnode->v_type != VREG)
  505. return (EINVAL);
  506. attribute = malloc(sizeof(struct ufs_extattr_list_entry),
  507. M_UFS_EXTATTR, M_WAITOK);
  508. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
  509. error = EOPNOTSUPP;
  510. goto free_exit;
  511. }
  512. if (ufs_extattr_find_attr(ump, attrnamespace, attrname)) {
  513. error = EEXIST;
  514. goto free_exit;
  515. }
  516. strncpy(attribute->uele_attrname, attrname,
  517. UFS_EXTATTR_MAXEXTATTRNAME);
  518. attribute->uele_attrnamespace = attrnamespace;
  519. bzero(&attribute->uele_fileheader,
  520. sizeof(struct ufs_extattr_fileheader));
  521. attribute->uele_backing_vnode = backing_vnode;
  522. auio.uio_iov = &aiov;
  523. auio.uio_iovcnt = 1;
  524. aiov.iov_base = (caddr_t) &attribute->uele_fileheader;
  525. aiov.iov_len = sizeof(struct ufs_extattr_fileheader);
  526. auio.uio_resid = sizeof(struct ufs_extattr_fileheader);
  527. auio.uio_offset = (off_t) 0;
  528. auio.uio_segflg = UIO_SYSSPACE;
  529. auio.uio_rw = UIO_READ;
  530. auio.uio_td = td;
  531. vn_lock(backing_vnode, LK_SHARED | LK_RETRY);
  532. error = VOP_READ(backing_vnode, &auio, IO_NODELOCKED,
  533. ump->um_extattr.uepm_ucred);
  534. if (error)
  535. goto unlock_free_exit;
  536. if (auio.uio_resid != 0) {
  537. printf("ufs_extattr_enable: malformed attribute header\n");
  538. error = EINVAL;
  539. goto unlock_free_exit;
  540. }
  541. if (attribute->uele_fileheader.uef_magic != UFS_EXTATTR_MAGIC) {
  542. printf("ufs_extattr_enable: invalid attribute header magic\n");
  543. error = EINVAL;
  544. goto unlock_free_exit;
  545. }
  546. if (attribute->uele_fileheader.uef_version != UFS_EXTATTR_VERSION) {
  547. printf("ufs_extattr_enable: incorrect attribute header "
  548. "version\n");
  549. error = EINVAL;
  550. goto unlock_free_exit;
  551. }
  552. ASSERT_VOP_LOCKED(backing_vnode, "ufs_extattr_enable");
  553. LIST_INSERT_HEAD(&ump->um_extattr.uepm_list, attribute,
  554. uele_entries);
  555. VOP_UNLOCK(backing_vnode, 0);
  556. return (0);
  557. unlock_free_exit:
  558. VOP_UNLOCK(backing_vnode, 0);
  559. free_exit:
  560. free(attribute, M_UFS_EXTATTR);
  561. return (error);
  562. }
  563. /*
  564. * Disable extended attribute support on an FS.
  565. */
  566. static int
  567. ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
  568. const char *attrname, struct thread *td)
  569. {
  570. struct ufs_extattr_list_entry *uele;
  571. int error = 0;
  572. if (!ufs_extattr_valid_attrname(attrnamespace, attrname))
  573. return (EINVAL);
  574. uele = ufs_extattr_find_attr(ump, attrnamespace, attrname);
  575. if (!uele)
  576. return (ENOATTR);
  577. LIST_REMOVE(uele, uele_entries);
  578. vn_lock(uele->uele_backing_vnode, LK_SHARED | LK_RETRY);
  579. ASSERT_VOP_LOCKED(uele->uele_backing_vnode, "ufs_extattr_disable");
  580. VOP_UNLOCK(uele->uele_backing_vnode, 0);
  581. error = vn_close(uele->uele_backing_vnode, FREAD|FWRITE,
  582. td->td_ucred, td);
  583. free(uele, M_UFS_EXTATTR);
  584. return (error);
  585. }
  586. /*
  587. * VFS call to manage extended attributes in UFS. If filename_vp is
  588. * non-NULL, it must be passed in locked, and regardless of errors in
  589. * processing, will be unlocked.
  590. */
  591. int
  592. ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
  593. int attrnamespace, const char *attrname)
  594. {
  595. struct ufsmount *ump = VFSTOUFS(mp);
  596. struct thread *td = curthread;
  597. int error;
  598. /*
  599. * Processes with privilege, but in jail, are not allowed to
  600. * configure extended attributes.
  601. */
  602. error = priv_check(td, PRIV_UFS_EXTATTRCTL);
  603. if (error) {
  604. if (filename_vp != nil)
  605. VOP_UNLOCK(filename_vp, 0);
  606. return (error);
  607. }
  608. /*
  609. * We only allow extattrctl(2) on UFS1 file systems, as UFS2 uses
  610. * native extended attributes.
  611. */
  612. if (ump->um_fstype != UFS1) {
  613. if (filename_vp != nil)
  614. VOP_UNLOCK(filename_vp, 0);
  615. return (EOPNOTSUPP);
  616. }
  617. switch(cmd) {
  618. case UFS_EXTATTR_CMD_START:
  619. if (filename_vp != nil) {
  620. VOP_UNLOCK(filename_vp, 0);
  621. return (EINVAL);
  622. }
  623. if (attrname != nil)
  624. return (EINVAL);
  625. error = ufs_extattr_start(mp, td);
  626. return (error);
  627. case UFS_EXTATTR_CMD_STOP:
  628. if (filename_vp != nil) {
  629. VOP_UNLOCK(filename_vp, 0);
  630. return (EINVAL);
  631. }
  632. if (attrname != nil)
  633. return (EINVAL);
  634. error = ufs_extattr_stop(mp, td);
  635. return (error);
  636. case UFS_EXTATTR_CMD_ENABLE:
  637. if (filename_vp == nil)
  638. return (EINVAL);
  639. if (attrname == nil) {
  640. VOP_UNLOCK(filename_vp, 0);
  641. return (EINVAL);
  642. }
  643. /*
  644. * ufs_extattr_enable_with_open() will always unlock the
  645. * vnode, regardless of failure.
  646. */
  647. ufs_extattr_uepm_lock(ump);
  648. error = ufs_extattr_enable_with_open(ump, filename_vp,
  649. attrnamespace, attrname, td);
  650. ufs_extattr_uepm_unlock(ump);
  651. return (error);
  652. case UFS_EXTATTR_CMD_DISABLE:
  653. if (filename_vp != nil) {
  654. VOP_UNLOCK(filename_vp, 0);
  655. return (EINVAL);
  656. }
  657. if (attrname == nil)
  658. return (EINVAL);
  659. ufs_extattr_uepm_lock(ump);
  660. error = ufs_extattr_disable(ump, attrnamespace, attrname,
  661. td);
  662. ufs_extattr_uepm_unlock(ump);
  663. return (error);
  664. default:
  665. return (EINVAL);
  666. }
  667. }
  668. /*
  669. * Vnode operating to retrieve a named extended attribute.
  670. */
  671. int
  672. ufs_getextattr(struct vop_getextattr_args *ap)
  673. /*
  674. vop_getextattr {
  675. IN struct vnode *a_vp;
  676. IN int a_attrnamespace;
  677. IN const char *a_name;
  678. INOUT struct uio *a_uio;
  679. OUT size_t *a_size;
  680. IN struct ucred *a_cred;
  681. IN struct thread *a_td;
  682. };
  683. */
  684. {
  685. struct mount *mp = ap->a_vp->v_mount;
  686. struct ufsmount *ump = VFSTOUFS(mp);
  687. int error;
  688. ufs_extattr_uepm_lock(ump);
  689. error = ufs_extattr_get(ap->a_vp, ap->a_attrnamespace, ap->a_name,
  690. ap->a_uio, ap->a_size, ap->a_cred, ap->a_td);
  691. ufs_extattr_uepm_unlock(ump);
  692. return (error);
  693. }
  694. /*
  695. * Real work associated with retrieving a named attribute--assumes that
  696. * the attribute lock has already been grabbed.
  697. */
  698. static int
  699. ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
  700. struct uio *uio, size_t *size, struct ucred *cred, struct thread *td)
  701. {
  702. struct ufs_extattr_list_entry *attribute;
  703. struct ufs_extattr_header ueh;
  704. struct iovec local_aiov;
  705. struct uio local_aio;
  706. struct mount *mp = vp->v_mount;
  707. struct ufsmount *ump = VFSTOUFS(mp);
  708. struct inode *ip = VTOI(vp);
  709. off_t base_offset;
  710. size_t len, old_len;
  711. int error = 0;
  712. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
  713. return (EOPNOTSUPP);
  714. if (strlen(name) == 0)
  715. return (EINVAL);
  716. error = extattr_check_cred(vp, attrnamespace, cred, td, VREAD);
  717. if (error)
  718. return (error);
  719. attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
  720. if (!attribute)
  721. return (ENOATTR);
  722. /*
  723. * Allow only offsets of zero to encourage the read/replace
  724. * extended attribute semantic. Otherwise we can't guarantee
  725. * atomicity, as we don't provide locks for extended attributes.
  726. */
  727. if (uio != nil && uio->uio_offset != 0)
  728. return (ENXIO);
  729. /*
  730. * Find base offset of header in file based on file header size, and
  731. * data header size + maximum data size, indexed by inode number.
  732. */
  733. base_offset = sizeof(struct ufs_extattr_fileheader) +
  734. ip->i_number * (sizeof(struct ufs_extattr_header) +
  735. attribute->uele_fileheader.uef_size);
  736. /*
  737. * Read in the data header to see if the data is defined, and if so
  738. * how much.
  739. */
  740. bzero(&ueh, sizeof(struct ufs_extattr_header));
  741. local_aiov.iov_base = (caddr_t) &ueh;
  742. local_aiov.iov_len = sizeof(struct ufs_extattr_header);
  743. local_aio.uio_iov = &local_aiov;
  744. local_aio.uio_iovcnt = 1;
  745. local_aio.uio_rw = UIO_READ;
  746. local_aio.uio_segflg = UIO_SYSSPACE;
  747. local_aio.uio_td = td;
  748. local_aio.uio_offset = base_offset;
  749. local_aio.uio_resid = sizeof(struct ufs_extattr_header);
  750. /*
  751. * Acquire locks.
  752. *
  753. * Don't need to get a lock on the backing file if the getattr is
  754. * being applied to the backing file, as the lock is already held.
  755. */
  756. if (attribute->uele_backing_vnode != vp)
  757. vn_lock(attribute->uele_backing_vnode, LK_SHARED | LK_RETRY);
  758. error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
  759. IO_NODELOCKED, ump->um_extattr.uepm_ucred);
  760. if (error)
  761. goto vopunlock_exit;
  762. /* Defined? */
  763. if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
  764. error = ENOATTR;
  765. goto vopunlock_exit;
  766. }
  767. /* Valid for the current inode generation? */
  768. if (ueh.ueh_i_gen != ip->i_gen) {
  769. /*
  770. * The inode itself has a different generation number
  771. * than the attribute data. For now, the best solution
  772. * is to coerce this to undefined, and let it get cleaned
  773. * up by the next write or extattrctl clean.
  774. */
  775. printf("ufs_extattr_get (%s): inode number inconsistency (%d, %ju)\n",
  776. mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (uintmax_t)ip->i_gen);
  777. error = ENOATTR;
  778. goto vopunlock_exit;
  779. }
  780. /* Local size consistency check. */
  781. if (ueh.ueh_len > attribute->uele_fileheader.uef_size) {
  782. error = ENXIO;
  783. goto vopunlock_exit;
  784. }
  785. /* Return full data size if caller requested it. */
  786. if (size != nil)
  787. *size = ueh.ueh_len;
  788. /* Return data if the caller requested it. */
  789. if (uio != nil) {
  790. /* Allow for offset into the attribute data. */
  791. uio->uio_offset = base_offset + sizeof(struct
  792. ufs_extattr_header);
  793. /*
  794. * Figure out maximum to transfer -- use buffer size and
  795. * local data limit.
  796. */
  797. len = MIN(uio->uio_resid, ueh.ueh_len);
  798. old_len = uio->uio_resid;
  799. uio->uio_resid = len;
  800. error = VOP_READ(attribute->uele_backing_vnode, uio,
  801. IO_NODELOCKED, ump->um_extattr.uepm_ucred);
  802. if (error)
  803. goto vopunlock_exit;
  804. uio->uio_resid = old_len - (len - uio->uio_resid);
  805. }
  806. vopunlock_exit:
  807. if (uio != nil)
  808. uio->uio_offset = 0;
  809. if (attribute->uele_backing_vnode != vp)
  810. VOP_UNLOCK(attribute->uele_backing_vnode, 0);
  811. return (error);
  812. }
  813. /*
  814. * Vnode operation to remove a named attribute.
  815. */
  816. int
  817. ufs_deleteextattr(struct vop_deleteextattr_args *ap)
  818. /*
  819. vop_deleteextattr {
  820. IN struct vnode *a_vp;
  821. IN int a_attrnamespace;
  822. IN const char *a_name;
  823. IN struct ucred *a_cred;
  824. IN struct thread *a_td;
  825. };
  826. */
  827. {
  828. struct mount *mp = ap->a_vp->v_mount;
  829. struct ufsmount *ump = VFSTOUFS(mp);
  830. int error;
  831. ufs_extattr_uepm_lock(ump);
  832. error = ufs_extattr_rm(ap->a_vp, ap->a_attrnamespace, ap->a_name,
  833. ap->a_cred, ap->a_td);
  834. ufs_extattr_uepm_unlock(ump);
  835. return (error);
  836. }
  837. /*
  838. * Vnode operation to set a named attribute.
  839. */
  840. int
  841. ufs_setextattr(struct vop_setextattr_args *ap)
  842. /*
  843. vop_setextattr {
  844. IN struct vnode *a_vp;
  845. IN int a_attrnamespace;
  846. IN const char *a_name;
  847. INOUT struct uio *a_uio;
  848. IN struct ucred *a_cred;
  849. IN struct thread *a_td;
  850. };
  851. */
  852. {
  853. struct mount *mp = ap->a_vp->v_mount;
  854. struct ufsmount *ump = VFSTOUFS(mp);
  855. int error;
  856. /*
  857. * XXX: No longer a supported way to delete extended attributes.
  858. */
  859. if (ap->a_uio == nil)
  860. return (EINVAL);
  861. ufs_extattr_uepm_lock(ump);
  862. error = ufs_extattr_set(ap->a_vp, ap->a_attrnamespace, ap->a_name,
  863. ap->a_uio, ap->a_cred, ap->a_td);
  864. ufs_extattr_uepm_unlock(ump);
  865. return (error);
  866. }
  867. /*
  868. * Real work associated with setting a vnode's extended attributes;
  869. * assumes that the attribute lock has already been grabbed.
  870. */
  871. static int
  872. ufs_extattr_set(struct vnode *vp, int attrnamespace, const char *name,
  873. struct uio *uio, struct ucred *cred, struct thread *td)
  874. {
  875. struct ufs_extattr_list_entry *attribute;
  876. struct ufs_extattr_header ueh;
  877. struct iovec local_aiov;
  878. struct uio local_aio;
  879. struct mount *mp = vp->v_mount;
  880. struct ufsmount *ump = VFSTOUFS(mp);
  881. struct inode *ip = VTOI(vp);
  882. off_t base_offset;
  883. int error = 0, ioflag;
  884. if (vp->v_mount->mnt_flag & MNT_RDONLY)
  885. return (EROFS);
  886. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
  887. return (EOPNOTSUPP);
  888. if (!ufs_extattr_valid_attrname(attrnamespace, name))
  889. return (EINVAL);
  890. error = extattr_check_cred(vp, attrnamespace, cred, td, VWRITE);
  891. if (error)
  892. return (error);
  893. attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
  894. if (!attribute)
  895. return (ENOATTR);
  896. /*
  897. * Early rejection of invalid offsets/length.
  898. * Reject: any offset but 0 (replace)
  899. * Any size greater than attribute size limit
  900. */
  901. if (uio->uio_offset != 0 ||
  902. uio->uio_resid > attribute->uele_fileheader.uef_size)
  903. return (ENXIO);
  904. /*
  905. * Find base offset of header in file based on file header size, and
  906. * data header size + maximum data size, indexed by inode number.
  907. */
  908. base_offset = sizeof(struct ufs_extattr_fileheader) +
  909. ip->i_number * (sizeof(struct ufs_extattr_header) +
  910. attribute->uele_fileheader.uef_size);
  911. /*
  912. * Write out a data header for the data.
  913. */
  914. ueh.ueh_len = uio->uio_resid;
  915. ueh.ueh_flags = UFS_EXTATTR_ATTR_FLAG_INUSE;
  916. ueh.ueh_i_gen = ip->i_gen;
  917. local_aiov.iov_base = (caddr_t) &ueh;
  918. local_aiov.iov_len = sizeof(struct ufs_extattr_header);
  919. local_aio.uio_iov = &local_aiov;
  920. local_aio.uio_iovcnt = 1;
  921. local_aio.uio_rw = UIO_WRITE;
  922. local_aio.uio_segflg = UIO_SYSSPACE;
  923. local_aio.uio_td = td;
  924. local_aio.uio_offset = base_offset;
  925. local_aio.uio_resid = sizeof(struct ufs_extattr_header);
  926. /*
  927. * Acquire locks.
  928. *
  929. * Don't need to get a lock on the backing file if the setattr is
  930. * being applied to the backing file, as the lock is already held.
  931. */
  932. if (attribute->uele_backing_vnode != vp)
  933. vn_lock(attribute->uele_backing_vnode, LK_EXCLUSIVE | LK_RETRY);
  934. ioflag = IO_NODELOCKED;
  935. if (ufs_extattr_sync)
  936. ioflag |= IO_SYNC;
  937. error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
  938. ump->um_extattr.uepm_ucred);
  939. if (error)
  940. goto vopunlock_exit;
  941. if (local_aio.uio_resid != 0) {
  942. error = ENXIO;
  943. goto vopunlock_exit;
  944. }
  945. /*
  946. * Write out user data.
  947. */
  948. uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header);
  949. ioflag = IO_NODELOCKED;
  950. if (ufs_extattr_sync)
  951. ioflag |= IO_SYNC;
  952. error = VOP_WRITE(attribute->uele_backing_vnode, uio, ioflag,
  953. ump->um_extattr.uepm_ucred);
  954. vopunlock_exit:
  955. uio->uio_offset = 0;
  956. if (attribute->uele_backing_vnode != vp)
  957. VOP_UNLOCK(attribute->uele_backing_vnode, 0);
  958. return (error);
  959. }
  960. /*
  961. * Real work associated with removing an extended attribute from a vnode.
  962. * Assumes the attribute lock has already been grabbed.
  963. */
  964. static int
  965. ufs_extattr_rm(struct vnode *vp, int attrnamespace, const char *name,
  966. struct ucred *cred, struct thread *td)
  967. {
  968. struct ufs_extattr_list_entry *attribute;
  969. struct ufs_extattr_header ueh;
  970. struct iovec local_aiov;
  971. struct uio local_aio;
  972. struct mount *mp = vp->v_mount;
  973. struct ufsmount *ump = VFSTOUFS(mp);
  974. struct inode *ip = VTOI(vp);
  975. off_t base_offset;
  976. int error = 0, ioflag;
  977. if (vp->v_mount->mnt_flag & MNT_RDONLY)
  978. return (EROFS);
  979. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
  980. return (EOPNOTSUPP);
  981. if (!ufs_extattr_valid_attrname(attrnamespace, name))
  982. return (EINVAL);
  983. error = extattr_check_cred(vp, attrnamespace, cred, td, VWRITE);
  984. if (error)
  985. return (error);
  986. attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
  987. if (!attribute)
  988. return (ENOATTR);
  989. /*
  990. * Find base offset of header in file based on file header size, and
  991. * data header size + maximum data size, indexed by inode number.
  992. */
  993. base_offset = sizeof(struct ufs_extattr_fileheader) +
  994. ip->i_number * (sizeof(struct ufs_extattr_header) +
  995. attribute->uele_fileheader.uef_size);
  996. /*
  997. * Check to see if currently defined.
  998. */
  999. bzero(&ueh, sizeof(struct ufs_extattr_header));
  1000. local_aiov.iov_base = (caddr_t) &ueh;
  1001. local_aiov.iov_len = sizeof(struct ufs_extattr_header);
  1002. local_aio.uio_iov = &local_aiov;
  1003. local_aio.uio_iovcnt = 1;
  1004. local_aio.uio_rw = UIO_READ;
  1005. local_aio.uio_segflg = UIO_SYSSPACE;
  1006. local_aio.uio_td = td;
  1007. local_aio.uio_offset = base_offset;
  1008. local_aio.uio_resid = sizeof(struct ufs_extattr_header);
  1009. /*
  1010. * Don't need to get the lock on the backing vnode if the vnode we're
  1011. * modifying is it, as we already hold the lock.
  1012. */
  1013. if (attribute->uele_backing_vnode != vp)
  1014. vn_lock(attribute->uele_backing_vnode, LK_EXCLUSIVE | LK_RETRY);
  1015. error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
  1016. IO_NODELOCKED, ump->um_extattr.uepm_ucred);
  1017. if (error)
  1018. goto vopunlock_exit;
  1019. /* Defined? */
  1020. if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
  1021. error = ENOATTR;
  1022. goto vopunlock_exit;
  1023. }
  1024. /* Valid for the current inode generation? */
  1025. if (ueh.ueh_i_gen != ip->i_gen) {
  1026. /*
  1027. * The inode itself has a different generation number than
  1028. * the attribute data. For now, the best solution is to
  1029. * coerce this to undefined, and let it get cleaned up by
  1030. * the next write or extattrctl clean.
  1031. */
  1032. printf("ufs_extattr_rm (%s): inode number inconsistency (%d, %jd)\n",
  1033. mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen);
  1034. error = ENOATTR;
  1035. goto vopunlock_exit;
  1036. }
  1037. /* Flag it as not in use. */
  1038. ueh.ueh_flags = 0;
  1039. ueh.ueh_len = 0;
  1040. local_aiov.iov_base = (caddr_t) &ueh;
  1041. local_aiov.iov_len = sizeof(struct ufs_extattr_header);
  1042. local_aio.uio_iov = &local_aiov;
  1043. local_aio.uio_iovcnt = 1;
  1044. local_aio.uio_rw = UIO_WRITE;
  1045. local_aio.uio_segflg = UIO_SYSSPACE;
  1046. local_aio.uio_td = td;
  1047. local_aio.uio_offset = base_offset;
  1048. local_aio.uio_resid = sizeof(struct ufs_extattr_header);
  1049. ioflag = IO_NODELOCKED;
  1050. if (ufs_extattr_sync)
  1051. ioflag |= IO_SYNC;
  1052. error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
  1053. ump->um_extattr.uepm_ucred);
  1054. if (error)
  1055. goto vopunlock_exit;
  1056. if (local_aio.uio_resid != 0)
  1057. error = ENXIO;
  1058. vopunlock_exit:
  1059. VOP_UNLOCK(attribute->uele_backing_vnode, 0);
  1060. return (error);
  1061. }
  1062. /*
  1063. * Called by UFS when an inode is no longer active and should have its
  1064. * attributes stripped.
  1065. */
  1066. void
  1067. ufs_extattr_vnode_inactive(struct vnode *vp, struct thread *td)
  1068. {
  1069. struct ufs_extattr_list_entry *uele;
  1070. struct mount *mp = vp->v_mount;
  1071. struct ufsmount *ump = VFSTOUFS(mp);
  1072. /*
  1073. * In that case, we cannot lock. We should not have any active vnodes
  1074. * on the fs if this is not yet initialized but is going to be, so
  1075. * this can go unlocked.
  1076. */
  1077. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
  1078. return;
  1079. ufs_extattr_uepm_lock(ump);
  1080. if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
  1081. ufs_extattr_uepm_unlock(ump);
  1082. return;
  1083. }
  1084. LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries)
  1085. ufs_extattr_rm(vp, uele->uele_attrnamespace,
  1086. uele->uele_attrname, nil, td);
  1087. ufs_extattr_uepm_unlock(ump);
  1088. }
  1089. #endif /* !UFS_EXTATTR */