summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c9
-rw-r--r--sys/ufs/ufs/extattr.h1
-rw-r--r--sys/ufs/ufs/ufs_extattr.c304
-rw-r--r--sys/ufs/ufs/ufs_extern.h1
4 files changed, 310 insertions, 5 deletions
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 78aaae5..a643019 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -700,10 +700,10 @@ ffs_mountfs(devvp, mp, p, malloctype)
(void) ffs_sbupdate(ump, MNT_WAIT);
}
#ifdef FFS_EXTATTR
+#ifdef FFS_EXTATTR_AUTOSTART
/*
- * XXX Auto-starting of EAs would go here.
*
- * Auto-starting would:
+ * Auto-starting does the following:
* - check for /.attribute in the fs, and extattr_start if so
* - for each file in .attribute, enable that file with
* an attribute of the same name.
@@ -711,8 +711,9 @@ ffs_mountfs(devvp, mp, p, malloctype)
* This would all happen while the file system was busy/not
* available, so would effectively be "atomic".
*/
- /* ufs_extattr_autostart(mp, ump); */
-#endif
+ (void) ufs_extattr_autostart(mp, p);
+#endif /* !FFS_EXTATTR_AUTOSTART */
+#endif /* !FFS_EXTATTR */
return (0);
out:
devvp->v_rdev->si_mountpoint = NULL;
diff --git a/sys/ufs/ufs/extattr.h b/sys/ufs/ufs/extattr.h
index b58a173..849e632 100644
--- a/sys/ufs/ufs/extattr.h
+++ b/sys/ufs/ufs/extattr.h
@@ -91,6 +91,7 @@ struct ufs_extattr_per_mount {
void ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm);
void ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm);
int ufs_extattr_start(struct mount *mp, struct proc *p);
+int ufs_extattr_autostart(struct mount *mp, struct proc *p);
int ufs_extattr_stop(struct mount *mp, struct proc *p);
int ufs_extattrctl(struct mount *mp, int cmd, const char *attrname,
caddr_t arg, struct proc *p);
diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c
index a9182eb..2c00b95 100644
--- a/sys/ufs/ufs/ufs_extattr.c
+++ b/sys/ufs/ufs/ufs_extattr.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1999, 2000 Robert N. M. Watson
+ * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,11 +39,18 @@
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/lock.h>
+#include <sys/dirent.h>
+#include <vm/vm_zone.h>
+
+#include <ufs/ufs/dir.h>
#include <ufs/ufs/extattr.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/inode.h>
+#include <ufs/ufs/ufs_extern.h>
+
+#include "opt_ffs.h"
#define MIN(a,b) (((a)<(b))?(a):(b))
@@ -200,6 +207,301 @@ unlock:
return (error);
}
+#ifdef FFS_EXTATTR_AUTOSTART
+/*
+ * Helper routine: given a locked parent directory and filename, return
+ * the locked vnode of the inode associated with the name. Will not
+ * follow symlinks, may return any type of vnode. Lock on parent will
+ * be released even in the event of a failure. In the event that the
+ * target is the parent (i.e., "."), there will be two references and
+ * one lock, requiring the caller to possibly special-case.
+ */
+#define UE_GETDIR_LOCKPARENT 1
+#define UE_GETDIR_LOCKPARENT_DONT 2
+static int
+ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, char *dirname,
+ struct vnode **vp, struct proc *p)
+{
+ struct vop_cachedlookup_args vargs;
+ struct componentname cnp;
+ struct vnode *target_vp;
+ int error;
+
+ bzero(&cnp, sizeof(cnp));
+ cnp.cn_nameiop = LOOKUP;
+ cnp.cn_flags = ISLASTCN;
+ if (lockparent == UE_GETDIR_LOCKPARENT)
+ cnp.cn_flags |= LOCKPARENT;
+ cnp.cn_proc = p;
+ cnp.cn_cred = p->p_ucred;
+ cnp.cn_pnbuf = zalloc(namei_zone);
+ cnp.cn_nameptr = cnp.cn_pnbuf;
+ error = copystr(dirname, cnp.cn_pnbuf, MAXPATHLEN,
+ (size_t *) &cnp.cn_namelen);
+ if (error) {
+ if (lockparent == UE_GETDIR_LOCKPARENT_DONT) {
+ VOP_UNLOCK(start_dvp, 0, p);
+ }
+ zfree(namei_zone, cnp.cn_pnbuf);
+ printf("ufs_extattr_lookup: copystr failed\n");
+ return (error);
+ }
+ cnp.cn_namelen--; /* trim nul termination */
+ vargs.a_desc = NULL;
+ vargs.a_dvp = start_dvp;
+ vargs.a_vpp = &target_vp;
+ vargs.a_cnp = &cnp;
+ error = ufs_lookup(&vargs);
+ zfree(namei_zone, cnp.cn_pnbuf);
+ if (error) {
+ /*
+ * Error condition, may have to release the lock on the parent
+ * if ufs_lookup() didn't.
+ */
+ if (!(cnp.cn_flags & PDIRUNLOCK) &&
+ (lockparent == UE_GETDIR_LOCKPARENT_DONT))
+ VOP_UNLOCK(start_dvp, 0, p);
+
+ /*
+ * Check that ufs_lookup() didn't release the lock when we
+ * didn't want it to.
+ */
+ if ((cnp.cn_flags & PDIRUNLOCK) &&
+ (lockparent == UE_GETDIR_LOCKPARENT))
+ panic("ufs_extattr_lookup: lockparent but PDIRUNLOCK");
+
+ printf("ufs_extattr_lookup: ufs_lookup failed (%d)\n", error);
+ return (error);
+ }
+/*
+ if (target_vp == start_dvp)
+ panic("ufs_extattr_lookup: target_vp == start_dvp");
+*/
+
+ if (target_vp != start_dvp &&
+ !(cnp.cn_flags & PDIRUNLOCK) &&
+ (lockparent == UE_GETDIR_LOCKPARENT_DONT))
+ panic("ufs_extattr_lookup: !lockparent but !PDIRUNLOCK");
+
+ if ((cnp.cn_flags & PDIRUNLOCK) &&
+ (lockparent == UE_GETDIR_LOCKPARENT))
+ panic("ufs_extattr_lookup: lockparent but PDIRUNLOCK");
+
+ /* printf("ufs_extattr_lookup: success\n"); */
+ *vp = target_vp;
+ return (0);
+}
+
+/*
+ * Enable an EA using the passed file system, backing vnode, attribute name,
+ * and proc. Will perform a VOP_OPEN() on the vp, so expects vp to be locked
+ * when passed in. Will unlock vp, and grab its own reference, so the caller
+ * needs to vrele(), just not vput(). If the call fails, the lock is not
+ * released.
+ */
+static int
+ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp,
+ char *attrname, struct proc *p)
+{
+ int error;
+
+ error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p);
+ if (error) {
+ printf("ufs_extattr_enable_with_open.VOP_OPEN(): failed "
+ "with %d\n", error);
+ return (error);
+ }
+
+ /*
+ * XXX: Note, should VOP_CLOSE() if vfs_object_create() fails, but due
+ * to a similar piece of code in vn_open(), we don't.
+ */
+ if (vn_canvmio(vp) == TRUE)
+ if ((error = vfs_object_create(vp, p, p->p_ucred)) != 0) {
+ /*
+ * XXX: bug replicated from vn_open(): should
+ * VOP_CLOSE() here.
+ */
+ return (error);
+ }
+
+ vp->v_writecount++;
+
+ vref(vp);
+
+ VOP_UNLOCK(vp, 0, p);
+
+ return (ufs_extattr_enable(ump, attrname, vp, p));
+}
+
+/*
+ * Given a locked directory vnode, iterate over the names in the directory
+ * and use ufs_extattr_lookup() to retrieve locked vnodes of potential
+ * attribute files. Then invoke ufs_extattr_enable_with_open() on each
+ * to attempt to start the attribute. Leaves the directory locked on
+ * exit.
+ * XXX: Add a EA namespace argument
+ */
+static int
+ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp,
+ struct proc *p)
+{
+ struct vop_readdir_args vargs;
+ struct dirent *dp, *edp;
+ struct vnode *attr_vp;
+ struct uio auio;
+ struct iovec aiov;
+ char *dirbuf;
+ int error, eofflag = 0;
+
+ if (dvp->v_type != VDIR)
+ return (ENOTDIR);
+
+ MALLOC(dirbuf, char *, DIRBLKSIZ, M_TEMP, M_WAITOK);
+
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_procp = p;
+ auio.uio_offset = 0;
+
+ vargs.a_desc = NULL;
+ vargs.a_vp = dvp;
+ vargs.a_uio = &auio;
+ vargs.a_cred = p->p_ucred;
+ vargs.a_eofflag = &eofflag;
+ vargs.a_ncookies = NULL;
+ vargs.a_cookies = NULL;
+
+ while (!eofflag) {
+ auio.uio_resid = DIRBLKSIZ;
+ aiov.iov_base = dirbuf;
+ aiov.iov_len = DIRBLKSIZ;
+ error = ufs_readdir(&vargs);
+ if (error) {
+ printf("ufs_extattr_iterate_directory: ufs_readdir "
+ "%d\n", error);
+ return (error);
+ }
+
+ edp = (struct dirent *)&dirbuf[DIRBLKSIZ];
+ for (dp = (struct dirent *)dirbuf; dp < edp; ) {
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+ dp->d_type = dp->d_namlen;
+ dp->d_namlen = 0;
+#else
+ dp->d_type = 0;
+#endif
+ if (dp->d_reclen == 0)
+ break;
+ error = ufs_extattr_lookup(dvp, UE_GETDIR_LOCKPARENT,
+ dp->d_name, &attr_vp, p);
+ if (error) {
+ printf("ufs_extattr_iterate_directory: lookup "
+ "%s %d\n", dp->d_name, error);
+ } else if (attr_vp == dvp) {
+ vrele(attr_vp);
+ } else if (attr_vp->v_type != VREG) {
+/*
+ * Eventually, this will be uncommented, but in the mean time, the ".."
+ * entry causes unnecessary console warnings.
+ printf("ufs_extattr_iterate_directory: "
+ "%s not VREG\n", dp->d_name);
+*/
+ vput(attr_vp);
+ } else {
+ error = ufs_extattr_enable_with_open(ump,
+ attr_vp, dp->d_name, p);
+ if (error) {
+ printf("ufs_extattr_iterate_directory: "
+ "enable %s %d\n", dp->d_name,
+ error);
+ vput(attr_vp);
+ } else {
+/*
+ * While it's nice to have some visual output here, skip for the time-being.
+ * Probably should be enabled by -v at boot.
+ printf("Autostarted %s\n", dp->d_name);
+ */
+ vrele(attr_vp);
+ }
+ }
+ dp = (struct dirent *) ((char *)dp + dp->d_reclen);
+ if (dp >= edp)
+ break;
+ }
+ }
+ FREE(dirbuf, M_TEMP);
+
+ return (0);
+}
+
+/*
+ * Auto-start of extended attributes, to be executed (optionally) at
+ * mount-time.
+ */
+int
+ufs_extattr_autostart(struct mount *mp, struct proc *p)
+{
+ struct vnode *attr_dvp, /**attr_vp,*/ *rvp;
+ int error;
+
+ /*
+ * Does ".attribute" exist off the file system root? If so,
+ * automatically start EA's.
+ */
+ error = VFS_ROOT(mp, &rvp);
+ if (error) {
+ printf("ufs_extattr_autostart.VFS_ROOT() returned %d\n", error);
+ return (error);
+ }
+
+ error = ufs_extattr_lookup(rvp, UE_GETDIR_LOCKPARENT_DONT,
+ ".attribute", &attr_dvp, p);
+ if (error) {
+ /* rvp ref'd but now unlocked */
+ vrele(rvp);
+ return (error);
+ }
+ if (rvp == attr_dvp) {
+ /* Should never happen. */
+ vrele(attr_dvp);
+ vput(rvp);
+ return (EINVAL);
+ }
+ vrele(rvp);
+
+ if (attr_dvp->v_type != VDIR) {
+ printf("ufs_extattr_autostart: .attribute != VDIR\n");
+ goto return_vput;
+ }
+
+ error = ufs_extattr_start(mp, p);
+ if (error) {
+ printf("ufs_extattr_autostart: ufs_extattr_start failed (%d)\n",
+ error);
+ goto return_vput;
+ }
+
+ /*
+ * Iterate over the directory. Eventually we may lookup sub-directories
+ * and iterate over them independently.
+ */
+ error = ufs_extattr_iterate_directory(VFSTOUFS(mp), attr_dvp, p);
+ if (error)
+ printf("ufs_extattr_iterate_directory returned %d\n", error);
+
+ /* Mask startup failures. */
+ error = 0;
+
+return_vput:
+ vput(attr_dvp);
+
+ return (error);
+}
+#endif /* !FFS_EXTATTR_AUTOSTART */
+
/*
* Stop extended attribute support on an FS.
*/
diff --git a/sys/ufs/ufs/ufs_extern.h b/sys/ufs/ufs/ufs_extern.h
index a5c7a47..82704b6 100644
--- a/sys/ufs/ufs/ufs_extern.h
+++ b/sys/ufs/ufs/ufs_extern.h
@@ -86,6 +86,7 @@ int ufs_inactive __P((struct vop_inactive_args *));
int ufs_init __P((struct vfsconf *));
void ufs_itimes __P((struct vnode *vp));
int ufs_lookup __P((struct vop_cachedlookup_args *));
+int ufs_readdir __P((struct vop_readdir_args *));
int ufs_reclaim __P((struct vop_reclaim_args *));
void ffs_snapgone __P((struct inode *));
int ufs_root __P((struct mount *, struct vnode **));
OpenPOWER on IntegriCloud