summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/cmd/devfsadm/devfsadm.c12
-rw-r--r--usr/src/cmd/fs.d/fslib.c39
-rw-r--r--usr/src/cmd/fs.d/ufs/fsck/main.c23
-rw-r--r--usr/src/cmd/lofiadm/main.c4
-rw-r--r--usr/src/cmd/zoneadm/zoneadm.c38
-rw-r--r--usr/src/cmd/zoneadmd/vplat.c24
-rw-r--r--usr/src/uts/common/fs/hsfs/hsfs_vfsops.c78
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_vfsops.c49
-rw-r--r--usr/src/uts/common/fs/udfs/udf_vfsops.c322
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_vfsops.c137
-rw-r--r--usr/src/uts/common/fs/vfs.c226
-rw-r--r--usr/src/uts/common/io/lofi.c52
-rw-r--r--usr/src/uts/common/sys/lofi.h9
-rw-r--r--usr/src/uts/common/sys/vfs.h4
14 files changed, 696 insertions, 321 deletions
diff --git a/usr/src/cmd/devfsadm/devfsadm.c b/usr/src/cmd/devfsadm/devfsadm.c
index 6598cc3639..8fd841976a 100644
--- a/usr/src/cmd/devfsadm/devfsadm.c
+++ b/usr/src/cmd/devfsadm/devfsadm.c
@@ -8467,10 +8467,16 @@ out:
if (dev_name)
free(dev_name);
- if (dev_name_lookup_err)
- err_print(DEV_NAME_LOOKUP_FAILED, node_path);
- else
+ if (dev_name_lookup_err) {
+ /*
+ * If a lofi mount fails, the /devices node may well have
+ * disappeared by the time we run, so let's not complain.
+ */
+ if (strcmp(subclass, ESC_LOFI) != 0)
+ err_print(DEV_NAME_LOOKUP_FAILED, node_path);
+ } else {
err_print(BUILD_EVENT_ATTR_FAILED, (err) ? strerror(err) : "");
+ }
return (NULL);
}
diff --git a/usr/src/cmd/fs.d/fslib.c b/usr/src/cmd/fs.d/fslib.c
index 552931ecda..5948c1e43e 100644
--- a/usr/src/cmd/fs.d/fslib.c
+++ b/usr/src/cmd/fs.d/fslib.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -174,7 +173,7 @@ fsmkmntlist(FILE *mfp)
resetmnttab(mfp);
while ((ret = getextmntent(mfp, &mnt, sizeof (struct extmnttab)))
- != -1) {
+ != -1) {
mntlist_t *mp;
if (ret != 0) /* bad entry */
@@ -216,19 +215,19 @@ fsgetmlast(mntlist_t *ml, struct mnttab *mntin)
* match if and only if both are equal.
*/
if ((strcmp(ml->mntl_mnt->mnt_mountp,
- mntin->mnt_mountp) == 0) &&
+ mntin->mnt_mountp) == 0) &&
(strcmp(ml->mntl_mnt->mnt_special,
- mntin->mnt_special) == 0))
+ mntin->mnt_special) == 0))
delete = ml;
} else if (mntin->mnt_mountp) {
if (strcmp(ml->mntl_mnt->mnt_mountp,
- mntin->mnt_mountp) == 0)
+ mntin->mnt_mountp) == 0)
delete = ml;
} else if (mntin->mnt_special) {
if (strcmp(ml->mntl_mnt->mnt_special,
- mntin->mnt_special) == 0)
+ mntin->mnt_special) == 0)
delete = ml;
- }
+ }
}
return (delete);
}
@@ -309,7 +308,7 @@ cmp_requested_to_actual_options(char *requested_opts, char *actual_opts,
while (*requested_opts != '\0') {
(void) getsubopt(&requested_opts, empty_opt_vector,
- &option_ptr);
+ &option_ptr);
/*
* Truncate any "=<value>" string from the end of
@@ -322,6 +321,14 @@ cmp_requested_to_actual_options(char *requested_opts, char *actual_opts,
continue;
/*
+ * Whilst we don't need this option to perform a lofi
+ * mount, let's not be mendacious enough to complain
+ * about it.
+ */
+ if (strcmp(option_ptr, "loop") == 0)
+ continue;
+
+ /*
* Search for the requested option in the list of options
* actually supported.
*/
@@ -344,7 +351,7 @@ cmp_requested_to_actual_options(char *requested_opts, char *actual_opts,
while (*actual_opt_hold != '\0') {
(void) getsubopt(&actual_opt_hold, empty_opt_vector,
- &actopt);
+ &actopt);
/* Truncate the "=<value>", if any. */
if ((equalptr = strchr(actopt, '=')) != NULL)
@@ -428,10 +435,10 @@ fs_get_zone_summaries(void)
for (;;) {
if (zone_list(ids, &numzones) < 0) {
- perror("unable to retrieve list of zones");
- if (ids != NULL)
- free(ids);
- return (NULL);
+ perror("unable to retrieve list of zones");
+ if (ids != NULL)
+ free(ids);
+ return (NULL);
}
if (numzones <= oldnumzones)
break;
diff --git a/usr/src/cmd/fs.d/ufs/fsck/main.c b/usr/src/cmd/fs.d/ufs/fsck/main.c
index 9ed962089a..981a99171f 100644
--- a/usr/src/cmd/fs.d/ufs/fsck/main.c
+++ b/usr/src/cmd/fs.d/ufs/fsck/main.c
@@ -696,7 +696,8 @@ check_sanity(char *filename)
int found_magic[MAGIC_LIMIT];
int magic_cnt;
int is_magic = 0;
- int is_block;
+ int is_block = 0;
+ int is_file = 0;
(void) memset((void *)found_magic, 0, sizeof (found_magic));
@@ -706,22 +707,12 @@ check_sanity(char *filename)
exit(EXNOSTAT);
}
- if ((stbd.st_mode & S_IFMT) == S_IFBLK) {
+ if (S_ISBLK(stbd.st_mode)) {
is_block = 1;
- } else if ((stbd.st_mode & S_IFMT) == S_IFCHR) {
+ } else if (S_ISCHR(stbd.st_mode)) {
is_block = 0;
- } else {
- /*
- * In !mflag mode, we allow checking the contents
- * of a file. Since this is intended primarily for
- * speeding up boot-time checks and allowing for a
- * file complicates the ok-input tests, we'll disallow
- * that option.
- */
- (void) fprintf(stderr,
- "ufs fsck: sanity check failed: "
- "%s not block or character device\n", filename);
- exit(EXNOSTAT);
+ } else if (S_ISREG(stbd.st_mode)) {
+ is_file = 1;
}
/*
@@ -729,7 +720,7 @@ check_sanity(char *filename)
* silently on failures. The whole point of this is to be tolerant
* of the magic file systems being already mounted.
*/
- if ((vfstab = fopen(VFSTAB, "r")) != 0) {
+ if (!is_file && (vfstab = fopen(VFSTAB, "r")) != NULL) {
for (magic_cnt = 0; magic_cnt < MAGIC_LIMIT; magic_cnt++) {
if (magic_cnt == MAGIC_NONE)
continue;
diff --git a/usr/src/cmd/lofiadm/main.c b/usr/src/cmd/lofiadm/main.c
index 40ec555e7f..22fd0d6bea 100644
--- a/usr/src/cmd/lofiadm/main.c
+++ b/usr/src/cmd/lofiadm/main.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -304,6 +304,8 @@ delete_mapping(int lfd, const char *devicename, const char *filename,
struct lofi_ioctl li;
li.li_force = force;
+ li.li_cleanup = B_FALSE;
+
if (devicename == NULL) {
/* delete by filename */
(void) strlcpy(li.li_filename, filename,
diff --git a/usr/src/cmd/zoneadm/zoneadm.c b/usr/src/cmd/zoneadm/zoneadm.c
index 1fb836f3a2..65c522b9fc 100644
--- a/usr/src/cmd/zoneadm/zoneadm.c
+++ b/usr/src/cmd/zoneadm/zoneadm.c
@@ -2437,7 +2437,7 @@ verify_ipd(zone_dochandle_t handle)
static int
verify_fs_special(struct zone_fstab *fstab)
{
- struct stat st;
+ struct stat64 st;
/*
* This validation is really intended for standard zone administration.
@@ -2450,7 +2450,7 @@ verify_fs_special(struct zone_fstab *fstab)
if (strcmp(fstab->zone_fs_type, MNTTYPE_ZFS) == 0)
return (verify_fs_zfs(fstab));
- if (stat(fstab->zone_fs_special, &st) != 0) {
+ if (stat64(fstab->zone_fs_special, &st) != 0) {
(void) fprintf(stderr, gettext("could not verify fs "
"%s: could not access %s: %s\n"), fstab->zone_fs_dir,
fstab->zone_fs_special, strerror(errno));
@@ -2474,6 +2474,17 @@ verify_fs_special(struct zone_fstab *fstab)
}
static int
+isregfile(const char *path)
+{
+ struct stat64 st;
+
+ if (stat64(path, &st) == -1)
+ return (-1);
+
+ return (S_ISREG(st.st_mode));
+}
+
+static int
verify_filesystems(zone_dochandle_t handle)
{
int return_code = Z_OK;
@@ -2529,8 +2540,10 @@ verify_filesystems(zone_dochandle_t handle)
goto next_fs;
}
/*
- * Verify /usr/lib/fs/<fstype>/fsck exists iff zone_fs_raw is
- * set.
+ * If zone_fs_raw is set, verify that there's an fsck
+ * binary for it. If zone_fs_raw is not set, and it's
+ * not a regular file (lofi mount), and there's an fsck
+ * binary for it, complain.
*/
if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/fsck",
fstab.zone_fs_type) > sizeof (cmdbuf)) {
@@ -2540,14 +2553,6 @@ verify_filesystems(zone_dochandle_t handle)
return_code = Z_ERR;
goto next_fs;
}
- if (fstab.zone_fs_raw[0] == '\0' && stat(cmdbuf, &st) == 0) {
- (void) fprintf(stderr, gettext("could not verify fs "
- "%s: must specify 'raw' device for %s "
- "file systems\n"),
- fstab.zone_fs_dir, fstab.zone_fs_type);
- return_code = Z_ERR;
- goto next_fs;
- }
if (fstab.zone_fs_raw[0] != '\0' &&
(stat(cmdbuf, &st) != 0 || !S_ISREG(st.st_mode))) {
(void) fprintf(stderr, gettext("cannot verify fs %s: "
@@ -2556,6 +2561,15 @@ verify_filesystems(zone_dochandle_t handle)
fstab.zone_fs_dir, fstab.zone_fs_type);
return_code = Z_ERR;
goto next_fs;
+ } else if (fstab.zone_fs_raw[0] == '\0' &&
+ stat(cmdbuf, &st) == 0 &&
+ isregfile(fstab.zone_fs_special) != 1) {
+ (void) fprintf(stderr, gettext("could not verify fs "
+ "%s: must specify 'raw' device for %s "
+ "file systems\n"),
+ fstab.zone_fs_dir, fstab.zone_fs_type);
+ return_code = Z_ERR;
+ goto next_fs;
}
/* Verify fs_special. */
diff --git a/usr/src/cmd/zoneadmd/vplat.c b/usr/src/cmd/zoneadmd/vplat.c
index 5a118a4eac..0d11899f03 100644
--- a/usr/src/cmd/zoneadmd/vplat.c
+++ b/usr/src/cmd/zoneadmd/vplat.c
@@ -803,6 +803,17 @@ forkexec(zlog_t *zlogp, const char *path, char *const argv[])
}
static int
+isregfile(const char *path)
+{
+ struct stat64 st;
+
+ if (stat64(path, &st) == -1)
+ return (-1);
+
+ return (S_ISREG(st.st_mode));
+}
+
+static int
dofsck(zlog_t *zlogp, const char *fstype, const char *rawdev)
{
char cmdbuf[MAXPATHLEN];
@@ -819,6 +830,13 @@ dofsck(zlog_t *zlogp, const char *fstype, const char *rawdev)
return (-1);
}
+ /*
+ * If it doesn't exist, that's OK: we verified this previously
+ * in zoneadm.
+ */
+ if (isregfile(cmdbuf) == -1)
+ return (0);
+
argv[0] = "fsck";
argv[1] = "-m";
argv[2] = (char *)rawdev;
@@ -1260,8 +1278,12 @@ mount_one(zlog_t *zlogp, struct zone_fstab *fsptr, const char *rootpath)
* Run 'fsck -m' if there's a device to fsck.
*/
if (fsptr->zone_fs_raw[0] != '\0' &&
- dofsck(zlogp, fsptr->zone_fs_type, fsptr->zone_fs_raw) != 0)
+ dofsck(zlogp, fsptr->zone_fs_type, fsptr->zone_fs_raw) != 0) {
+ return (-1);
+ } else if (isregfile(fsptr->zone_fs_special) == 1 &&
+ dofsck(zlogp, fsptr->zone_fs_type, fsptr->zone_fs_special) != 0) {
return (-1);
+ }
/*
* Build up mount option string.
diff --git a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c
index 9c25cc5249..5b2ae35930 100644
--- a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c
+++ b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1343,40 +1343,57 @@ hs_getmdev(struct vfs *vfsp, char *fspec, int flags, dev_t *pdev, mode_t *mode,
cred_t *cr)
{
int error;
- struct vnode *vp;
+ struct vnode *svp = NULL;
+ struct vnode *lvp = NULL;
+ struct vnode *bvp;
struct vattr vap;
dev_t dev;
+ enum uio_seg fromspace = (flags & MS_SYSSPACE) ?
+ UIO_SYSSPACE : UIO_USERSPACE;
/*
- * Get the device to be mounted
+ * Look up the device/file to be mounted.
*/
- error = lookupname(fspec, (flags & MS_SYSSPACE) ?
- UIO_SYSSPACE : UIO_USERSPACE, FOLLOW, NULLVPP, &vp);
+ error = lookupname(fspec, fromspace, FOLLOW, NULLVPP, &svp);
if (error) {
- if (error == ENOENT) {
- return (ENODEV); /* needs translation */
- }
- return (error);
+ if (error == ENOENT)
+ error = ENODEV;
+ goto out;
}
- if (vp->v_type != VBLK) {
- VN_RELE(vp);
- return (ENOTBLK);
+
+ error = vfs_get_lofi(vfsp, &lvp);
+
+ if (error > 0) {
+ if (error == ENOENT)
+ error = ENODEV;
+ goto out;
+ } else if (error == 0) {
+ bvp = lvp;
+ } else {
+ bvp = svp;
+
+ if (bvp->v_type != VBLK) {
+ error = ENOTBLK;
+ goto out;
+ }
+
+ if ((error = secpolicy_spec_open(cr, bvp, FREAD)) != 0)
+ goto out;
}
+
/*
- * Can we read from the device?
+ * Can we read from the device/file ?
*/
- if ((error = VOP_ACCESS(vp, VREAD, 0, cr, NULL)) != 0 ||
- (error = secpolicy_spec_open(cr, vp, FREAD)) != 0) {
- VN_RELE(vp);
- return (error);
- }
+ if ((error = VOP_ACCESS(svp, VREAD, 0, cr, NULL)) != 0)
+ goto out;
vap.va_mask = AT_MODE; /* get protection mode */
- (void) VOP_GETATTR(vp, &vap, 0, CRED(), NULL);
+ (void) VOP_GETATTR(bvp, &vap, 0, CRED(), NULL);
*mode = vap.va_mode;
- dev = *pdev = vp->v_rdev;
- VN_RELE(vp);
+ dev = *pdev = bvp->v_rdev;
+
+ error = EBUSY;
/*
* Ensure that this device isn't already mounted,
@@ -1385,14 +1402,23 @@ hs_getmdev(struct vfs *vfsp, char *fspec, int flags, dev_t *pdev, mode_t *mode,
*/
if ((flags & MS_NOCHECK) == 0) {
if (vfs_devmounting(dev, vfsp))
- return (EBUSY);
+ goto out;
if (vfs_devismounted(dev) && !(flags & MS_REMOUNT))
- return (EBUSY);
+ goto out;
}
- if (getmajor(*pdev) >= devcnt)
- return (ENXIO);
- return (0);
+ if (getmajor(*pdev) >= devcnt) {
+ error = ENXIO;
+ goto out;
+ }
+
+ error = 0;
+out:
+ if (svp != NULL)
+ VN_RELE(svp);
+ if (lvp != NULL)
+ VN_RELE(lvp);
+ return (error);
}
static void
diff --git a/usr/src/uts/common/fs/pcfs/pc_vfsops.c b/usr/src/uts/common/fs/pcfs/pc_vfsops.c
index 43cfc0d73c..9062bf1304 100644
--- a/usr/src/uts/common/fs/pcfs/pc_vfsops.c
+++ b/usr/src/uts/common/fs/pcfs/pc_vfsops.c
@@ -293,7 +293,8 @@ pcfs_device_identify(
{
struct pathname special;
char *c;
- struct vnode *bvp;
+ struct vnode *svp = NULL;
+ struct vnode *lvp = NULL;
int oflag, aflag;
int error;
@@ -307,7 +308,7 @@ pcfs_device_identify(
*dos_ldrive = -1;
if (error =
- lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp)) {
+ lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &svp)) {
/*
* If there's no device node, the name specified most likely
* maps to a PCFS-style "partition specifier" to select a
@@ -384,7 +385,7 @@ pcfs_device_identify(
error = lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW,
- NULLVPP, &bvp);
+ NULLVPP, &svp);
} else {
*dos_ldrive = UNPARTITIONED_DRIVE;
}
@@ -395,8 +396,6 @@ devlookup_done:
ASSERT(*dos_ldrive >= UNPARTITIONED_DRIVE);
- *xdev = bvp->v_rdev;
-
/*
* Verify caller's permission to open the device special file.
*/
@@ -409,20 +408,38 @@ devlookup_done:
aflag = VREAD | VWRITE;
}
- if (bvp->v_type != VBLK)
- error = ENOTBLK;
- else if (getmajor(*xdev) >= devcnt)
- error = ENXIO;
+ error = vfs_get_lofi(vfsp, &lvp);
- if ((error != 0) ||
- (error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
- (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
- VN_RELE(bvp);
- return (error);
+ if (error > 0) {
+ if (error == ENOENT)
+ error = ENODEV;
+ goto out;
+ } else if (error == 0) {
+ *xdev = lvp->v_rdev;
+ } else {
+ *xdev = svp->v_rdev;
+
+ if (svp->v_type != VBLK)
+ error = ENOTBLK;
+
+ if ((error = secpolicy_spec_open(cr, svp, oflag)) != 0)
+ goto out;
}
- VN_RELE(bvp);
- return (0);
+ if (getmajor(*xdev) >= devcnt) {
+ error = ENXIO;
+ goto out;
+ }
+
+ if ((error = VOP_ACCESS(svp, aflag, 0, cr, NULL)) != 0)
+ goto out;
+
+out:
+ if (svp != NULL)
+ VN_RELE(svp);
+ if (lvp != NULL)
+ VN_RELE(lvp);
+ return (error);
}
static int
diff --git a/usr/src/uts/common/fs/udfs/udf_vfsops.c b/usr/src/uts/common/fs/udfs/udf_vfsops.c
index 95f98d6229..7d638f9066 100644
--- a/usr/src/uts/common/fs/udfs/udf_vfsops.c
+++ b/usr/src/uts/common/fs/udfs/udf_vfsops.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -91,22 +91,22 @@ extern struct vnode *common_specvp(struct vnode *vp);
extern kmutex_t ud_sync_busy;
static int32_t ud_mountfs(struct vfs *,
- enum whymountroot, dev_t, char *, struct cred *, int32_t);
+ enum whymountroot, dev_t, char *, struct cred *, int32_t);
static struct udf_vfs *ud_validate_and_fill_superblock(dev_t,
- int32_t, uint32_t);
+ int32_t, uint32_t);
void ud_destroy_fsp(struct udf_vfs *);
void ud_convert_to_superblock(struct udf_vfs *,
- struct log_vol_int_desc *);
+ struct log_vol_int_desc *);
void ud_update_superblock(struct vfs *);
int32_t ud_get_last_block(dev_t, daddr_t *);
static int32_t ud_val_get_vat(struct udf_vfs *,
- dev_t, daddr_t, struct ud_map *);
+ dev_t, daddr_t, struct ud_map *);
int32_t ud_read_sparing_tbls(struct udf_vfs *,
- dev_t, struct ud_map *, struct pmap_typ2 *);
+ dev_t, struct ud_map *, struct pmap_typ2 *);
uint32_t ud_get_lbsize(dev_t, uint32_t *);
static int32_t udf_mount(struct vfs *,
- struct vnode *, struct mounta *, struct cred *);
+ struct vnode *, struct mounta *, struct cred *);
static int32_t udf_unmount(struct vfs *, int, struct cred *);
static int32_t udf_root(struct vfs *, struct vnode **);
static int32_t udf_statvfs(struct vfs *, struct statvfs64 *);
@@ -183,7 +183,8 @@ udf_mount(struct vfs *vfsp, struct vnode *mvp,
struct mounta *uap, struct cred *cr)
{
dev_t dev;
- struct vnode *bvp;
+ struct vnode *lvp = NULL;
+ struct vnode *svp = NULL;
struct pathname dpn;
int32_t error;
enum whymountroot why;
@@ -202,9 +203,9 @@ udf_mount(struct vfs *vfsp, struct vnode *mvp,
mutex_enter(&mvp->v_lock);
if ((uap->flags & MS_REMOUNT) == 0 &&
(uap->flags & MS_OVERLAY) == 0 &&
- (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
- mutex_exit(&mvp->v_lock);
- return (EBUSY);
+ (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
+ mutex_exit(&mvp->v_lock);
+ return (EBUSY);
}
mutex_exit(&mvp->v_lock);
@@ -213,18 +214,30 @@ udf_mount(struct vfs *vfsp, struct vnode *mvp,
}
/*
- * Resolve path name of special file being mounted.
+ * Resolve path name of the file being mounted.
*/
if (error = lookupname(uap->spec, UIO_USERSPACE, FOLLOW, NULLVPP,
- &bvp)) {
+ &svp)) {
pn_free(&dpn);
return (error);
}
- if (bvp->v_type != VBLK) {
- error = ENOTBLK;
+
+ error = vfs_get_lofi(vfsp, &lvp);
+
+ if (error > 0) {
+ if (error == ENOENT)
+ error = ENODEV;
goto out;
+ } else if (error == 0) {
+ dev = lvp->v_rdev;
+ } else {
+ dev = svp->v_rdev;
+
+ if (svp->v_type != VBLK) {
+ error = ENOTBLK;
+ goto out;
+ }
}
- dev = bvp->v_rdev;
/*
* Ensure that this device isn't already mounted,
@@ -282,19 +295,23 @@ udf_mount(struct vfs *vfsp, struct vnode *mvp,
oflag = FREAD | FWRITE;
aflag = VREAD | VWRITE;
}
- if ((error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
- (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
+
+ if (lvp == NULL &&
+ (error = secpolicy_spec_open(cr, svp, oflag)) != 0)
+ goto out;
+
+ if ((error = VOP_ACCESS(svp, aflag, 0, cr, NULL)) != 0)
goto out;
- }
/*
* Mount the filesystem.
*/
error = ud_mountfs(vfsp, why, dev, dpn.pn_path, cr, 0);
out:
- VN_RELE(bvp);
+ VN_RELE(svp);
+ if (lvp != NULL)
+ VN_RELE(lvp);
pn_free(&dpn);
-
return (error);
}
@@ -436,15 +453,13 @@ udf_statvfs(struct vfs *vfsp, struct statvfs64 *sp)
* 38(over head each dent) + MAXNAMLEN / 2 + inode_size(==block size)
*/
sp->f_ffree = sp->f_favail =
- (sp->f_bavail * sp->f_bsize) / (146 + sp->f_bsize);
+ (sp->f_bavail * sp->f_bsize) / (146 + sp->f_bsize);
/*
* The total number of inodes is
* the sum of files + directories + free inodes
*/
- sp->f_files = sp->f_ffree +
- udf_vfsp->udf_nfiles +
- udf_vfsp->udf_ndirs;
+ sp->f_files = sp->f_ffree + udf_vfsp->udf_nfiles + udf_vfsp->udf_ndirs;
(void) cmpldev(&d32, vfsp->vfs_dev);
sp->f_fsid = d32;
(void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
@@ -495,14 +510,14 @@ udf_vget(struct vfs *vfsp,
udfid = (struct udf_fid *)fidp;
if ((error = ud_iget(vfsp, udfid->udfid_prn,
- udfid->udfid_icb_lbn, &ip, NULL, CRED())) != 0) {
+ udfid->udfid_icb_lbn, &ip, NULL, CRED())) != 0) {
*vpp = NULL;
return (error);
}
rw_enter(&ip->i_contents, RW_READER);
if ((udfid->udfid_uinq_lo != (ip->i_uniqid & 0xffffffff)) ||
- (udfid->udfid_prn != ip->i_icb_prn)) {
+ (udfid->udfid_prn != ip->i_icb_prn)) {
rw_exit(&ip->i_contents);
VN_RELE(ITOV(ip));
*vpp = NULL;
@@ -555,7 +570,7 @@ udf_mountroot(struct vfs *vfsp, enum whymountroot why)
(void) dnlc_purge_vfsp(vfsp, 0);
vp = common_specvp(vp);
(void) VOP_PUTPAGE(vp, (offset_t)0,
- (uint32_t)0, B_INVAL, CRED(), NULL);
+ (uint32_t)0, B_INVAL, CRED(), NULL);
binval(vfsp->vfs_dev);
ovflags = vfsp->vfs_flag;
@@ -566,7 +581,7 @@ udf_mountroot(struct vfs *vfsp, enum whymountroot why)
ud_update(0);
vp = ((struct udf_vfs *)vfsp->vfs_data)->udf_devvp;
(void) VOP_CLOSE(vp, FREAD|FWRITE, 1,
- (offset_t)0, CRED(), NULL);
+ (offset_t)0, CRED(), NULL);
return (0);
}
@@ -589,7 +604,7 @@ udf_mountroot(struct vfs *vfsp, enum whymountroot why)
if (why == ROOT_INIT) {
vfs_add((struct vnode *)0, vfsp,
- (vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0);
+ (vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0);
}
vfs_unlock(vfsp);
return (0);
@@ -678,7 +693,7 @@ ud_mountfs(struct vfs *vfsp,
if (udf_vfsp->udf_flags & UDF_FL_RDONLY) {
(void) dnlc_purge_vfsp(vfsp, 0);
(void) VOP_PUTPAGE(devvp, (offset_t)0, (uint_t)0,
- B_INVAL, CRED(), NULL);
+ B_INVAL, CRED(), NULL);
(void) ud_iflush(vfsp);
bflush(dev);
binval(dev);
@@ -689,7 +704,7 @@ ud_mountfs(struct vfs *vfsp,
* disallow mount of any highier version
*/
if ((udf_vfsp->udf_miread > UDF_150) ||
- (udf_vfsp->udf_miwrite > UDF_150)) {
+ (udf_vfsp->udf_miwrite > UDF_150)) {
error = EINVAL;
goto remountout;
}
@@ -715,8 +730,8 @@ ud_mountfs(struct vfs *vfsp,
* mount in rw mode
*/
tpt = ud_bread(vfsp->vfs_dev,
- udf_vfsp->udf_iseq_loc << udf_vfsp->udf_l2d_shift,
- udf_vfsp->udf_iseq_len);
+ udf_vfsp->udf_iseq_loc << udf_vfsp->udf_l2d_shift,
+ udf_vfsp->udf_iseq_len);
if (tpt->b_flags & B_ERROR) {
error = EIO;
goto remountout;
@@ -735,7 +750,7 @@ ud_mountfs(struct vfs *vfsp,
lvid = (struct log_vol_int_desc *)ttag;
if (SWAP_32(lvid->lvid_int_type) !=
- LOG_VOL_CLOSE_INT) {
+ LOG_VOL_CLOSE_INT) {
error = EINVAL;
goto remountout;
}
@@ -744,7 +759,7 @@ ud_mountfs(struct vfs *vfsp,
* Copy new data to old data
*/
bcopy(udf_vfsp->udf_iseq->b_un.b_addr,
- tpt->b_un.b_addr, udf_vfsp->udf_iseq_len);
+ tpt->b_un.b_addr, udf_vfsp->udf_iseq_len);
break;
}
}
@@ -846,7 +861,7 @@ remountout:
* disallow mount of any highier version
*/
if ((udf_vfsp->udf_miread > UDF_150) ||
- (udf_vfsp->udf_miwrite > UDF_150)) {
+ (udf_vfsp->udf_miwrite > UDF_150)) {
error = EINVAL;
goto out;
}
@@ -904,7 +919,7 @@ remountout:
_NOTE(COMPETING_THREADS_NOW);
#endif
if (error = ud_iget(vfsp, udf_vfsp->udf_ricb_prn,
- udf_vfsp->udf_ricb_loc, &rip, NULL, cr)) {
+ udf_vfsp->udf_ricb_loc, &rip, NULL, cr)) {
mutex_destroy(&udf_vfsp->udf_lock);
goto out;
}
@@ -937,7 +952,7 @@ out:
ud_destroy_fsp(udf_vfsp);
if (needclose) {
(void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ?
- FREAD : FREAD|FWRITE, 1, (offset_t)0, cr, NULL);
+ FREAD : FREAD|FWRITE, 1, (offset_t)0, cr, NULL);
bflush(dev);
binval(dev);
}
@@ -982,8 +997,8 @@ ud_validate_and_fill_superblock(dev_t dev, int32_t bsize, uint32_t avd_loc)
*/
secbp = ud_bread(dev, avd_loc << shift, ANCHOR_VOL_DESC_LEN);
if ((error = geterror(secbp)) != 0) {
- cmn_err(CE_NOTE,
- "udfs : Could not read Anchor Volume Desc %x", error);
+ cmn_err(CE_NOTE, "udfs : Could not read Anchor Volume Desc %x",
+ error);
brelse(secbp);
return (NULL);
}
@@ -994,7 +1009,7 @@ ud_validate_and_fill_superblock(dev_t dev, int32_t bsize, uint32_t avd_loc)
return (NULL);
}
udf_vfsp = (struct udf_vfs *)
- kmem_zalloc(sizeof (struct udf_vfs), KM_SLEEP);
+ kmem_zalloc(sizeof (struct udf_vfs), KM_SLEEP);
udf_vfsp->udf_mvds_loc = SWAP_32(avdp->avd_main_vdse.ext_loc);
udf_vfsp->udf_mvds_len = SWAP_32(avdp->avd_main_vdse.ext_len);
udf_vfsp->udf_rvds_loc = SWAP_32(avdp->avd_res_vdse.ext_loc);
@@ -1008,15 +1023,15 @@ ud_validate_and_fill_superblock(dev_t dev, int32_t bsize, uint32_t avd_loc)
*/
vds_loc = udf_vfsp->udf_mvds_loc;
secbp = ud_bread(dev, vds_loc << shift,
- udf_vfsp->udf_mvds_len);
+ udf_vfsp->udf_mvds_len);
if ((error = geterror(secbp)) != 0) {
brelse(secbp);
- cmn_err(CE_NOTE,
- "udfs : Could not read Main Volume Desc %x", error);
+ cmn_err(CE_NOTE, "udfs : Could not read Main Volume Desc %x",
+ error);
vds_loc = udf_vfsp->udf_rvds_loc;
secbp = ud_bread(dev, vds_loc << shift,
- udf_vfsp->udf_rvds_len);
+ udf_vfsp->udf_rvds_len);
if ((error = geterror(secbp)) != 0) {
brelse(secbp);
cmn_err(CE_NOTE,
@@ -1046,7 +1061,7 @@ ud_validate_and_fill_superblock(dev_t dev, int32_t bsize, uint32_t avd_loc)
1, desc_len) == 0) {
if (udf_vfsp->udf_pvd == NULL) {
udf_vfsp->udf_pvd =
- (struct pri_vol_desc *)ttag;
+ (struct pri_vol_desc *)ttag;
} else {
struct pri_vol_desc *opvd, *npvd;
@@ -1054,15 +1069,15 @@ ud_validate_and_fill_superblock(dev_t dev, int32_t bsize, uint32_t avd_loc)
npvd = (struct pri_vol_desc *)ttag;
if ((strncmp(opvd->pvd_vsi,
- npvd->pvd_vsi, 128) == 0) &&
- (strncmp(opvd->pvd_vol_id,
- npvd->pvd_vol_id, 32) == 0) &&
- (strncmp((caddr_t)&opvd->pvd_desc_cs,
- (caddr_t)&npvd->pvd_desc_cs,
- sizeof (charspec_t)) == 0)) {
+ npvd->pvd_vsi, 128) == 0) &&
+ (strncmp(opvd->pvd_vol_id,
+ npvd->pvd_vol_id, 32) == 0) &&
+ (strncmp((caddr_t)&opvd->pvd_desc_cs,
+ (caddr_t)&npvd->pvd_desc_cs,
+ sizeof (charspec_t)) == 0)) {
if (SWAP_32(opvd->pvd_vdsn) <
- SWAP_32(npvd->pvd_vdsn)) {
+ SWAP_32(npvd->pvd_vdsn)) {
udf_vfsp->udf_pvd = npvd;
}
} else {
@@ -1076,7 +1091,7 @@ ud_validate_and_fill_superblock(dev_t dev, int32_t bsize, uint32_t avd_loc)
lvd = (struct log_vol_desc *)ttag;
if (strncmp(lvd->lvd_dom_id.reg_id,
- UDF_DOMAIN_NAME, 23) != 0) {
+ UDF_DOMAIN_NAME, 23) != 0) {
printf("Domain ID in lvd is not valid\n");
goto out;
}
@@ -1088,12 +1103,12 @@ ud_validate_and_fill_superblock(dev_t dev, int32_t bsize, uint32_t avd_loc)
olvd = udf_vfsp->udf_lvd;
if ((strncmp((caddr_t)&olvd->lvd_desc_cs,
- (caddr_t)&lvd->lvd_desc_cs,
- sizeof (charspec_t)) == 0) &&
- (strncmp(olvd->lvd_lvid,
- lvd->lvd_lvid, 128) == 0)) {
+ (caddr_t)&lvd->lvd_desc_cs,
+ sizeof (charspec_t)) == 0) &&
+ (strncmp(olvd->lvd_lvid,
+ lvd->lvd_lvid, 128) == 0)) {
if (SWAP_32(olvd->lvd_vdsn) <
- SWAP_32(lvd->lvd_vdsn)) {
+ SWAP_32(lvd->lvd_vdsn)) {
udf_vfsp->udf_lvd = lvd;
}
} else {
@@ -1111,35 +1126,37 @@ ud_validate_and_fill_superblock(dev_t dev, int32_t bsize, uint32_t avd_loc)
pdesc = (struct part_desc *)ttag;
pold = udf_vfsp->udf_parts;
for (i = 0; i < udf_vfsp->udf_npart; i++) {
- if (pold->udp_number ==
- SWAP_16(pdesc->pd_pnum)) {
- if (SWAP_32(pdesc->pd_vdsn) >
- pold->udp_seqno) {
- pold->udp_seqno =
- SWAP_32(pdesc->pd_vdsn);
- pold->udp_access =
- SWAP_32(pdesc->pd_acc_type);
- pold->udp_start =
- SWAP_32(pdesc->pd_part_start);
- pold->udp_length =
- SWAP_32(pdesc->pd_part_length);
- }
- goto loop_end;
+ if (pold->udp_number !=
+ SWAP_16(pdesc->pd_pnum)) {
+ pold++;
+ continue;
+ }
+
+ if (SWAP_32(pdesc->pd_vdsn) >
+ pold->udp_seqno) {
+ pold->udp_seqno =
+ SWAP_32(pdesc->pd_vdsn);
+ pold->udp_access =
+ SWAP_32(pdesc->pd_acc_type);
+ pold->udp_start =
+ SWAP_32(pdesc->pd_part_start);
+ pold->udp_length =
+ SWAP_32(pdesc->pd_part_length);
}
- pold ++;
+ goto loop_end;
}
pold = udf_vfsp->udf_parts;
udf_vfsp->udf_npart++;
pnew = kmem_zalloc(udf_vfsp->udf_npart *
- sizeof (struct ud_part), KM_SLEEP);
+ sizeof (struct ud_part), KM_SLEEP);
udf_vfsp->udf_parts = pnew;
if (pold) {
bcopy(pold, pnew,
- sizeof (struct ud_part) *
- (udf_vfsp->udf_npart - 1));
+ sizeof (struct ud_part) *
+ (udf_vfsp->udf_npart - 1));
kmem_free(pold,
- sizeof (struct ud_part) *
- (udf_vfsp->udf_npart - 1));
+ sizeof (struct ud_part) *
+ (udf_vfsp->udf_npart - 1));
}
part = pnew + (udf_vfsp->udf_npart - 1);
part->udp_number = SWAP_16(pdesc->pd_pnum);
@@ -1157,23 +1174,23 @@ ud_validate_and_fill_superblock(dev_t dev, int32_t bsize, uint32_t avd_loc)
if (hdr->phdr_ust.sad_ext_len) {
part->udp_flags = UDP_SPACETBLS;
part->udp_unall_loc =
- SWAP_32(hdr->phdr_ust.sad_ext_loc);
+ SWAP_32(hdr->phdr_ust.sad_ext_loc);
part->udp_unall_len =
- SWAP_32(hdr->phdr_ust.sad_ext_len);
+ SWAP_32(hdr->phdr_ust.sad_ext_len);
part->udp_freed_loc =
- SWAP_32(hdr->phdr_fst.sad_ext_loc);
+ SWAP_32(hdr->phdr_fst.sad_ext_loc);
part->udp_freed_len =
- SWAP_32(hdr->phdr_fst.sad_ext_len);
+ SWAP_32(hdr->phdr_fst.sad_ext_len);
} else {
part->udp_flags = UDP_BITMAPS;
part->udp_unall_loc =
- SWAP_32(hdr->phdr_usb.sad_ext_loc);
+ SWAP_32(hdr->phdr_usb.sad_ext_loc);
part->udp_unall_len =
- SWAP_32(hdr->phdr_usb.sad_ext_len);
+ SWAP_32(hdr->phdr_usb.sad_ext_len);
part->udp_freed_loc =
- SWAP_32(hdr->phdr_fsb.sad_ext_loc);
+ SWAP_32(hdr->phdr_fsb.sad_ext_loc);
part->udp_freed_len =
- SWAP_32(hdr->phdr_fsb.sad_ext_len);
+ SWAP_32(hdr->phdr_fsb.sad_ext_len);
}
} else if (ud_verify_tag_and_desc(ttag, UD_TERM_DESC,
vds_loc + (index >> shift),
@@ -1185,8 +1202,8 @@ loop_end:
;
}
if ((udf_vfsp->udf_pvd == NULL) ||
- (udf_vfsp->udf_lvd == NULL) ||
- (udf_vfsp->udf_parts == NULL)) {
+ (udf_vfsp->udf_lvd == NULL) ||
+ (udf_vfsp->udf_parts == NULL)) {
goto out;
}
@@ -1201,7 +1218,7 @@ loop_end:
* Process Logical Volume Descriptor
*/
udf_vfsp->udf_lbsize =
- SWAP_32(udf_vfsp->udf_lvd->lvd_log_bsize);
+ SWAP_32(udf_vfsp->udf_lvd->lvd_log_bsize);
udf_vfsp->udf_lbmask = udf_vfsp->udf_lbsize - 1;
udf_vfsp->udf_l2d_shift = shift;
udf_vfsp->udf_l2b_shift = shift + DEV_BSHIFT;
@@ -1211,7 +1228,7 @@ loop_end:
* proper domain.
*/
if (strcmp(udf_vfsp->udf_lvd->lvd_dom_id.reg_id,
- UDF_DOMAIN_NAME) != 0) {
+ UDF_DOMAIN_NAME) != 0) {
goto out;
}
@@ -1224,16 +1241,16 @@ loop_end:
}
udf_vfsp->udf_iseq_loc =
- SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_loc);
+ SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_loc);
udf_vfsp->udf_iseq_len =
- SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_len);
+ SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_len);
udf_vfsp->udf_fsd_prn =
- SWAP_16(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_prn);
+ SWAP_16(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_prn);
udf_vfsp->udf_fsd_loc =
- SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_loc);
+ SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_loc);
udf_vfsp->udf_fsd_len =
- SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_len);
+ SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_len);
/*
@@ -1242,13 +1259,13 @@ loop_end:
udf_vfsp->udf_mtype = udf_vfsp->udf_parts[0].udp_access;
for (index = 0; index < udf_vfsp->udf_npart; index ++) {
if (udf_vfsp->udf_parts[index].udp_access <
- udf_vfsp->udf_mtype) {
+ udf_vfsp->udf_mtype) {
udf_vfsp->udf_mtype =
- udf_vfsp->udf_parts[index].udp_access;
+ udf_vfsp->udf_parts[index].udp_access;
}
}
if ((udf_vfsp->udf_mtype < UDF_MT_RO) ||
- (udf_vfsp->udf_mtype > UDF_MT_OW)) {
+ (udf_vfsp->udf_mtype > UDF_MT_OW)) {
udf_vfsp->udf_mtype = UDF_MT_RO;
}
@@ -1258,19 +1275,19 @@ loop_end:
for (index = 0; index < count; index++) {
if ((hdr->maph_type == MAP_TYPE1) &&
- (hdr->maph_length == MAP_TYPE1_LEN)) {
+ (hdr->maph_length == MAP_TYPE1_LEN)) {
typ1 = (struct pmap_typ1 *)hdr;
map = udf_vfsp->udf_maps;
udf_vfsp->udf_maps =
- kmem_zalloc(sizeof (struct ud_map) *
- (udf_vfsp->udf_nmaps + 1),
- KM_SLEEP);
+ kmem_zalloc(sizeof (struct ud_map) *
+ (udf_vfsp->udf_nmaps + 1), KM_SLEEP);
if (map != NULL) {
bcopy(map, udf_vfsp->udf_maps,
- sizeof (struct ud_map) * udf_vfsp->udf_nmaps);
- kmem_free(map,
- sizeof (struct ud_map) * udf_vfsp->udf_nmaps);
+ sizeof (struct ud_map) *
+ udf_vfsp->udf_nmaps);
+ kmem_free(map, sizeof (struct ud_map) *
+ udf_vfsp->udf_nmaps);
}
map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
map->udm_flags = UDM_MAP_NORM;
@@ -1278,11 +1295,11 @@ loop_end:
map->udm_pn = SWAP_16(typ1->map1_pn);
udf_vfsp->udf_nmaps ++;
} else if ((hdr->maph_type == MAP_TYPE2) &&
- (hdr->maph_length == MAP_TYPE2_LEN)) {
+ (hdr->maph_length == MAP_TYPE2_LEN)) {
typ2 = (struct pmap_typ2 *)hdr;
if (strncmp(typ2->map2_pti.reg_id,
- UDF_VIRT_PART, 23) == 0) {
+ UDF_VIRT_PART, 23) == 0) {
/*
* Add this to the normal
* partition table so that
@@ -1290,16 +1307,15 @@ loop_end:
*/
map = udf_vfsp->udf_maps;
udf_vfsp->udf_maps =
- kmem_zalloc(sizeof (struct ud_map) *
- (udf_vfsp->udf_nmaps + 1),
- KM_SLEEP);
+ kmem_zalloc(sizeof (struct ud_map) *
+ (udf_vfsp->udf_nmaps + 1), KM_SLEEP);
if (map != NULL) {
bcopy(map, udf_vfsp->udf_maps,
- sizeof (struct ud_map) *
- udf_vfsp->udf_nmaps);
+ sizeof (struct ud_map) *
+ udf_vfsp->udf_nmaps);
kmem_free(map,
- sizeof (struct ud_map) *
- udf_vfsp->udf_nmaps);
+ sizeof (struct ud_map) *
+ udf_vfsp->udf_nmaps);
}
map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
map->udm_flags = UDM_MAP_VPM;
@@ -1310,34 +1326,34 @@ loop_end:
goto out;
}
if (error = ud_val_get_vat(udf_vfsp, dev,
- lblkno, map)) {
+ lblkno, map)) {
goto out;
}
} else if (strncmp(typ2->map2_pti.reg_id,
- UDF_SPAR_PART, 23) == 0) {
+ UDF_SPAR_PART, 23) == 0) {
if (SWAP_16(typ2->map2_pl) != 32) {
printf(
- "Packet Length is not valid %x\n",
- SWAP_16(typ2->map2_pl));
+ "Packet Length is not valid %x\n",
+ SWAP_16(typ2->map2_pl));
goto out;
}
if ((typ2->map2_nst < 1) ||
- (typ2->map2_nst > 4)) {
+ (typ2->map2_nst > 4)) {
goto out;
}
map = udf_vfsp->udf_maps;
udf_vfsp->udf_maps =
- kmem_zalloc(sizeof (struct ud_map) *
- (udf_vfsp->udf_nmaps + 1),
- KM_SLEEP);
+ kmem_zalloc(sizeof (struct ud_map) *
+ (udf_vfsp->udf_nmaps + 1),
+ KM_SLEEP);
if (map != NULL) {
bcopy(map, udf_vfsp->udf_maps,
- sizeof (struct ud_map) *
- udf_vfsp->udf_nmaps);
+ sizeof (struct ud_map) *
+ udf_vfsp->udf_nmaps);
kmem_free(map,
- sizeof (struct ud_map) *
- udf_vfsp->udf_nmaps);
+ sizeof (struct ud_map) *
+ udf_vfsp->udf_nmaps);
}
map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
map->udm_flags = UDM_MAP_SPM;
@@ -1347,7 +1363,7 @@ loop_end:
udf_vfsp->udf_nmaps ++;
if (error = ud_read_sparing_tbls(udf_vfsp,
- dev, map, typ2)) {
+ dev, map, typ2)) {
goto out;
}
} else {
@@ -1373,11 +1389,11 @@ loop_end:
* and process it
*/
secbp = ud_bread(dev, udf_vfsp->udf_iseq_loc << shift,
- udf_vfsp->udf_iseq_len);
+ udf_vfsp->udf_iseq_len);
if ((error = geterror(secbp)) != 0) {
cmn_err(CE_NOTE,
"udfs : Could not read Logical Volume Integrity Sequence %x",
- error);
+ error);
brelse(secbp);
goto out;
}
@@ -1424,8 +1440,8 @@ loop_end:
}
if ((blkno = ud_xlate_to_daddr(udf_vfsp,
- udf_vfsp->udf_fsd_prn, udf_vfsp->udf_fsd_loc,
- 1, &dummy)) == 0) {
+ udf_vfsp->udf_fsd_prn, udf_vfsp->udf_fsd_loc,
+ 1, &dummy)) == 0) {
goto out;
}
secbp = ud_bread(dev, blkno << shift, udf_vfsp->udf_fsd_len);
@@ -1449,8 +1465,8 @@ loop_end:
secbp->b_flags = B_AGE | B_STALE;
brelse(secbp);
udf_vfsp->udf_root_blkno = ud_xlate_to_daddr(udf_vfsp,
- udf_vfsp->udf_ricb_prn, udf_vfsp->udf_ricb_loc,
- 1, &dummy);
+ udf_vfsp->udf_ricb_prn, udf_vfsp->udf_ricb_loc,
+ 1, &dummy);
return (udf_vfsp);
out:
@@ -1603,7 +1619,7 @@ ud_get_last_block(dev_t dev, daddr_t *blkno)
int32_t rval, error;
if ((error = cdev_ioctl(dev, DKIOCGVTOC, (intptr_t)&vtoc,
- FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
+ FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
cmn_err(CE_NOTE, "Could not get the vtoc information");
return (error);
}
@@ -1612,7 +1628,7 @@ ud_get_last_block(dev_t dev, daddr_t *blkno)
return (EINVAL);
}
if ((error = cdev_ioctl(dev, DKIOCINFO, (intptr_t)&dki_info,
- FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
+ FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
cmn_err(CE_NOTE, "Could not get the slice information");
return (error);
}
@@ -1656,8 +1672,8 @@ ud_val_get_vat(struct udf_vfs *udf_vfsp, dev_t dev,
udm->udm_vat_icb = end_loc - ud_sub_blks[i];
secbp = ud_bread(dev,
- udm->udm_vat_icb << udf_vfsp->udf_l2d_shift,
- udf_vfsp->udf_lbsize);
+ udm->udm_vat_icb << udf_vfsp->udf_l2d_shift,
+ udf_vfsp->udf_lbsize);
ASSERT(secbp->b_un.b_addr);
fe = (struct file_entry *)secbp->b_un.b_addr;
@@ -1683,10 +1699,10 @@ ud_val_get_vat(struct udf_vfs *udf_vfsp, dev_t dev,
udm->udm_nent = 1;
} else if (ad_type == ICB_FLAG_SHORT_AD) {
udm->udm_nent =
- SWAP_32(fe->fe_len_adesc) / sizeof (struct short_ad);
+ SWAP_32(fe->fe_len_adesc) / sizeof (struct short_ad);
} else if (ad_type == ICB_FLAG_LONG_AD) {
udm->udm_nent =
- SWAP_32(fe->fe_len_adesc) / sizeof (struct long_ad);
+ SWAP_32(fe->fe_len_adesc) / sizeof (struct long_ad);
} else {
err = EINVAL;
goto end;
@@ -1701,22 +1717,22 @@ ud_val_get_vat(struct udf_vfs *udf_vfsp, dev_t dev,
if (ad_type == ICB_FLAG_ONE_AD) {
udm->udm_count[0] = (SWAP_64(fe->fe_info_len) - 36) /
- sizeof (uint32_t);
+ sizeof (uint32_t);
udm->udm_bp[0] = secbp;
udm->udm_addr[0] = (uint32_t *)
- &fe->fe_spec[SWAP_32(fe->fe_len_ear)];
+ &fe->fe_spec[SWAP_32(fe->fe_len_ear)];
return (0);
}
for (i = 0; i < udm->udm_nent; i++) {
if (ad_type == ICB_FLAG_SHORT_AD) {
sad = (struct short_ad *)
- (fe->fe_spec + SWAP_32(fe->fe_len_ear));
+ (fe->fe_spec + SWAP_32(fe->fe_len_ear));
sad += i;
count = SWAP_32(sad->sad_ext_len);
blk = SWAP_32(sad->sad_ext_loc);
} else {
lad = (struct long_ad *)
- (fe->fe_spec + SWAP_32(fe->fe_len_ear));
+ (fe->fe_spec + SWAP_32(fe->fe_len_ear));
lad += i;
count = SWAP_32(lad->lad_ext_len);
blk = SWAP_32(lad->lad_ext_loc);
@@ -1744,9 +1760,9 @@ ud_val_get_vat(struct udf_vfs *udf_vfsp, dev_t dev,
count = (count + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
udm->udm_bp[i] = ud_bread(dev,
- blk << udf_vfsp->udf_l2d_shift, count);
+ blk << udf_vfsp->udf_l2d_shift, count);
if ((udm->udm_bp[i]->b_error != 0) ||
- (udm->udm_bp[i]->b_resid)) {
+ (udm->udm_bp[i]->b_resid)) {
err = EINVAL;
break;
}
@@ -1782,7 +1798,7 @@ ud_read_sparing_tbls(struct udf_vfs *udf_vfsp,
map->udm_loc[index] = SWAP_32(typ2->map2_st[index]);
bp = ud_bread(dev,
- map->udm_loc[index] << udf_vfsp->udf_l2d_shift, sz);
+ map->udm_loc[index] << udf_vfsp->udf_l2d_shift, sz);
if ((bp->b_error != 0) || (bp->b_resid)) {
brelse(bp);
continue;
@@ -1840,23 +1856,23 @@ ud_get_lbsize(dev_t dev, uint32_t *loc)
}
if (cdev_ioctl(dev, CDROMREADOFFSET, (intptr_t)&session_offset,
- FKIOCTL|FREAD|FNATIVE, CRED(), &rval) != 0) {
+ FKIOCTL|FREAD|FNATIVE, CRED(), &rval) != 0) {
session_offset = 0;
}
for (index = 0; index < end_index; index++) {
for (bsize = DEV_BSIZE, shift = 0;
- bsize <= MAXBSIZE; bsize <<= 1, shift++) {
+ bsize <= MAXBSIZE; bsize <<= 1, shift++) {
if (index == 0) {
avd_loc = 256;
if (bsize <= 2048) {
avd_loc +=
- session_offset * 2048 / bsize;
+ session_offset * 2048 / bsize;
} else {
avd_loc +=
- session_offset / (bsize / 2048);
+ session_offset / (bsize / 2048);
}
} else if (index == 1) {
avd_loc = last_block - (1 << shift);
@@ -1865,7 +1881,7 @@ ud_get_lbsize(dev_t dev, uint32_t *loc)
}
bp = ud_bread(dev, avd_loc << shift,
- ANCHOR_VOL_DESC_LEN);
+ ANCHOR_VOL_DESC_LEN);
if (geterror(bp) != 0) {
brelse(bp);
continue;
diff --git a/usr/src/uts/common/fs/ufs/ufs_vfsops.c b/usr/src/uts/common/fs/ufs/ufs_vfsops.c
index 80151eaa32..bcc7bfbfd0 100644
--- a/usr/src/uts/common/fs/ufs/ufs_vfsops.c
+++ b/usr/src/uts/common/fs/ufs/ufs_vfsops.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -265,7 +265,8 @@ ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
char *data = uap->dataptr;
int datalen = uap->datalen;
dev_t dev;
- struct vnode *bvp;
+ struct vnode *lvp = NULL;
+ struct vnode *svp = NULL;
struct pathname dpn;
int error;
enum whymountroot why = ROOT_INIT;
@@ -308,6 +309,16 @@ ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
} else {
datalen = 0;
}
+
+ if ((vfsp->vfs_flag & VFS_RDONLY) != 0 ||
+ (uap->flags & MS_RDONLY) != 0) {
+ oflag = FREAD;
+ aflag = VREAD;
+ } else {
+ oflag = FREAD | FWRITE;
+ aflag = VREAD | VWRITE;
+ }
+
/*
* Read in the mount point pathname
* (so we can record the directory the file system was last mounted on).
@@ -318,55 +329,67 @@ ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
/*
* Resolve path name of special file being mounted.
*/
- if (error = lookupname(uap->spec, fromspace, FOLLOW, NULL, &bvp)) {
+ if (error = lookupname(uap->spec, fromspace, FOLLOW, NULL, &svp)) {
pn_free(&dpn);
return (error);
}
- if (bvp->v_type != VBLK) {
- VN_RELE(bvp);
- pn_free(&dpn);
- return (ENOTBLK);
- }
- dev = bvp->v_rdev;
- if (getmajor(dev) >= devcnt) {
+
+ error = vfs_get_lofi(vfsp, &lvp);
+
+ if (error > 0) {
+ VN_RELE(svp);
pn_free(&dpn);
- VN_RELE(bvp);
- return (ENXIO);
+ return (error);
+ } else if (error == 0) {
+ dev = lvp->v_rdev;
+
+ if (getmajor(dev) >= devcnt) {
+ error = ENXIO;
+ goto out;
+ }
+ } else {
+ dev = svp->v_rdev;
+
+ if (svp->v_type != VBLK) {
+ VN_RELE(svp);
+ pn_free(&dpn);
+ return (ENOTBLK);
+ }
+
+ if (getmajor(dev) >= devcnt) {
+ error = ENXIO;
+ goto out;
+ }
+
+ /*
+ * In SunCluster, requests to a global device are
+ * satisfied by a local device. We substitute the global
+ * pxfs node with a local spec node here.
+ */
+ if (IS_PXFSVP(svp)) {
+ ASSERT(lvp == NULL);
+ VN_RELE(svp);
+ svp = makespecvp(dev, VBLK);
+ }
+
+ if ((error = secpolicy_spec_open(cr, svp, oflag)) != 0) {
+ VN_RELE(svp);
+ pn_free(&dpn);
+ return (error);
+ }
}
+
if (uap->flags & MS_REMOUNT)
why = ROOT_REMOUNT;
/*
- * In SunCluster, requests to a global device are satisfied by
- * a local device. We substitute the global pxfs node with a
- * local spec node here.
- */
- if (IS_PXFSVP(bvp)) {
- VN_RELE(bvp);
- bvp = makespecvp(dev, VBLK);
- }
-
- /*
- * Open block device mounted on. We need this to
- * check whether the caller has sufficient rights to
- * access the device in question.
- * When bio is fixed for vnodes this can all be vnode
+ * Open device/file mounted on. We need this to check whether
+ * the caller has sufficient rights to access the resource in
+ * question. When bio is fixed for vnodes this can all be vnode
* operations.
*/
- if ((vfsp->vfs_flag & VFS_RDONLY) != 0 ||
- (uap->flags & MS_RDONLY) != 0) {
- oflag = FREAD;
- aflag = VREAD;
- } else {
- oflag = FREAD | FWRITE;
- aflag = VREAD | VWRITE;
- }
- if ((error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
- (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
- pn_free(&dpn);
- VN_RELE(bvp);
- return (error);
- }
+ if ((error = VOP_ACCESS(svp, aflag, 0, cr, NULL)) != 0)
+ goto out;
/*
* Ensure that this device isn't already mounted or in progress on a
@@ -376,15 +399,13 @@ ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
if ((uap->flags & MS_NOCHECK) == 0) {
if ((uap->flags & MS_GLOBAL) == 0 &&
vfs_devmounting(dev, vfsp)) {
- pn_free(&dpn);
- VN_RELE(bvp);
- return (EBUSY);
+ error = EBUSY;
+ goto out;
}
if (vfs_devismounted(dev)) {
if ((uap->flags & MS_REMOUNT) == 0) {
- pn_free(&dpn);
- VN_RELE(bvp);
- return (EBUSY);
+ error = EBUSY;
+ goto out;
}
}
}
@@ -402,15 +423,31 @@ ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
/*
* Mount the filesystem, free the device vnode on error.
*/
- error = mountfs(vfsp, why, bvp, dpn.pn_path, cr, 0, &args, datalen);
+ error = mountfs(vfsp, why, lvp != NULL ? lvp : svp,
+ dpn.pn_path, cr, 0, &args, datalen);
+
+ if (error == 0) {
+ vfs_set_feature(vfsp, VFSFT_XVATTR);
+
+ /*
+ * If lofi, drop our reference to the original file.
+ */
+ if (lvp != NULL)
+ VN_RELE(svp);
+ }
+
+out:
pn_free(&dpn);
+
if (error) {
- VN_RELE(bvp);
+ if (lvp != NULL)
+ VN_RELE(lvp);
+ if (svp != NULL)
+ VN_RELE(svp);
}
- if (error == 0)
- vfs_set_feature(vfsp, VFSFT_XVATTR);
return (error);
}
+
/*
* Mount root file system.
* "why" is ROOT_INIT on initial call ROOT_REMOUNT if called to
diff --git a/usr/src/uts/common/fs/vfs.c b/usr/src/uts/common/fs/vfs.c
index 3c2008f599..842fd07320 100644
--- a/usr/src/uts/common/fs/vfs.c
+++ b/usr/src/uts/common/fs/vfs.c
@@ -85,6 +85,7 @@
#include <sys/reboot.h>
#include <sys/attr.h>
#include <sys/spa.h>
+#include <sys/lofi.h>
#include <vm/page.h>
@@ -525,6 +526,7 @@ vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
vfsp->vfs_prev = vfsp;
vfsp->vfs_zone_next = vfsp;
vfsp->vfs_zone_prev = vfsp;
+ vfsp->vfs_lofi_minor = 0;
sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
vfsimpl_setup(vfsp);
vfsp->vfs_data = (data);
@@ -982,6 +984,129 @@ stripzonepath(const char *strpath)
}
/*
+ * Check to see if our "block device" is actually a file. If so,
+ * automatically add a lofi device, and keep track of this fact.
+ */
+static int
+lofi_add(const char *fsname, struct vfs *vfsp,
+ mntopts_t *mntopts, struct mounta *uap)
+{
+ int fromspace = (uap->flags & MS_SYSSPACE) ?
+ UIO_SYSSPACE : UIO_USERSPACE;
+ struct lofi_ioctl *li = NULL;
+ struct vnode *vp = NULL;
+ struct pathname pn = { NULL };
+ ldi_ident_t ldi_id;
+ ldi_handle_t ldi_hdl;
+ int minor;
+ int err = 0;
+
+ if (fsname == NULL)
+ return (0);
+ if (strcmp(fsname, "mntfs") == 0 || strcmp(fsname, "lofs") == 0)
+ return (0);
+
+ if (pn_get(uap->spec, fromspace, &pn) != 0)
+ return (0);
+
+ if (lookupname(uap->spec, fromspace, FOLLOW, NULL, &vp) != 0)
+ goto out;
+
+ if (vp->v_type != VREG)
+ goto out;
+
+ /* OK, this is a lofi mount. */
+
+ if ((uap->flags & (MS_REMOUNT|MS_GLOBAL)) ||
+ vfs_optionisset_nolock(mntopts, MNTOPT_SUID, NULL) ||
+ vfs_optionisset_nolock(mntopts, MNTOPT_SETUID, NULL) ||
+ vfs_optionisset_nolock(mntopts, MNTOPT_DEVICES, NULL)) {
+ err = EINVAL;
+ goto out;
+ }
+
+ ldi_id = ldi_ident_from_anon();
+ li = kmem_zalloc(sizeof (*li), KM_SLEEP);
+ (void) strlcpy(li->li_filename, pn.pn_path, MAXPATHLEN + 1);
+
+ /*
+ * The lofi control node is currently exclusive-open. We'd like
+ * to improve this, but in the meantime, we'll loop waiting for
+ * access.
+ */
+ for (;;) {
+ err = ldi_open_by_name("/dev/lofictl", FREAD | FWRITE | FEXCL,
+ kcred, &ldi_hdl, ldi_id);
+
+ if (err != EBUSY)
+ break;
+
+ if ((err = delay_sig(hz / 8)) == EINTR)
+ break;
+ }
+
+ if (err)
+ goto out2;
+
+ err = ldi_ioctl(ldi_hdl, LOFI_MAP_FILE, (intptr_t)li,
+ FREAD | FWRITE | FEXCL | FKIOCTL, kcred, &minor);
+
+ (void) ldi_close(ldi_hdl, FREAD | FWRITE | FEXCL, kcred);
+
+ if (!err)
+ vfsp->vfs_lofi_minor = minor;
+
+out2:
+ ldi_ident_release(ldi_id);
+out:
+ if (li != NULL)
+ kmem_free(li, sizeof (*li));
+ if (vp != NULL)
+ VN_RELE(vp);
+ pn_free(&pn);
+ return (err);
+}
+
+static void
+lofi_remove(struct vfs *vfsp)
+{
+ struct lofi_ioctl *li = NULL;
+ ldi_ident_t ldi_id;
+ ldi_handle_t ldi_hdl;
+ int err;
+
+ if (vfsp->vfs_lofi_minor == 0)
+ return;
+
+ ldi_id = ldi_ident_from_anon();
+
+ li = kmem_zalloc(sizeof (*li), KM_SLEEP);
+ li->li_minor = vfsp->vfs_lofi_minor;
+ li->li_cleanup = B_TRUE;
+
+ do {
+ err = ldi_open_by_name("/dev/lofictl", FREAD | FWRITE | FEXCL,
+ kcred, &ldi_hdl, ldi_id);
+ } while (err == EBUSY);
+
+ if (err)
+ goto out;
+
+ err = ldi_ioctl(ldi_hdl, LOFI_UNMAP_FILE_MINOR, (intptr_t)li,
+ FREAD | FWRITE | FEXCL | FKIOCTL, kcred, NULL);
+
+ (void) ldi_close(ldi_hdl, FREAD | FWRITE | FEXCL, kcred);
+
+ if (!err)
+ vfsp->vfs_lofi_minor = 0;
+
+out:
+ ldi_ident_release(ldi_id);
+ if (li != NULL)
+ kmem_free(li, sizeof (*li));
+}
+
+/*
* Common mount code. Called from the system call entry point, from autofs,
* nfsv4 trigger mounts, and from pxfs.
*
@@ -1029,6 +1154,7 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
refstr_t *oldresource, *oldmntpt;
struct pathname pn, rpn;
vsk_anchor_t *vskap;
+ char fstname[FSTYPSZ];
/*
* The v_flag value for the mount point vp is permanently set
@@ -1069,7 +1195,8 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
} else if (uap->flags & (MS_OPTIONSTR | MS_DATA | MS_FSS)) {
size_t n;
uint_t fstype;
- char name[FSTYPSZ];
+
+ fsname = fstname;
if ((fstype = (uintptr_t)uap->fstype) < 256) {
RLOCK_VFSSW();
@@ -1078,19 +1205,19 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
RUNLOCK_VFSSW();
return (EINVAL);
}
- (void) strcpy(name, vfssw[fstype].vsw_name);
+ (void) strcpy(fsname, vfssw[fstype].vsw_name);
RUNLOCK_VFSSW();
- if ((vswp = vfs_getvfssw(name)) == NULL)
+ if ((vswp = vfs_getvfssw(fsname)) == NULL)
return (EINVAL);
} else {
/*
* Handle either kernel or user address space.
*/
if (uap->flags & MS_SYSSPACE) {
- error = copystr(uap->fstype, name,
+ error = copystr(uap->fstype, fsname,
FSTYPSZ, &n);
} else {
- error = copyinstr(uap->fstype, name,
+ error = copyinstr(uap->fstype, fsname,
FSTYPSZ, &n);
}
if (error) {
@@ -1098,7 +1225,7 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
return (EINVAL);
return (error);
}
- if ((vswp = vfs_getvfssw(name)) == NULL)
+ if ((vswp = vfs_getvfssw(fsname)) == NULL)
return (EINVAL);
}
} else {
@@ -1354,6 +1481,26 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
VFS_HOLD(vfsp);
+ if ((error = lofi_add(fsname, vfsp, &mnt_mntopts, uap)) != 0) {
+ if (!remount) {
+ if (splice)
+ vn_vfsunlock(vp);
+ vfs_free(vfsp);
+ } else {
+ vn_vfsunlock(vp);
+ VFS_RELE(vfsp);
+ }
+ goto errout;
+ }
+
+ /*
+ * PRIV_SYS_MOUNT doesn't mean you can become root.
+ */
+ if (vfsp->vfs_lofi_minor != 0) {
+ uap->flags |= MS_NOSUID;
+ vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
+ }
+
/*
* The vfs_reflock is not used anymore the code below explicitly
* holds it preventing others accesing it directly.
@@ -1373,6 +1520,9 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
if (!remount) {
if (error = vfs_lock(vfsp)) {
vfsp->vfs_flag = ovflags;
+
+ lofi_remove(vfsp);
+
if (splice)
vn_vfsunlock(vp);
vfs_free(vfsp);
@@ -1397,8 +1547,32 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
}
if (addmip) {
- bdev = bvp->v_rdev;
- VN_RELE(bvp);
+ vnode_t *lvp = NULL;
+
+ error = vfs_get_lofi(vfsp, &lvp);
+ if (error > 0) {
+ lofi_remove(vfsp);
+
+ if (splice)
+ vn_vfsunlock(vp);
+ vfs_unlock(vfsp);
+
+ if (remount) {
+ VFS_RELE(vfsp);
+ } else {
+ vfs_free(vfsp);
+ }
+
+ goto errout;
+ } else if (error == -1) {
+ bdev = bvp->v_rdev;
+ VN_RELE(bvp);
+ } else {
+ bdev = lvp->v_rdev;
+ VN_RELE(lvp);
+ VN_RELE(bvp);
+ }
+
vfs_addmip(bdev, vfsp);
addmip = 0;
delmip = 1;
@@ -1478,6 +1652,8 @@ domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0);
if (error) {
+ lofi_remove(vfsp);
+
if (remount) {
/* put back pre-remount options */
vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
@@ -1648,6 +1824,7 @@ errout:
if (inargs != opts)
kmem_free(inargs, MAX_MNTOPT_STR);
if (copyout_error) {
+ lofi_remove(vfsp);
VFS_RELE(vfsp);
error = copyout_error;
}
@@ -4137,6 +4314,7 @@ vfs_rele(vfs_t *vfsp)
ASSERT(vfsp->vfs_count != 0);
if (atomic_add_32_nv(&vfsp->vfs_count, -1) == 0) {
VFS_FREEVFS(vfsp);
+ lofi_remove(vfsp);
if (vfsp->vfs_zone)
zone_rele(vfsp->vfs_zone);
vfs_freemnttab(vfsp);
@@ -4483,3 +4661,35 @@ vfs_propagate_features(vfs_t *from, vfs_t *to)
to->vfs_featureset[i] = from->vfs_featureset[i];
}
}
+
+#define LOFICTL_PATH "/devices/pseudo/lofi@0:%d"
+
+/*
+ * Return the vnode for the lofi node if there's a lofi mount in place.
+ * Returns -1 when there's no lofi node, 0 on success, and > 0 on
+ * failure.
+ */
+int
+vfs_get_lofi(vfs_t *vfsp, vnode_t **vpp)
+{
+ char *path = NULL;
+ int strsize;
+ int err;
+
+ if (vfsp->vfs_lofi_minor == 0) {
+ *vpp = NULL;
+ return (-1);
+ }
+
+ strsize = snprintf(NULL, 0, LOFICTL_PATH, vfsp->vfs_lofi_minor);
+ path = kmem_alloc(strsize + 1, KM_SLEEP);
+ (void) snprintf(path, strsize + 1, LOFICTL_PATH, vfsp->vfs_lofi_minor);
+
+ err = lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, vpp);
+
+ if (err)
+ *vpp = NULL;
+
+ kmem_free(path, strsize + 1);
+ return (err);
+}
diff --git a/usr/src/uts/common/io/lofi.c b/usr/src/uts/common/io/lofi.c
index 43b948cac2..5e33149e82 100644
--- a/usr/src/uts/common/io/lofi.c
+++ b/usr/src/uts/common/io/lofi.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -325,11 +325,14 @@ lofi_close(dev_t dev, int flag, int otyp, struct cred *credp)
mark_closed(lsp, otyp);
/*
- * If we have forcibly closed the underlying device, and this is the
- * last close, then tear down the rest of the device.
+ * If we forcibly closed the underlying device (li_force), or
+ * asked for cleanup (li_cleanup), finish up if we're the last
+ * out of the door.
*/
- if (minor != 0 && lsp->ls_vp == NULL && !is_opened(lsp))
+ if (minor != 0 && !is_opened(lsp) &&
+ (lsp->ls_cleanup || lsp->ls_vp == NULL))
lofi_free_handle(dev, minor, lsp, credp);
+
mutex_exit(&lofi_lock);
return (0);
}
@@ -1403,21 +1406,28 @@ lofi_unmap_file(dev_t dev, struct lofi_ioctl *ulip, int byfilename,
return (ENXIO);
}
+ /*
+ * If it's still held open, we'll do one of three things:
+ *
+ * If no flag is set, just return EBUSY.
+ *
+ * If the 'cleanup' flag is set, unmap and remove the device when
+ * the last user finishes.
+ *
+ * If the 'force' flag is set, then we forcibly close the underlying
+ * file. Subsequent operations will fail, and the DKIOCSTATE ioctl
+ * will return DKIO_DEV_GONE. When the device is last closed, the
+ * device will be cleaned up appropriately.
+ *
+ * This is complicated by the fact that we may have outstanding
+ * dispatched I/Os. Rather than having a single mutex to serialize all
+ * I/O, we keep a count of the number of outstanding I/O requests, as
+ * well as a flag to indicate that no new I/Os should be dispatched.
+ * We set the flag, wait for the number of outstanding I/Os to reach 0,
+ * and then close the underlying vnode.
+ */
+
if (is_opened(lsp)) {
- /*
- * If the 'force' flag is set, then we forcibly close the
- * underlying file. Subsequent operations will fail, and the
- * DKIOCSTATE ioctl will return DKIO_DEV_GONE. When the device
- * is last closed, the device will be cleaned up appropriately.
- *
- * This is complicated by the fact that we may have outstanding
- * dispatched I/Os. Rather than having a single mutex to
- * serialize all I/O, we keep a count of the number of
- * outstanding I/O requests, as well as a flag to indicate that
- * no new I/Os should be dispatched. We set the flag, wait for
- * the number of outstanding I/Os to reach 0, and then close the
- * underlying vnode.
- */
if (klip->li_force) {
mutex_enter(&lsp->ls_vp_lock);
lsp->ls_vp_closereq = B_TRUE;
@@ -1434,7 +1444,13 @@ lofi_unmap_file(dev_t dev, struct lofi_ioctl *ulip, int byfilename,
(void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
free_lofi_ioctl(klip);
return (0);
+ } else if (klip->li_cleanup) {
+ lsp->ls_cleanup = 1;
+ mutex_exit(&lofi_lock);
+ free_lofi_ioctl(klip);
+ return (0);
}
+
mutex_exit(&lofi_lock);
free_lofi_ioctl(klip);
return (EBUSY);
diff --git a/usr/src/uts/common/sys/lofi.h b/usr/src/uts/common/sys/lofi.h
index cea7123815..7ae6574483 100644
--- a/usr/src/uts/common/sys/lofi.h
+++ b/usr/src/uts/common/sys/lofi.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -106,6 +106,11 @@ extern "C" {
* removed, so the DKIOCSTATE ioctl will return DKIO_DEV_GONE. When the device
* is last closed, it will be torn down.
*
+ * If the 'li_cleanup' flag is set for any of the LOFI_UNMAP_* commands, then
+ * if the device is busy, it is marked for removal at the next time it is
+ * no longer held open by anybody. When the device is last closed, it will be
+ * torn down.
+ *
* Oh, and last but not least: these ioctls are totally private and only
* for use by lofiadm(1M).
*
@@ -114,6 +119,7 @@ extern "C" {
struct lofi_ioctl {
uint32_t li_minor;
boolean_t li_force;
+ boolean_t li_cleanup;
char li_filename[MAXPATHLEN + 1];
char li_algorithm[MAXALGLEN];
};
@@ -163,6 +169,7 @@ struct lofi_state {
uint32_t ls_chr_open;
uint32_t ls_lyr_open_count;
int ls_openflag;
+ boolean_t ls_cleanup; /* cleanup on close */
taskq_t *ls_taskq;
kstat_t *ls_kstat;
kmutex_t ls_kstat_lock;
diff --git a/usr/src/uts/common/sys/vfs.h b/usr/src/uts/common/sys/vfs.h
index 2ad5dde93b..2cc2e4f64c 100644
--- a/usr/src/uts/common/sys/vfs.h
+++ b/usr/src/uts/common/sys/vfs.h
@@ -251,7 +251,9 @@ typedef struct vfs {
struct zone *vfs_zone; /* zone that owns the mount */
struct vfs *vfs_zone_next; /* next VFS visible in zone */
struct vfs *vfs_zone_prev; /* prev VFS visible in zone */
+
struct fem_head *vfs_femhead; /* fs monitoring */
+ minor_t vfs_lofi_minor; /* minor if lofi mount */
} vfs_t;
#define vfs_featureset vfs_implp->vi_featureset
@@ -535,6 +537,8 @@ void vfs_root_redev(vfs_t *vfsp, dev_t ndev, int fstype);
int vfs_zone_change_safe(vfs_t *);
+int vfs_get_lofi(vfs_t *, vnode_t **);
+
#define VFSHASH(maj, min) (((int)((maj)+(min))) & (vfshsz - 1))
#define VFS_ON_LIST(vfsp) \
((vfsp)->vfs_next != (vfsp) && (vfsp)->vfs_next != NULL)