]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/ufs/ufs/ufs_extattr.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / ufs / ufs / ufs_extattr.c
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 /*
37  * Support for filesystem extended attribute: UFS-specific support functions.
38  */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 #include "opt_ufs.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/namei.h>
49 #include <sys/malloc.h>
50 #include <sys/fcntl.h>
51 #include <sys/priv.h>
52 #include <sys/proc.h>
53 #include <sys/vnode.h>
54 #include <sys/mount.h>
55 #include <sys/lock.h>
56 #include <sys/dirent.h>
57 #include <sys/extattr.h>
58 #include <sys/sx.h>
59 #include <sys/sysctl.h>
60
61 #include <vm/uma.h>
62
63 #include <ufs/ufs/dir.h>
64 #include <ufs/ufs/extattr.h>
65 #include <ufs/ufs/quota.h>
66 #include <ufs/ufs/ufsmount.h>
67 #include <ufs/ufs/inode.h>
68 #include <ufs/ufs/ufs_extern.h>
69
70 #ifdef UFS_EXTATTR
71
72 static MALLOC_DEFINE(M_UFS_EXTATTR, "ufs_extattr", "ufs extended attribute");
73
74 static int ufs_extattr_sync = 0;
75 SYSCTL_INT(_debug, OID_AUTO, ufs_extattr_sync, CTLFLAG_RW, &ufs_extattr_sync,
76     0, "");
77
78 static int      ufs_extattr_valid_attrname(int attrnamespace,
79                     const char *attrname);
80 static int      ufs_extattr_enable_with_open(struct ufsmount *ump,
81                     struct vnode *vp, int attrnamespace, const char *attrname,
82                     struct thread *td);
83 static int      ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
84                     const char *attrname, struct vnode *backing_vnode,
85                     struct thread *td);
86 static int      ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
87                     const char *attrname, struct thread *td);
88 static int      ufs_extattr_get(struct vnode *vp, int attrnamespace,
89                     const char *name, struct uio *uio, size_t *size,
90                     struct ucred *cred, struct thread *td);
91 static int      ufs_extattr_set(struct vnode *vp, int attrnamespace,
92                     const char *name, struct uio *uio, struct ucred *cred,
93                     struct thread *td);
94 static int      ufs_extattr_rm(struct vnode *vp, int attrnamespace,
95                     const char *name, struct ucred *cred, struct thread *td);
96 static int      ufs_extattr_autostart_locked(struct mount *mp,
97                     struct thread *td);
98 static int      ufs_extattr_start_locked(struct ufsmount *ump,
99                     struct thread *td);
100
101 /*
102  * Per-FS attribute lock protecting attribute operations.
103  *
104  * XXXRW: Perhaps something more fine-grained would be appropriate, but at
105  * the end of the day we're going to contend on the vnode lock for the
106  * backing file anyway.
107  */
108 static void
109 ufs_extattr_uepm_lock(struct ufsmount *ump, struct thread *td)
110 {
111
112         sx_xlock(&ump->um_extattr.uepm_lock);
113 }
114
115 static void
116 ufs_extattr_uepm_unlock(struct ufsmount *ump, struct thread *td)
117 {
118
119         sx_xunlock(&ump->um_extattr.uepm_lock);
120 }
121
122 /*-
123  * Determine whether the name passed is a valid name for an actual
124  * attribute.
125  *
126  * Invalid currently consists of:
127  *       NULL pointer for attrname
128  *       zero-length attrname (used to retrieve application attribute list)
129  */
130 static int
131 ufs_extattr_valid_attrname(int attrnamespace, const char *attrname)
132 {
133
134         if (attrname == NULL)
135                 return (0);
136         if (strlen(attrname) == 0)
137                 return (0);
138         return (1);
139 }
140
141 /*
142  * Locate an attribute given a name and mountpoint.
143  * Must be holding uepm lock for the mount point.
144  */
145 static struct ufs_extattr_list_entry *
146 ufs_extattr_find_attr(struct ufsmount *ump, int attrnamespace,
147     const char *attrname)
148 {
149         struct ufs_extattr_list_entry *search_attribute;
150
151         sx_assert(&ump->um_extattr.uepm_lock, SA_XLOCKED);
152
153         for (search_attribute = LIST_FIRST(&ump->um_extattr.uepm_list);
154             search_attribute != NULL;
155             search_attribute = LIST_NEXT(search_attribute, uele_entries)) {
156                 if (!(strncmp(attrname, search_attribute->uele_attrname,
157                     UFS_EXTATTR_MAXEXTATTRNAME)) &&
158                     (attrnamespace == search_attribute->uele_attrnamespace)) {
159                         return (search_attribute);
160                 }
161         }
162
163         return (0);
164 }
165
166 /*
167  * Initialize per-FS structures supporting extended attributes.  Do not
168  * start extended attributes yet.
169  */
170 void
171 ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm)
172 {
173
174         uepm->uepm_flags = 0;
175         LIST_INIT(&uepm->uepm_list);
176         sx_init(&uepm->uepm_lock, "ufs_extattr_sx");
177         uepm->uepm_flags |= UFS_EXTATTR_UEPM_INITIALIZED;
178 }
179
180 /*
181  * Destroy per-FS structures supporting extended attributes.  Assumes
182  * that EAs have already been stopped, and will panic if not.
183  */
184 void
185 ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm)
186 {
187
188         if (!(uepm->uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
189                 panic("ufs_extattr_uepm_destroy: not initialized");
190
191         if ((uepm->uepm_flags & UFS_EXTATTR_UEPM_STARTED))
192                 panic("ufs_extattr_uepm_destroy: called while still started");
193
194         /*
195          * It's not clear that either order for the next two lines is
196          * ideal, and it should never be a problem if this is only called
197          * during unmount, and with vfs_busy().
198          */
199         uepm->uepm_flags &= ~UFS_EXTATTR_UEPM_INITIALIZED;
200         sx_destroy(&uepm->uepm_lock);
201 }
202
203 /*
204  * Start extended attribute support on an FS.
205  */
206 int
207 ufs_extattr_start(struct mount *mp, struct thread *td)
208 {
209         struct ufsmount *ump;
210         int error = 0;
211
212         ump = VFSTOUFS(mp);
213
214         ufs_extattr_uepm_lock(ump, td);
215         error = ufs_extattr_start_locked(ump, td);
216         ufs_extattr_uepm_unlock(ump, td);
217         return (error);
218 }
219
220 static int
221 ufs_extattr_start_locked(struct ufsmount *ump, struct thread *td)
222 {
223         if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
224                 return (EOPNOTSUPP);
225         if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)
226                 return (EBUSY);
227
228         ump->um_extattr.uepm_flags |= UFS_EXTATTR_UEPM_STARTED;
229         ump->um_extattr.uepm_ucred = crhold(td->td_ucred);
230         return (0);
231 }
232
233 #ifdef UFS_EXTATTR_AUTOSTART
234 /*
235  * Helper routine: given a locked parent directory and filename, return
236  * the locked vnode of the inode associated with the name.  Will not
237  * follow symlinks, may return any type of vnode.  Lock on parent will
238  * be released even in the event of a failure.  In the event that the
239  * target is the parent (i.e., "."), there will be two references and
240  * one lock, requiring the caller to possibly special-case.
241  */
242 #define UE_GETDIR_LOCKPARENT    1
243 #define UE_GETDIR_LOCKPARENT_DONT       2
244 static int
245 ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, char *dirname,
246     struct vnode **vp, struct thread *td)
247 {
248         struct vop_cachedlookup_args vargs;
249         struct componentname cnp;
250         struct vnode *target_vp;
251         int error;
252
253         bzero(&cnp, sizeof(cnp));
254         cnp.cn_nameiop = LOOKUP;
255         cnp.cn_flags = ISLASTCN;
256         if (lockparent == UE_GETDIR_LOCKPARENT)
257                 cnp.cn_flags |= LOCKPARENT;
258         cnp.cn_lkflags = LK_EXCLUSIVE;
259         cnp.cn_thread = td;
260         cnp.cn_cred = td->td_ucred;
261         cnp.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
262         cnp.cn_nameptr = cnp.cn_pnbuf;
263         error = copystr(dirname, cnp.cn_pnbuf, MAXPATHLEN,
264             (size_t *) &cnp.cn_namelen);
265         if (error) {
266                 if (lockparent == UE_GETDIR_LOCKPARENT_DONT) {
267                         VOP_UNLOCK(start_dvp, 0, td);
268                 }
269                 uma_zfree(namei_zone, cnp.cn_pnbuf);
270                 printf("ufs_extattr_lookup: copystr failed\n");
271                 return (error);
272         }
273         cnp.cn_namelen--;       /* trim nul termination */
274         vargs.a_gen.a_desc = NULL;
275         vargs.a_dvp = start_dvp;
276         vargs.a_vpp = &target_vp;
277         vargs.a_cnp = &cnp;
278         error = ufs_lookup(&vargs);
279         uma_zfree(namei_zone, cnp.cn_pnbuf);
280         if (error) {
281                 /*
282                  * Error condition, may have to release the lock on the parent
283                  * if ufs_lookup() didn't.
284                  */
285                 if (lockparent == UE_GETDIR_LOCKPARENT_DONT)
286                         VOP_UNLOCK(start_dvp, 0, td);
287
288                 /*
289                  * Check that ufs_lookup() didn't release the lock when we
290                  * didn't want it to.
291                  */
292                 if (lockparent == UE_GETDIR_LOCKPARENT)
293                         ASSERT_VOP_LOCKED(start_dvp, "ufs_extattr_lookup");
294
295                 return (error);
296         }
297 /*
298         if (target_vp == start_dvp)
299                 panic("ufs_extattr_lookup: target_vp == start_dvp");
300 */
301
302         if (target_vp != start_dvp && lockparent == UE_GETDIR_LOCKPARENT_DONT)
303                 VOP_UNLOCK(start_dvp, 0, td);
304
305         if (lockparent == UE_GETDIR_LOCKPARENT)
306                 ASSERT_VOP_LOCKED(start_dvp, "ufs_extattr_lookup");
307
308         /* printf("ufs_extattr_lookup: success\n"); */
309         *vp = target_vp;
310         return (0);
311 }
312 #endif /* !UFS_EXTATTR_AUTOSTART */
313
314 /*
315  * Enable an EA using the passed filesystem, backing vnode, attribute name,
316  * namespace, and proc.  Will perform a VOP_OPEN() on the vp, so expects vp
317  * to be locked when passed in.  The vnode will be returned unlocked,
318  * regardless of success/failure of the function.  As a result, the caller
319  * will always need to vrele(), but not vput().
320  */
321 static int
322 ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp,
323     int attrnamespace, const char *attrname, struct thread *td)
324 {
325         int error;
326
327         error = VOP_OPEN(vp, FREAD|FWRITE, td->td_ucred, td, NULL);
328         if (error) {
329                 printf("ufs_extattr_enable_with_open.VOP_OPEN(): failed "
330                     "with %d\n", error);
331                 VOP_UNLOCK(vp, 0, td);
332                 return (error);
333         }
334
335         vp->v_writecount++;
336
337         vref(vp);
338
339         VOP_UNLOCK(vp, 0, td);
340
341         error = ufs_extattr_enable(ump, attrnamespace, attrname, vp, td);
342         if (error != 0)
343                 vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
344         return (error);
345 }
346
347 #ifdef UFS_EXTATTR_AUTOSTART
348 /*
349  * Given a locked directory vnode, iterate over the names in the directory
350  * and use ufs_extattr_lookup() to retrieve locked vnodes of potential
351  * attribute files.  Then invoke ufs_extattr_enable_with_open() on each
352  * to attempt to start the attribute.  Leaves the directory locked on
353  * exit.
354  */
355 static int
356 ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp,
357     int attrnamespace, struct thread *td)
358 {
359         struct vop_readdir_args vargs;
360         struct dirent *dp, *edp;
361         struct vnode *attr_vp;
362         struct uio auio;
363         struct iovec aiov;
364         char *dirbuf;
365         int error, eofflag = 0;
366
367         if (dvp->v_type != VDIR)
368                 return (ENOTDIR);
369
370         MALLOC(dirbuf, char *, DIRBLKSIZ, M_TEMP, M_WAITOK);
371
372         auio.uio_iov = &aiov;
373         auio.uio_iovcnt = 1;
374         auio.uio_rw = UIO_READ;
375         auio.uio_segflg = UIO_SYSSPACE;
376         auio.uio_td = td;
377         auio.uio_offset = 0;
378
379         vargs.a_gen.a_desc = NULL;
380         vargs.a_vp = dvp;
381         vargs.a_uio = &auio;
382         vargs.a_cred = td->td_ucred;
383         vargs.a_eofflag = &eofflag;
384         vargs.a_ncookies = NULL;
385         vargs.a_cookies = NULL;
386
387         while (!eofflag) {
388                 auio.uio_resid = DIRBLKSIZ;
389                 aiov.iov_base = dirbuf;
390                 aiov.iov_len = DIRBLKSIZ;
391                 error = ufs_readdir(&vargs);
392                 if (error) {
393                         printf("ufs_extattr_iterate_directory: ufs_readdir "
394                             "%d\n", error);
395                         return (error);
396                 }
397
398                 /*
399                  * XXXRW: While in UFS, we always get DIRBLKSIZ returns from
400                  * the directory code on success, on other file systems this
401                  * may not be the case.  For portability, we should check the
402                  * read length on return from ufs_readdir().
403                  */
404                 edp = (struct dirent *)&dirbuf[DIRBLKSIZ];
405                 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
406 #if (BYTE_ORDER == LITTLE_ENDIAN)
407                         dp->d_type = dp->d_namlen;
408                         dp->d_namlen = 0;
409 #else
410                         dp->d_type = 0;
411 #endif
412                         if (dp->d_reclen == 0)
413                                 break;
414                         error = ufs_extattr_lookup(dvp, UE_GETDIR_LOCKPARENT,
415                             dp->d_name, &attr_vp, td);
416                         if (error) {
417                                 printf("ufs_extattr_iterate_directory: lookup "
418                                     "%s %d\n", dp->d_name, error);
419                         } else if (attr_vp == dvp) {
420                                 vrele(attr_vp);
421                         } else if (attr_vp->v_type != VREG) {
422                                 vput(attr_vp);
423                         } else {
424                                 error = ufs_extattr_enable_with_open(ump,
425                                     attr_vp, attrnamespace, dp->d_name, td);
426                                 vrele(attr_vp);
427                                 if (error) {
428                                         printf("ufs_extattr_iterate_directory: "
429                                             "enable %s %d\n", dp->d_name,
430                                             error);
431                                 } else if (bootverbose) {
432                                         printf("UFS autostarted EA %s\n",
433                                             dp->d_name);
434                                 }
435                         }
436                         dp = (struct dirent *) ((char *)dp + dp->d_reclen);
437                         if (dp >= edp)
438                                 break;
439                 }
440         }
441         FREE(dirbuf, M_TEMP);
442         
443         return (0);
444 }
445
446 /*
447  * Auto-start of extended attributes, to be executed (optionally) at
448  * mount-time.
449  */
450 int
451 ufs_extattr_autostart(struct mount *mp, struct thread *td)
452 {
453         struct ufsmount *ump;
454         int error;
455
456         ump = VFSTOUFS(mp);
457         ufs_extattr_uepm_lock(ump, td);
458         error = ufs_extattr_autostart_locked(mp, td);
459         ufs_extattr_uepm_unlock(ump, td);
460         return (error);
461 }
462
463 static int
464 ufs_extattr_autostart_locked(struct mount *mp, struct thread *td)
465 {
466         struct vnode *rvp, *attr_dvp, *attr_system_dvp, *attr_user_dvp;
467         struct ufsmount *ump = VFSTOUFS(mp);
468         int error;
469
470         /*
471          * UFS_EXTATTR applies only to UFS1, as UFS2 uses native extended
472          * attributes, so don't autostart.
473          */
474         if (ump->um_fstype != UFS1)
475                 return (0);
476
477         /*
478          * Does UFS_EXTATTR_FSROOTSUBDIR exist off the filesystem root?
479          * If so, automatically start EA's.
480          */
481         error = VFS_ROOT(mp, LK_EXCLUSIVE, &rvp, td);
482         if (error) {
483                 printf("ufs_extattr_autostart.VFS_ROOT() returned %d\n",
484                     error);
485                 return (error);
486         }
487
488         error = ufs_extattr_lookup(rvp, UE_GETDIR_LOCKPARENT_DONT,
489             UFS_EXTATTR_FSROOTSUBDIR, &attr_dvp, td);
490         if (error) {
491                 /* rvp ref'd but now unlocked */
492                 vrele(rvp);
493                 return (error);
494         }
495         if (rvp == attr_dvp) {
496                 /* Should never happen. */
497                 vput(rvp);
498                 vrele(attr_dvp);
499                 return (EINVAL);
500         }
501         vrele(rvp);
502
503         if (attr_dvp->v_type != VDIR) {
504                 printf("ufs_extattr_autostart: %s != VDIR\n",
505                     UFS_EXTATTR_FSROOTSUBDIR);
506                 goto return_vput_attr_dvp;
507         }
508
509         error = ufs_extattr_start_locked(ump, td);
510         if (error) {
511                 printf("ufs_extattr_autostart: ufs_extattr_start failed (%d)\n",
512                     error);
513                 goto return_vput_attr_dvp;
514         }
515
516         /*
517          * Look for two subdirectories: UFS_EXTATTR_SUBDIR_SYSTEM,
518          * UFS_EXTATTR_SUBDIR_USER.  For each, iterate over the sub-directory,
519          * and start with appropriate type.  Failures in either don't
520          * result in an over-all failure.  attr_dvp is left locked to
521          * be cleaned up on exit.
522          */
523         error = ufs_extattr_lookup(attr_dvp, UE_GETDIR_LOCKPARENT,
524             UFS_EXTATTR_SUBDIR_SYSTEM, &attr_system_dvp, td);
525         if (!error) {
526                 error = ufs_extattr_iterate_directory(VFSTOUFS(mp),
527                     attr_system_dvp, EXTATTR_NAMESPACE_SYSTEM, td);
528                 if (error)
529                         printf("ufs_extattr_iterate_directory returned %d\n",
530                             error);
531                 vput(attr_system_dvp);
532         }
533
534         error = ufs_extattr_lookup(attr_dvp, UE_GETDIR_LOCKPARENT,
535             UFS_EXTATTR_SUBDIR_USER, &attr_user_dvp, td);
536         if (!error) {
537                 error = ufs_extattr_iterate_directory(VFSTOUFS(mp),
538                     attr_user_dvp, EXTATTR_NAMESPACE_USER, td);
539                 if (error)
540                         printf("ufs_extattr_iterate_directory returned %d\n",
541                             error);
542                 vput(attr_user_dvp);
543         }
544
545         /* Mask startup failures in sub-directories. */
546         error = 0;
547
548 return_vput_attr_dvp:
549         vput(attr_dvp);
550
551         return (error);
552 }
553 #endif /* !UFS_EXTATTR_AUTOSTART */
554
555 /*
556  * Stop extended attribute support on an FS.
557  */
558 int
559 ufs_extattr_stop(struct mount *mp, struct thread *td)
560 {
561         struct ufs_extattr_list_entry *uele;
562         struct ufsmount *ump = VFSTOUFS(mp);
563         int error = 0;
564
565         ufs_extattr_uepm_lock(ump, td);
566
567         if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
568                 error = EOPNOTSUPP;
569                 goto unlock;
570         }
571
572         while ((uele = LIST_FIRST(&ump->um_extattr.uepm_list)) != NULL) {
573                 ufs_extattr_disable(ump, uele->uele_attrnamespace,
574                     uele->uele_attrname, td);
575         }
576
577         ump->um_extattr.uepm_flags &= ~UFS_EXTATTR_UEPM_STARTED;
578
579         crfree(ump->um_extattr.uepm_ucred);
580         ump->um_extattr.uepm_ucred = NULL;
581
582 unlock:
583         ufs_extattr_uepm_unlock(ump, td);
584
585         return (error);
586 }
587
588 /*
589  * Enable a named attribute on the specified filesystem; provide an
590  * unlocked backing vnode to hold the attribute data.
591  */
592 static int
593 ufs_extattr_enable(struct ufsmount *ump, int attrnamespace,
594     const char *attrname, struct vnode *backing_vnode, struct thread *td)
595 {
596         struct ufs_extattr_list_entry *attribute;
597         struct iovec aiov;
598         struct uio auio;
599         int error = 0;
600
601         if (!ufs_extattr_valid_attrname(attrnamespace, attrname))
602                 return (EINVAL);
603         if (backing_vnode->v_type != VREG)
604                 return (EINVAL);
605
606         MALLOC(attribute, struct ufs_extattr_list_entry *,
607             sizeof(struct ufs_extattr_list_entry), M_UFS_EXTATTR, M_WAITOK);
608         if (attribute == NULL)
609                 return (ENOMEM);
610
611         if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
612                 error = EOPNOTSUPP;
613                 goto free_exit;
614         }
615
616         if (ufs_extattr_find_attr(ump, attrnamespace, attrname)) {
617                 error = EEXIST;
618                 goto free_exit;
619         }
620
621         strncpy(attribute->uele_attrname, attrname,
622             UFS_EXTATTR_MAXEXTATTRNAME);
623         attribute->uele_attrnamespace = attrnamespace;
624         bzero(&attribute->uele_fileheader,
625             sizeof(struct ufs_extattr_fileheader));
626         
627         attribute->uele_backing_vnode = backing_vnode;
628
629         auio.uio_iov = &aiov;
630         auio.uio_iovcnt = 1;
631         aiov.iov_base = (caddr_t) &attribute->uele_fileheader;
632         aiov.iov_len = sizeof(struct ufs_extattr_fileheader);
633         auio.uio_resid = sizeof(struct ufs_extattr_fileheader);
634         auio.uio_offset = (off_t) 0;
635         auio.uio_segflg = UIO_SYSSPACE;
636         auio.uio_rw = UIO_READ;
637         auio.uio_td = td;
638
639         vn_lock(backing_vnode, LK_SHARED | LK_RETRY, td);
640         error = VOP_READ(backing_vnode, &auio, IO_NODELOCKED,
641             ump->um_extattr.uepm_ucred);
642
643         if (error)
644                 goto unlock_free_exit;
645
646         if (auio.uio_resid != 0) {
647                 printf("ufs_extattr_enable: malformed attribute header\n");
648                 error = EINVAL;
649                 goto unlock_free_exit;
650         }
651
652         if (attribute->uele_fileheader.uef_magic != UFS_EXTATTR_MAGIC) {
653                 printf("ufs_extattr_enable: invalid attribute header magic\n");
654                 error = EINVAL;
655                 goto unlock_free_exit;
656         }
657
658         if (attribute->uele_fileheader.uef_version != UFS_EXTATTR_VERSION) {
659                 printf("ufs_extattr_enable: incorrect attribute header "
660                     "version\n");
661                 error = EINVAL;
662                 goto unlock_free_exit;
663         }
664
665         ASSERT_VOP_LOCKED(backing_vnode, "ufs_extattr_enable");
666         LIST_INSERT_HEAD(&ump->um_extattr.uepm_list, attribute,
667             uele_entries);
668
669         VOP_UNLOCK(backing_vnode, 0, td);
670         return (0);
671
672 unlock_free_exit:
673         VOP_UNLOCK(backing_vnode, 0, td);
674
675 free_exit:
676         FREE(attribute, M_UFS_EXTATTR);
677         return (error);
678 }
679
680 /*
681  * Disable extended attribute support on an FS.
682  */
683 static int
684 ufs_extattr_disable(struct ufsmount *ump, int attrnamespace,
685     const char *attrname, struct thread *td)
686 {
687         struct ufs_extattr_list_entry *uele;
688         int error = 0;
689
690         if (!ufs_extattr_valid_attrname(attrnamespace, attrname))
691                 return (EINVAL);
692
693         uele = ufs_extattr_find_attr(ump, attrnamespace, attrname);
694         if (!uele)
695                 return (ENOATTR);
696
697         LIST_REMOVE(uele, uele_entries);
698
699         vn_lock(uele->uele_backing_vnode, LK_SHARED | LK_RETRY,
700             td);
701         ASSERT_VOP_LOCKED(uele->uele_backing_vnode, "ufs_extattr_disable");
702         VOP_UNLOCK(uele->uele_backing_vnode, 0, td);
703         error = vn_close(uele->uele_backing_vnode, FREAD|FWRITE,
704             td->td_ucred, td);
705
706         FREE(uele, M_UFS_EXTATTR);
707
708         return (error);
709 }
710
711 /*
712  * VFS call to manage extended attributes in UFS.  If filename_vp is
713  * non-NULL, it must be passed in locked, and regardless of errors in
714  * processing, will be unlocked.
715  */
716 int
717 ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
718     int attrnamespace, const char *attrname, struct thread *td)
719 {
720         struct ufsmount *ump = VFSTOUFS(mp);
721         int error;
722
723         /*
724          * Processes with privilege, but in jail, are not allowed to
725          * configure extended attributes.
726          */
727         error = priv_check(td, PRIV_UFS_EXTATTRCTL);
728         if (error) {
729                 if (filename_vp != NULL)
730                         VOP_UNLOCK(filename_vp, 0, td);
731                 return (error);
732         }
733
734         /*
735          * We only allow extattrctl(2) on UFS1 file systems, as UFS2 uses
736          * native extended attributes.
737          */
738         if (ump->um_fstype != UFS1) {
739                 if (filename_vp != NULL)
740                         VOP_UNLOCK(filename_vp, 0, td);
741                 return (EOPNOTSUPP);
742         }
743
744         switch(cmd) {
745         case UFS_EXTATTR_CMD_START:
746                 if (filename_vp != NULL) {
747                         VOP_UNLOCK(filename_vp, 0, td);
748                         return (EINVAL);
749                 }
750                 if (attrname != NULL)
751                         return (EINVAL);
752
753                 error = ufs_extattr_start(mp, td);
754
755                 return (error);
756                 
757         case UFS_EXTATTR_CMD_STOP:
758                 if (filename_vp != NULL) {
759                         VOP_UNLOCK(filename_vp, 0, td);
760                         return (EINVAL);
761                 }
762                 if (attrname != NULL)
763                         return (EINVAL);
764
765                 error = ufs_extattr_stop(mp, td);
766
767                 return (error);
768
769         case UFS_EXTATTR_CMD_ENABLE:
770
771                 if (filename_vp == NULL)
772                         return (EINVAL);
773                 if (attrname == NULL) {
774                         VOP_UNLOCK(filename_vp, 0, td);
775                         return (EINVAL);
776                 }
777
778                 /*
779                  * ufs_extattr_enable_with_open() will always unlock the
780                  * vnode, regardless of failure.
781                  */
782                 ufs_extattr_uepm_lock(ump, td);
783                 error = ufs_extattr_enable_with_open(ump, filename_vp,
784                     attrnamespace, attrname, td);
785                 ufs_extattr_uepm_unlock(ump, td);
786
787                 return (error);
788
789         case UFS_EXTATTR_CMD_DISABLE:
790
791                 if (filename_vp != NULL) {
792                         VOP_UNLOCK(filename_vp, 0, td);
793                         return (EINVAL);
794                 }
795                 if (attrname == NULL)
796                         return (EINVAL);
797
798                 ufs_extattr_uepm_lock(ump, td);
799                 error = ufs_extattr_disable(ump, attrnamespace, attrname,
800                     td);
801                 ufs_extattr_uepm_unlock(ump, td);
802
803                 return (error);
804
805         default:
806                 return (EINVAL);
807         }
808 }
809
810 /*
811  * Vnode operating to retrieve a named extended attribute.
812  */
813 int
814 ufs_getextattr(struct vop_getextattr_args *ap)
815 /*
816 vop_getextattr {
817         IN struct vnode *a_vp;
818         IN int a_attrnamespace;
819         IN const char *a_name;
820         INOUT struct uio *a_uio;
821         OUT size_t *a_size;
822         IN struct ucred *a_cred;
823         IN struct thread *a_td;
824 };
825 */
826 {
827         struct mount *mp = ap->a_vp->v_mount;
828         struct ufsmount *ump = VFSTOUFS(mp);
829         int error;
830
831         ufs_extattr_uepm_lock(ump, ap->a_td);
832
833         error = ufs_extattr_get(ap->a_vp, ap->a_attrnamespace, ap->a_name,
834             ap->a_uio, ap->a_size, ap->a_cred, ap->a_td);
835
836         ufs_extattr_uepm_unlock(ump, ap->a_td);
837
838         return (error);
839 }
840
841 /*
842  * Real work associated with retrieving a named attribute--assumes that
843  * the attribute lock has already been grabbed.
844  */
845 static int
846 ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
847     struct uio *uio, size_t *size, struct ucred *cred, struct thread *td)
848 {
849         struct ufs_extattr_list_entry *attribute;
850         struct ufs_extattr_header ueh;
851         struct iovec local_aiov;
852         struct uio local_aio;
853         struct mount *mp = vp->v_mount;
854         struct ufsmount *ump = VFSTOUFS(mp);
855         struct inode *ip = VTOI(vp);
856         off_t base_offset;
857         size_t len, old_len;
858         int error = 0;
859
860         if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
861                 return (EOPNOTSUPP);
862
863         if (strlen(name) == 0)
864                 return (EINVAL);
865
866         error = extattr_check_cred(vp, attrnamespace, cred, td, IREAD);
867         if (error)
868                 return (error);
869
870         attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
871         if (!attribute)
872                 return (ENOATTR);
873
874         /*
875          * Allow only offsets of zero to encourage the read/replace
876          * extended attribute semantic.  Otherwise we can't guarantee
877          * atomicity, as we don't provide locks for extended attributes.
878          */
879         if (uio != NULL && uio->uio_offset != 0)
880                 return (ENXIO);
881
882         /*
883          * Find base offset of header in file based on file header size, and
884          * data header size + maximum data size, indexed by inode number.
885          */
886         base_offset = sizeof(struct ufs_extattr_fileheader) +
887             ip->i_number * (sizeof(struct ufs_extattr_header) +
888             attribute->uele_fileheader.uef_size);
889
890         /*
891          * Read in the data header to see if the data is defined, and if so
892          * how much.
893          */
894         bzero(&ueh, sizeof(struct ufs_extattr_header));
895         local_aiov.iov_base = (caddr_t) &ueh;
896         local_aiov.iov_len = sizeof(struct ufs_extattr_header);
897         local_aio.uio_iov = &local_aiov;
898         local_aio.uio_iovcnt = 1;
899         local_aio.uio_rw = UIO_READ;
900         local_aio.uio_segflg = UIO_SYSSPACE;
901         local_aio.uio_td = td;
902         local_aio.uio_offset = base_offset;
903         local_aio.uio_resid = sizeof(struct ufs_extattr_header);
904         
905         /*
906          * Acquire locks.
907          *
908          * Don't need to get a lock on the backing file if the getattr is
909          * being applied to the backing file, as the lock is already held.
910          */
911         if (attribute->uele_backing_vnode != vp)
912                 vn_lock(attribute->uele_backing_vnode, LK_SHARED |
913                     LK_RETRY, td);
914
915         error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
916             IO_NODELOCKED, ump->um_extattr.uepm_ucred);
917         if (error)
918                 goto vopunlock_exit;
919
920         /* Defined? */
921         if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
922                 error = ENOATTR;
923                 goto vopunlock_exit;
924         }
925
926         /* Valid for the current inode generation? */
927         if (ueh.ueh_i_gen != ip->i_gen) {
928                 /*
929                  * The inode itself has a different generation number
930                  * than the attribute data.  For now, the best solution
931                  * is to coerce this to undefined, and let it get cleaned
932                  * up by the next write or extattrctl clean.
933                  */
934                 printf("ufs_extattr_get (%s): inode number inconsistency (%d, %jd)\n",
935                     mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen);
936                 error = ENOATTR;
937                 goto vopunlock_exit;
938         }
939
940         /* Local size consistency check. */
941         if (ueh.ueh_len > attribute->uele_fileheader.uef_size) {
942                 error = ENXIO;
943                 goto vopunlock_exit;
944         }
945
946         /* Return full data size if caller requested it. */
947         if (size != NULL)
948                 *size = ueh.ueh_len;
949
950         /* Return data if the caller requested it. */
951         if (uio != NULL) {
952                 /* Allow for offset into the attribute data. */
953                 uio->uio_offset = base_offset + sizeof(struct
954                     ufs_extattr_header);
955
956                 /*
957                  * Figure out maximum to transfer -- use buffer size and
958                  * local data limit.
959                  */
960                 len = MIN(uio->uio_resid, ueh.ueh_len);
961                 old_len = uio->uio_resid;
962                 uio->uio_resid = len;
963
964                 error = VOP_READ(attribute->uele_backing_vnode, uio,
965                     IO_NODELOCKED, ump->um_extattr.uepm_ucred);
966                 if (error)
967                         goto vopunlock_exit;
968
969                 uio->uio_resid = old_len - (len - uio->uio_resid);
970         }
971
972 vopunlock_exit:
973
974         if (uio != NULL)
975                 uio->uio_offset = 0;
976
977         if (attribute->uele_backing_vnode != vp)
978                 VOP_UNLOCK(attribute->uele_backing_vnode, 0, td);
979
980         return (error);
981 }
982
983 /*
984  * Vnode operation to remove a named attribute.
985  */
986 int
987 ufs_deleteextattr(struct vop_deleteextattr_args *ap)
988 /*
989 vop_deleteextattr {
990         IN struct vnode *a_vp;
991         IN int a_attrnamespace;
992         IN const char *a_name;
993         IN struct ucred *a_cred;
994         IN struct thread *a_td;
995 };
996 */
997 {
998         struct mount *mp = ap->a_vp->v_mount;
999         struct ufsmount *ump = VFSTOUFS(mp); 
1000         int error;
1001
1002         ufs_extattr_uepm_lock(ump, ap->a_td);
1003
1004         error = ufs_extattr_rm(ap->a_vp, ap->a_attrnamespace, ap->a_name,
1005             ap->a_cred, ap->a_td);
1006
1007
1008         ufs_extattr_uepm_unlock(ump, ap->a_td);
1009
1010         return (error);
1011 }
1012
1013 /*
1014  * Vnode operation to set a named attribute.
1015  */
1016 int
1017 ufs_setextattr(struct vop_setextattr_args *ap)
1018 /*
1019 vop_setextattr {
1020         IN struct vnode *a_vp;
1021         IN int a_attrnamespace;
1022         IN const char *a_name;
1023         INOUT struct uio *a_uio;
1024         IN struct ucred *a_cred;
1025         IN struct thread *a_td;
1026 };
1027 */
1028 {
1029         struct mount *mp = ap->a_vp->v_mount;
1030         struct ufsmount *ump = VFSTOUFS(mp); 
1031         int error;
1032
1033         ufs_extattr_uepm_lock(ump, ap->a_td);
1034
1035         /*
1036          * XXX: No longer a supported way to delete extended attributes.
1037          */
1038         if (ap->a_uio == NULL)
1039                 return (EINVAL);
1040
1041         error = ufs_extattr_set(ap->a_vp, ap->a_attrnamespace, ap->a_name,
1042             ap->a_uio, ap->a_cred, ap->a_td);
1043
1044         ufs_extattr_uepm_unlock(ump, ap->a_td);
1045
1046         return (error);
1047 }
1048
1049 /*
1050  * Real work associated with setting a vnode's extended attributes;
1051  * assumes that the attribute lock has already been grabbed.
1052  */
1053 static int
1054 ufs_extattr_set(struct vnode *vp, int attrnamespace, const char *name,
1055     struct uio *uio, struct ucred *cred, struct thread *td)
1056 {
1057         struct ufs_extattr_list_entry *attribute;
1058         struct ufs_extattr_header ueh;
1059         struct iovec local_aiov;
1060         struct uio local_aio;
1061         struct mount *mp = vp->v_mount;
1062         struct ufsmount *ump = VFSTOUFS(mp);
1063         struct inode *ip = VTOI(vp);
1064         off_t base_offset;
1065         int error = 0, ioflag;
1066
1067         if (vp->v_mount->mnt_flag & MNT_RDONLY)
1068                 return (EROFS);
1069         if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
1070                 return (EOPNOTSUPP);
1071         if (!ufs_extattr_valid_attrname(attrnamespace, name))
1072                 return (EINVAL);
1073
1074         error = extattr_check_cred(vp, attrnamespace, cred, td, IWRITE);
1075         if (error)
1076                 return (error);
1077
1078         attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
1079         if (!attribute)
1080                 return (ENOATTR);
1081
1082         /*
1083          * Early rejection of invalid offsets/length.
1084          * Reject: any offset but 0 (replace)
1085          *       Any size greater than attribute size limit
1086          */
1087         if (uio->uio_offset != 0 ||
1088             uio->uio_resid > attribute->uele_fileheader.uef_size)
1089                 return (ENXIO);
1090
1091         /*
1092          * Find base offset of header in file based on file header size, and
1093          * data header size + maximum data size, indexed by inode number.
1094          */
1095         base_offset = sizeof(struct ufs_extattr_fileheader) +
1096             ip->i_number * (sizeof(struct ufs_extattr_header) +
1097             attribute->uele_fileheader.uef_size);
1098
1099         /*
1100          * Write out a data header for the data.
1101          */
1102         ueh.ueh_len = uio->uio_resid;
1103         ueh.ueh_flags = UFS_EXTATTR_ATTR_FLAG_INUSE;
1104         ueh.ueh_i_gen = ip->i_gen;
1105         local_aiov.iov_base = (caddr_t) &ueh;
1106         local_aiov.iov_len = sizeof(struct ufs_extattr_header);
1107         local_aio.uio_iov = &local_aiov;
1108         local_aio.uio_iovcnt = 1;
1109         local_aio.uio_rw = UIO_WRITE;
1110         local_aio.uio_segflg = UIO_SYSSPACE;
1111         local_aio.uio_td = td;
1112         local_aio.uio_offset = base_offset;
1113         local_aio.uio_resid = sizeof(struct ufs_extattr_header);
1114
1115         /*
1116          * Acquire locks.
1117          *
1118          * Don't need to get a lock on the backing file if the setattr is
1119          * being applied to the backing file, as the lock is already held.
1120          */
1121         if (attribute->uele_backing_vnode != vp)
1122                 vn_lock(attribute->uele_backing_vnode, 
1123                     LK_EXCLUSIVE | LK_RETRY, td);
1124
1125         ioflag = IO_NODELOCKED;
1126         if (ufs_extattr_sync)
1127                 ioflag |= IO_SYNC;
1128         error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
1129             ump->um_extattr.uepm_ucred);
1130         if (error)
1131                 goto vopunlock_exit;
1132
1133         if (local_aio.uio_resid != 0) {
1134                 error = ENXIO;
1135                 goto vopunlock_exit;
1136         }
1137
1138         /*
1139          * Write out user data.
1140          */
1141         uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header);
1142
1143         ioflag = IO_NODELOCKED;
1144         if (ufs_extattr_sync)
1145                 ioflag |= IO_SYNC;
1146         error = VOP_WRITE(attribute->uele_backing_vnode, uio, ioflag,
1147             ump->um_extattr.uepm_ucred);
1148
1149 vopunlock_exit:
1150         uio->uio_offset = 0;
1151
1152         if (attribute->uele_backing_vnode != vp)
1153                 VOP_UNLOCK(attribute->uele_backing_vnode, 0, td);
1154
1155         return (error);
1156 }
1157
1158 /*
1159  * Real work associated with removing an extended attribute from a vnode.
1160  * Assumes the attribute lock has already been grabbed.
1161  */
1162 static int
1163 ufs_extattr_rm(struct vnode *vp, int attrnamespace, const char *name,
1164     struct ucred *cred, struct thread *td)
1165 {
1166         struct ufs_extattr_list_entry *attribute;
1167         struct ufs_extattr_header ueh;
1168         struct iovec local_aiov;
1169         struct uio local_aio;
1170         struct mount *mp = vp->v_mount;
1171         struct ufsmount *ump = VFSTOUFS(mp);
1172         struct inode *ip = VTOI(vp);
1173         off_t base_offset;
1174         int error = 0, ioflag;
1175
1176         if (vp->v_mount->mnt_flag & MNT_RDONLY)  
1177                 return (EROFS);
1178         if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
1179                 return (EOPNOTSUPP);
1180         if (!ufs_extattr_valid_attrname(attrnamespace, name))
1181                 return (EINVAL);
1182
1183         error = extattr_check_cred(vp, attrnamespace, cred, td, IWRITE);
1184         if (error)
1185                 return (error);
1186
1187         attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
1188         if (!attribute)
1189                 return (ENOATTR);
1190
1191         /*
1192          * Find base offset of header in file based on file header size, and
1193          * data header size + maximum data size, indexed by inode number.
1194          */
1195         base_offset = sizeof(struct ufs_extattr_fileheader) +
1196             ip->i_number * (sizeof(struct ufs_extattr_header) +
1197             attribute->uele_fileheader.uef_size);
1198
1199         /*
1200          * Check to see if currently defined.
1201          */
1202         bzero(&ueh, sizeof(struct ufs_extattr_header));
1203
1204         local_aiov.iov_base = (caddr_t) &ueh;
1205         local_aiov.iov_len = sizeof(struct ufs_extattr_header);
1206         local_aio.uio_iov = &local_aiov;
1207         local_aio.uio_iovcnt = 1;
1208         local_aio.uio_rw = UIO_READ;
1209         local_aio.uio_segflg = UIO_SYSSPACE;
1210         local_aio.uio_td = td;
1211         local_aio.uio_offset = base_offset;
1212         local_aio.uio_resid = sizeof(struct ufs_extattr_header);
1213
1214         /*
1215          * Don't need to get the lock on the backing vnode if the vnode we're
1216          * modifying is it, as we already hold the lock.
1217          */
1218         if (attribute->uele_backing_vnode != vp)
1219                 vn_lock(attribute->uele_backing_vnode,
1220                     LK_EXCLUSIVE | LK_RETRY, td);
1221
1222         error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
1223             IO_NODELOCKED, ump->um_extattr.uepm_ucred);
1224         if (error)
1225                 goto vopunlock_exit;
1226
1227         /* Defined? */
1228         if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
1229                 error = ENOATTR;
1230                 goto vopunlock_exit;
1231         }
1232
1233         /* Valid for the current inode generation? */
1234         if (ueh.ueh_i_gen != ip->i_gen) {
1235                 /*
1236                  * The inode itself has a different generation number than
1237                  * the attribute data.  For now, the best solution is to
1238                  * coerce this to undefined, and let it get cleaned up by
1239                  * the next write or extattrctl clean.
1240                  */
1241                 printf("ufs_extattr_rm (%s): inode number inconsistency (%d, %jd)\n",
1242                     mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen);
1243                 error = ENOATTR;
1244                 goto vopunlock_exit;
1245         }
1246
1247         /* Flag it as not in use. */
1248         ueh.ueh_flags = 0;
1249         ueh.ueh_len = 0;
1250
1251         local_aiov.iov_base = (caddr_t) &ueh;
1252         local_aiov.iov_len = sizeof(struct ufs_extattr_header);
1253         local_aio.uio_iov = &local_aiov;
1254         local_aio.uio_iovcnt = 1;
1255         local_aio.uio_rw = UIO_WRITE;
1256         local_aio.uio_segflg = UIO_SYSSPACE;
1257         local_aio.uio_td = td;
1258         local_aio.uio_offset = base_offset;
1259         local_aio.uio_resid = sizeof(struct ufs_extattr_header);
1260
1261         ioflag = IO_NODELOCKED;
1262         if (ufs_extattr_sync)
1263                 ioflag |= IO_SYNC;
1264         error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
1265             ump->um_extattr.uepm_ucred);
1266         if (error)
1267                 goto vopunlock_exit;
1268
1269         if (local_aio.uio_resid != 0)
1270                 error = ENXIO;
1271
1272 vopunlock_exit:
1273         VOP_UNLOCK(attribute->uele_backing_vnode, 0, td);
1274
1275         return (error);
1276 }
1277
1278 /*
1279  * Called by UFS when an inode is no longer active and should have its
1280  * attributes stripped.
1281  */
1282 void
1283 ufs_extattr_vnode_inactive(struct vnode *vp, struct thread *td)
1284 {
1285         struct ufs_extattr_list_entry *uele;
1286         struct mount *mp = vp->v_mount;
1287         struct ufsmount *ump = VFSTOUFS(mp);
1288
1289         /*
1290          * In that case, we cannot lock. We should not have any active vnodes
1291          * on the fs if this is not yet initialized but is going to be, so
1292          * this can go unlocked.
1293          */
1294         if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
1295                 return;
1296
1297         ufs_extattr_uepm_lock(ump, td);
1298
1299         if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
1300                 ufs_extattr_uepm_unlock(ump, td);
1301                 return;
1302         }
1303
1304         LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries)
1305                 ufs_extattr_rm(vp, uele->uele_attrnamespace,
1306                     uele->uele_attrname, NULL, td);
1307
1308         ufs_extattr_uepm_unlock(ump, td);
1309 }
1310
1311 #endif /* !UFS_EXTATTR */