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

« back to all changes in this revision

Viewing changes to include/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: src/sys/ufs/ufs/ufs_extattr.c,v 1.86.2.4.2.1 2010/02/10 00:26:20 kensmith Exp $");
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, td);
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, td);
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, td);
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, td);
334
 
                return (error);
335
 
        }
336
 
 
337
 
        vp->v_writecount++;
338
 
 
339
 
        vref(vp);
340
 
 
341
 
        VOP_UNLOCK(vp, 0, td);
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
 
        MALLOC(dirbuf, char *, 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, td);
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
 
        MALLOC(attribute, struct ufs_extattr_list_entry *,
609
 
            sizeof(struct ufs_extattr_list_entry), 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, td);
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, td);
672
 
        return (0);
673
 
 
674
 
unlock_free_exit:
675
 
        VOP_UNLOCK(backing_vnode, 0, td);
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
 
            td);
703
 
        ASSERT_VOP_LOCKED(uele->uele_backing_vnode, "ufs_extattr_disable");
704
 
        VOP_UNLOCK(uele->uele_backing_vnode, 0, td);
705
 
        error = vn_close(uele->uele_backing_vnode, FREAD|FWRITE,
706
 
            td->td_ucred, td);
707
 
 
708
 
        FREE(uele, M_UFS_EXTATTR);
709
 
 
710
 
        return (error);
711
 
}
712
 
 
713
 
/*
714
 
 * VFS call to manage extended attributes in UFS.  If filename_vp is
715
 
 * non-NULL, it must be passed in locked, and regardless of errors in
716
 
 * processing, will be unlocked.
717
 
 */
718
 
int
719
 
ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp,
720
 
    int attrnamespace, const char *attrname, struct thread *td)
721
 
{
722
 
        struct ufsmount *ump = VFSTOUFS(mp);
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, td);
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, td);
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, td);
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, td);
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, td);
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, td);
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, IREAD);
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 |
915
 
                    LK_RETRY, td);
916
 
 
917
 
        error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
918
 
            IO_NODELOCKED, ump->um_extattr.uepm_ucred);
919
 
        if (error)
920
 
                goto vopunlock_exit;
921
 
 
922
 
        /* Defined? */
923
 
        if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
924
 
                error = ENOATTR;
925
 
                goto vopunlock_exit;
926
 
        }
927
 
 
928
 
        /* Valid for the current inode generation? */
929
 
        if (ueh.ueh_i_gen != ip->i_gen) {
930
 
                /*
931
 
                 * The inode itself has a different generation number
932
 
                 * than the attribute data.  For now, the best solution
933
 
                 * is to coerce this to undefined, and let it get cleaned
934
 
                 * up by the next write or extattrctl clean.
935
 
                 */
936
 
                printf("ufs_extattr_get (%s): inode number inconsistency (%d, %jd)\n",
937
 
                    mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen);
938
 
                error = ENOATTR;
939
 
                goto vopunlock_exit;
940
 
        }
941
 
 
942
 
        /* Local size consistency check. */
943
 
        if (ueh.ueh_len > attribute->uele_fileheader.uef_size) {
944
 
                error = ENXIO;
945
 
                goto vopunlock_exit;
946
 
        }
947
 
 
948
 
        /* Return full data size if caller requested it. */
949
 
        if (size != NULL)
950
 
                *size = ueh.ueh_len;
951
 
 
952
 
        /* Return data if the caller requested it. */
953
 
        if (uio != NULL) {
954
 
                /* Allow for offset into the attribute data. */
955
 
                uio->uio_offset = base_offset + sizeof(struct
956
 
                    ufs_extattr_header);
957
 
 
958
 
                /*
959
 
                 * Figure out maximum to transfer -- use buffer size and
960
 
                 * local data limit.
961
 
                 */
962
 
                len = MIN(uio->uio_resid, ueh.ueh_len);
963
 
                old_len = uio->uio_resid;
964
 
                uio->uio_resid = len;
965
 
 
966
 
                error = VOP_READ(attribute->uele_backing_vnode, uio,
967
 
                    IO_NODELOCKED, ump->um_extattr.uepm_ucred);
968
 
                if (error)
969
 
                        goto vopunlock_exit;
970
 
 
971
 
                uio->uio_resid = old_len - (len - uio->uio_resid);
972
 
        }
973
 
 
974
 
vopunlock_exit:
975
 
 
976
 
        if (uio != NULL)
977
 
                uio->uio_offset = 0;
978
 
 
979
 
        if (attribute->uele_backing_vnode != vp)
980
 
                VOP_UNLOCK(attribute->uele_backing_vnode, 0, td);
981
 
 
982
 
        return (error);
983
 
}
984
 
 
985
 
/*
986
 
 * Vnode operation to remove a named attribute.
987
 
 */
988
 
int
989
 
ufs_deleteextattr(struct vop_deleteextattr_args *ap)
990
 
/*
991
 
vop_deleteextattr {
992
 
        IN struct vnode *a_vp;
993
 
        IN int a_attrnamespace;
994
 
        IN const char *a_name;
995
 
        IN struct ucred *a_cred;
996
 
        IN struct thread *a_td;
997
 
};
998
 
*/
999
 
{
1000
 
        struct mount *mp = ap->a_vp->v_mount;
1001
 
        struct ufsmount *ump = VFSTOUFS(mp); 
1002
 
        int error;
1003
 
 
1004
 
        ufs_extattr_uepm_lock(ump, ap->a_td);
1005
 
 
1006
 
        error = ufs_extattr_rm(ap->a_vp, ap->a_attrnamespace, ap->a_name,
1007
 
            ap->a_cred, ap->a_td);
1008
 
 
1009
 
 
1010
 
        ufs_extattr_uepm_unlock(ump, ap->a_td);
1011
 
 
1012
 
        return (error);
1013
 
}
1014
 
 
1015
 
/*
1016
 
 * Vnode operation to set a named attribute.
1017
 
 */
1018
 
int
1019
 
ufs_setextattr(struct vop_setextattr_args *ap)
1020
 
/*
1021
 
vop_setextattr {
1022
 
        IN struct vnode *a_vp;
1023
 
        IN int a_attrnamespace;
1024
 
        IN const char *a_name;
1025
 
        INOUT struct uio *a_uio;
1026
 
        IN struct ucred *a_cred;
1027
 
        IN struct thread *a_td;
1028
 
};
1029
 
*/
1030
 
{
1031
 
        struct mount *mp = ap->a_vp->v_mount;
1032
 
        struct ufsmount *ump = VFSTOUFS(mp); 
1033
 
        int error;
1034
 
 
1035
 
        ufs_extattr_uepm_lock(ump, ap->a_td);
1036
 
 
1037
 
        /*
1038
 
         * XXX: No longer a supported way to delete extended attributes.
1039
 
         */
1040
 
        if (ap->a_uio == NULL)
1041
 
                return (EINVAL);
1042
 
 
1043
 
        error = ufs_extattr_set(ap->a_vp, ap->a_attrnamespace, ap->a_name,
1044
 
            ap->a_uio, ap->a_cred, ap->a_td);
1045
 
 
1046
 
        ufs_extattr_uepm_unlock(ump, ap->a_td);
1047
 
 
1048
 
        return (error);
1049
 
}
1050
 
 
1051
 
/*
1052
 
 * Real work associated with setting a vnode's extended attributes;
1053
 
 * assumes that the attribute lock has already been grabbed.
1054
 
 */
1055
 
static int
1056
 
ufs_extattr_set(struct vnode *vp, int attrnamespace, const char *name,
1057
 
    struct uio *uio, struct ucred *cred, struct thread *td)
1058
 
{
1059
 
        struct ufs_extattr_list_entry *attribute;
1060
 
        struct ufs_extattr_header ueh;
1061
 
        struct iovec local_aiov;
1062
 
        struct uio local_aio;
1063
 
        struct mount *mp = vp->v_mount;
1064
 
        struct ufsmount *ump = VFSTOUFS(mp);
1065
 
        struct inode *ip = VTOI(vp);
1066
 
        off_t base_offset;
1067
 
        int error = 0, ioflag;
1068
 
 
1069
 
        if (vp->v_mount->mnt_flag & MNT_RDONLY)
1070
 
                return (EROFS);
1071
 
        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
1072
 
                return (EOPNOTSUPP);
1073
 
        if (!ufs_extattr_valid_attrname(attrnamespace, name))
1074
 
                return (EINVAL);
1075
 
 
1076
 
        error = extattr_check_cred(vp, attrnamespace, cred, td, IWRITE);
1077
 
        if (error)
1078
 
                return (error);
1079
 
 
1080
 
        attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
1081
 
        if (!attribute)
1082
 
                return (ENOATTR);
1083
 
 
1084
 
        /*
1085
 
         * Early rejection of invalid offsets/length.
1086
 
         * Reject: any offset but 0 (replace)
1087
 
         *       Any size greater than attribute size limit
1088
 
         */
1089
 
        if (uio->uio_offset != 0 ||
1090
 
            uio->uio_resid > attribute->uele_fileheader.uef_size)
1091
 
                return (ENXIO);
1092
 
 
1093
 
        /*
1094
 
         * Find base offset of header in file based on file header size, and
1095
 
         * data header size + maximum data size, indexed by inode number.
1096
 
         */
1097
 
        base_offset = sizeof(struct ufs_extattr_fileheader) +
1098
 
            ip->i_number * (sizeof(struct ufs_extattr_header) +
1099
 
            attribute->uele_fileheader.uef_size);
1100
 
 
1101
 
        /*
1102
 
         * Write out a data header for the data.
1103
 
         */
1104
 
        ueh.ueh_len = uio->uio_resid;
1105
 
        ueh.ueh_flags = UFS_EXTATTR_ATTR_FLAG_INUSE;
1106
 
        ueh.ueh_i_gen = ip->i_gen;
1107
 
        local_aiov.iov_base = (caddr_t) &ueh;
1108
 
        local_aiov.iov_len = sizeof(struct ufs_extattr_header);
1109
 
        local_aio.uio_iov = &local_aiov;
1110
 
        local_aio.uio_iovcnt = 1;
1111
 
        local_aio.uio_rw = UIO_WRITE;
1112
 
        local_aio.uio_segflg = UIO_SYSSPACE;
1113
 
        local_aio.uio_td = td;
1114
 
        local_aio.uio_offset = base_offset;
1115
 
        local_aio.uio_resid = sizeof(struct ufs_extattr_header);
1116
 
 
1117
 
        /*
1118
 
         * Acquire locks.
1119
 
         *
1120
 
         * Don't need to get a lock on the backing file if the setattr is
1121
 
         * being applied to the backing file, as the lock is already held.
1122
 
         */
1123
 
        if (attribute->uele_backing_vnode != vp)
1124
 
                vn_lock(attribute->uele_backing_vnode, 
1125
 
                    LK_EXCLUSIVE | LK_RETRY, td);
1126
 
 
1127
 
        ioflag = IO_NODELOCKED;
1128
 
        if (ufs_extattr_sync)
1129
 
                ioflag |= IO_SYNC;
1130
 
        error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
1131
 
            ump->um_extattr.uepm_ucred);
1132
 
        if (error)
1133
 
                goto vopunlock_exit;
1134
 
 
1135
 
        if (local_aio.uio_resid != 0) {
1136
 
                error = ENXIO;
1137
 
                goto vopunlock_exit;
1138
 
        }
1139
 
 
1140
 
        /*
1141
 
         * Write out user data.
1142
 
         */
1143
 
        uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header);
1144
 
 
1145
 
        ioflag = IO_NODELOCKED;
1146
 
        if (ufs_extattr_sync)
1147
 
                ioflag |= IO_SYNC;
1148
 
        error = VOP_WRITE(attribute->uele_backing_vnode, uio, ioflag,
1149
 
            ump->um_extattr.uepm_ucred);
1150
 
 
1151
 
vopunlock_exit:
1152
 
        uio->uio_offset = 0;
1153
 
 
1154
 
        if (attribute->uele_backing_vnode != vp)
1155
 
                VOP_UNLOCK(attribute->uele_backing_vnode, 0, td);
1156
 
 
1157
 
        return (error);
1158
 
}
1159
 
 
1160
 
/*
1161
 
 * Real work associated with removing an extended attribute from a vnode.
1162
 
 * Assumes the attribute lock has already been grabbed.
1163
 
 */
1164
 
static int
1165
 
ufs_extattr_rm(struct vnode *vp, int attrnamespace, const char *name,
1166
 
    struct ucred *cred, struct thread *td)
1167
 
{
1168
 
        struct ufs_extattr_list_entry *attribute;
1169
 
        struct ufs_extattr_header ueh;
1170
 
        struct iovec local_aiov;
1171
 
        struct uio local_aio;
1172
 
        struct mount *mp = vp->v_mount;
1173
 
        struct ufsmount *ump = VFSTOUFS(mp);
1174
 
        struct inode *ip = VTOI(vp);
1175
 
        off_t base_offset;
1176
 
        int error = 0, ioflag;
1177
 
 
1178
 
        if (vp->v_mount->mnt_flag & MNT_RDONLY)  
1179
 
                return (EROFS);
1180
 
        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
1181
 
                return (EOPNOTSUPP);
1182
 
        if (!ufs_extattr_valid_attrname(attrnamespace, name))
1183
 
                return (EINVAL);
1184
 
 
1185
 
        error = extattr_check_cred(vp, attrnamespace, cred, td, IWRITE);
1186
 
        if (error)
1187
 
                return (error);
1188
 
 
1189
 
        attribute = ufs_extattr_find_attr(ump, attrnamespace, name);
1190
 
        if (!attribute)
1191
 
                return (ENOATTR);
1192
 
 
1193
 
        /*
1194
 
         * Find base offset of header in file based on file header size, and
1195
 
         * data header size + maximum data size, indexed by inode number.
1196
 
         */
1197
 
        base_offset = sizeof(struct ufs_extattr_fileheader) +
1198
 
            ip->i_number * (sizeof(struct ufs_extattr_header) +
1199
 
            attribute->uele_fileheader.uef_size);
1200
 
 
1201
 
        /*
1202
 
         * Check to see if currently defined.
1203
 
         */
1204
 
        bzero(&ueh, sizeof(struct ufs_extattr_header));
1205
 
 
1206
 
        local_aiov.iov_base = (caddr_t) &ueh;
1207
 
        local_aiov.iov_len = sizeof(struct ufs_extattr_header);
1208
 
        local_aio.uio_iov = &local_aiov;
1209
 
        local_aio.uio_iovcnt = 1;
1210
 
        local_aio.uio_rw = UIO_READ;
1211
 
        local_aio.uio_segflg = UIO_SYSSPACE;
1212
 
        local_aio.uio_td = td;
1213
 
        local_aio.uio_offset = base_offset;
1214
 
        local_aio.uio_resid = sizeof(struct ufs_extattr_header);
1215
 
 
1216
 
        /*
1217
 
         * Don't need to get the lock on the backing vnode if the vnode we're
1218
 
         * modifying is it, as we already hold the lock.
1219
 
         */
1220
 
        if (attribute->uele_backing_vnode != vp)
1221
 
                vn_lock(attribute->uele_backing_vnode,
1222
 
                    LK_EXCLUSIVE | LK_RETRY, td);
1223
 
 
1224
 
        error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
1225
 
            IO_NODELOCKED, ump->um_extattr.uepm_ucred);
1226
 
        if (error)
1227
 
                goto vopunlock_exit;
1228
 
 
1229
 
        /* Defined? */
1230
 
        if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
1231
 
                error = ENOATTR;
1232
 
                goto vopunlock_exit;
1233
 
        }
1234
 
 
1235
 
        /* Valid for the current inode generation? */
1236
 
        if (ueh.ueh_i_gen != ip->i_gen) {
1237
 
                /*
1238
 
                 * The inode itself has a different generation number than
1239
 
                 * the attribute data.  For now, the best solution is to
1240
 
                 * coerce this to undefined, and let it get cleaned up by
1241
 
                 * the next write or extattrctl clean.
1242
 
                 */
1243
 
                printf("ufs_extattr_rm (%s): inode number inconsistency (%d, %jd)\n",
1244
 
                    mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen);
1245
 
                error = ENOATTR;
1246
 
                goto vopunlock_exit;
1247
 
        }
1248
 
 
1249
 
        /* Flag it as not in use. */
1250
 
        ueh.ueh_flags = 0;
1251
 
        ueh.ueh_len = 0;
1252
 
 
1253
 
        local_aiov.iov_base = (caddr_t) &ueh;
1254
 
        local_aiov.iov_len = sizeof(struct ufs_extattr_header);
1255
 
        local_aio.uio_iov = &local_aiov;
1256
 
        local_aio.uio_iovcnt = 1;
1257
 
        local_aio.uio_rw = UIO_WRITE;
1258
 
        local_aio.uio_segflg = UIO_SYSSPACE;
1259
 
        local_aio.uio_td = td;
1260
 
        local_aio.uio_offset = base_offset;
1261
 
        local_aio.uio_resid = sizeof(struct ufs_extattr_header);
1262
 
 
1263
 
        ioflag = IO_NODELOCKED;
1264
 
        if (ufs_extattr_sync)
1265
 
                ioflag |= IO_SYNC;
1266
 
        error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
1267
 
            ump->um_extattr.uepm_ucred);
1268
 
        if (error)
1269
 
                goto vopunlock_exit;
1270
 
 
1271
 
        if (local_aio.uio_resid != 0)
1272
 
                error = ENXIO;
1273
 
 
1274
 
vopunlock_exit:
1275
 
        VOP_UNLOCK(attribute->uele_backing_vnode, 0, td);
1276
 
 
1277
 
        return (error);
1278
 
}
1279
 
 
1280
 
/*
1281
 
 * Called by UFS when an inode is no longer active and should have its
1282
 
 * attributes stripped.
1283
 
 */
1284
 
void
1285
 
ufs_extattr_vnode_inactive(struct vnode *vp, struct thread *td)
1286
 
{
1287
 
        struct ufs_extattr_list_entry *uele;
1288
 
        struct mount *mp = vp->v_mount;
1289
 
        struct ufsmount *ump = VFSTOUFS(mp);
1290
 
 
1291
 
        /*
1292
 
         * In that case, we cannot lock. We should not have any active vnodes
1293
 
         * on the fs if this is not yet initialized but is going to be, so
1294
 
         * this can go unlocked.
1295
 
         */
1296
 
        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED))
1297
 
                return;
1298
 
 
1299
 
        ufs_extattr_uepm_lock(ump, td);
1300
 
 
1301
 
        if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) {
1302
 
                ufs_extattr_uepm_unlock(ump, td);
1303
 
                return;
1304
 
        }
1305
 
 
1306
 
        LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries)
1307
 
                ufs_extattr_rm(vp, uele->uele_attrnamespace,
1308
 
                    uele->uele_attrname, NULL, td);
1309
 
 
1310
 
        ufs_extattr_uepm_unlock(ump, td);
1311
 
}
1312
 
 
1313
 
#endif /* !UFS_EXTATTR */