~ubuntu-branches/debian/jessie/ufsutils/jessie

« back to all changes in this revision

Viewing changes to sys/ufs/ufs/ufs_extattr.c

  • Committer: Bazaar Package Importer
  • Author(s): Guillem Jover, Robert Millan, Guillem Jover, Peter Pentchev
  • Date: 2011-05-31 03:50:05 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20110531035005-wyiyk25p99ivd0k0
Tags: 8.2-1
[ Robert Millan ]
* Set ufsutils-udeb to kfreebsd-any.

[ Guillem Jover ]
* New upstream version (based on FreeBSD 8.2)
* Now using Standards-Version 3.9.2 (no changes needed).
* Switch to source format “3.0 (quilt)”.
  - Remove quilt from Build-Depends.
  - Remove patch target in debian/rules.
  - Remove now unneeded README.source.
  - Refresh all patches.
* Reorganize source code:
  - Switch from debian/upstream.sh to debian/rules get-orig-source target.
  - Switch from CVS to Subversion to retrieve the source code.
  - Use the same source layout as upstream (no more relocations),
    i.e. lib/, sbin/, sys/sys, sys/ufs.
  - Move libport/ to port/.
  - Merge libdisklabel/ into port/.
* Remove unneeded linking against libtermcap, thus removing the need for
  ncurses.
* Add an empty debian/watch file explaining that there's no packaged
  upstream releases. Suggested by Peter Pentchev.
* Update CVS to Subversion reference to upstream source code in
  debian/copyright.
* Remove unused lib variable from debian/rules.
* Use dpkg-buildflags to set CPPFLAGS, CFLAGS and LDFLAGS.
  Based on a patch by Peter Pentchev.
* Remove bogus reference to BSD license in /usr/share/common-licenses.
* Always set -I../../sys, even on GNU/kFreeBSD systems.

[ Peter Pentchev ]
* Remove duplicate section “utils” from ufsutils binary package.
* Remove XC- prefix from Package-Type.
* Honour CPPFLAGS and LDFLAGS and do not link with CFLAGS.

Show diffs side-by-side

added added

removed removed

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