hsfs_vfsops.c revision 76a4d1fd5c4791455bf111e8a1d0f281e3fb669f
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* 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
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* VFS operations for High Sierra filesystem
*/
#include <sys/isa_defs.h>
#include <sys/sysmacros.h>
#include <sys/pathname.h>
#include <sys/vfs_opreg.h>
#include <sys/bootconf.h>
/*
* These are needed for the CDROMREADOFFSET Code
*/
#define HSFS_CLKSET
/*
* Options for mount.
*/
#define HOPT_GLOBAL MNTOPT_GLOBAL
#define HOPT_NOGLOBAL MNTOPT_NOGLOBAL
#define HOPT_MAPLCASE "maplcase"
#define HOPT_NOMAPLCASE "nomaplcase"
#define HOPT_NOTRAILDOT "notraildot"
#define HOPT_TRAILDOT "traildot"
#define HOPT_NRR "nrr"
#define HOPT_RR "rr"
#define HOPT_JOLIET "joliet"
#define HOPT_NOJOLIET "nojoliet"
#define HOPT_JOLIETLONG "jolietlong"
#define HOPT_VERS2 "vers2"
#define HOPT_NOVERS2 "novers2"
static mntopt_t hsfs_options[] = {
};
static mntopts_t hsfs_proto_opttbl = {
sizeof (hsfs_options) / sizeof (mntopt_t),
};
/*
* Indicates whether to enable the I/O scheduling and readahead logic
* 1 - Enable, 0 - Do not Enable.
* Debugging purposes.
*/
int do_schedio = 1;
static int hsfsfstype;
static int hsfsinit(int, char *);
"hsfs",
/* We don't suppport remounting */
};
};
static struct modlinkage modlinkage = {
};
char _depends_on[] = "fs/specfs";
extern void hsched_init_caches(void);
extern void hsched_fini_caches(void);
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
_fini(void)
{
int error;
if (error)
return (error);
/*
* Tear down the operations vectors
*/
(void) vfs_freevfsops_by_type(hsfsfstype);
return (0);
}
int
{
}
/* default mode, uid, gid */
uid_t hsfs_default_uid = 0;
struct modlinkage *modlinkage);
static void hs_copylabel(struct hs_volume *, unsigned char *, int);
static int
{
static const fs_operation_def_t hsfs_vfsops_template[] = {
};
int error;
if (error != 0) {
return (error);
}
if (error != 0) {
(void) vfs_freevfsops_by_type(fstype);
return (error);
}
hsfsfstype = fstype;
return (0);
}
/*ARGSUSED*/
static int
{
int vnode_busy;
int error;
int flags; /* this will hold the mount specific data */
return (error);
return (ENOTDIR);
/* mount option must be read only, else mount will be rejected */
return (EROFS);
/*
* We already told the framework that we don't support remounting.
*/
return (EBUSY);
}
/*
* Check for the options that actually affect things
* at our level.
*/
flags = 0;
flags |= HSFSMNT_NORRIP;
flags |= HSFSMNT_NOVERS2;
if (error)
return (error);
if (error != 0) {
return (error);
}
/*
* If the device is a tape, return error
*/
return (ENOTBLK);
}
/*
* Mount the filesystem.
*/
return (error);
}
/*ARGSUSED*/
static int
int flag,
{
return (EPERM);
/*
* forced unmount is not supported by this file system
* and thus, ENOTSUP is being returned.
*/
return (ENOTSUP);
return (EBUSY);
/* destroy all old pages and hsnodes for this vfs */
if (hs_synchash(vfsp))
return (EBUSY);
break;
}
panic("hsfs_unmount: vfs not mounted?");
/*NOTREACHED*/
}
/* free path table space */
/* free path table index table */
/* free "mounted on" pathame */
return (0);
}
/*ARGSUSED*/
static int
{
return (0);
}
/*ARGSUSED*/
static int
{
return (EINVAL);
return (0);
}
/*
* Previously nodeid was declared as uint32_t. This has been changed
* to conform better with the ISO9660 standard. The standard states that
* a LBN can be a 32 bit number, as the MAKE_NODEID macro shifts this
* LBN 11 places left (LBN_TO_BYTE) and then shifts the result 5 right
* (divide by 32) we are left with the potential of an overflow if
* confined to a 32 bit value.
*/
static int
{
int error;
/*
* Look for vnode on hashlist.
* If found, it's now active and the refcnt was incremented.
*/
/*
* Not in cache, so we need to remake it.
* hs_remakenode() will read the directory entry
* and then check again to see if anyone else has
* put it in the cache.
*/
return (error);
}
return (0);
}
/*
* Compute a CD-ROM fsid by checksumming the first 64K of data on the CD
* We use the 'fsp' argument to determine the location of the root
* directory entry, and we start reading from there.
*/
static int
{
int error;
int fsid;
/*
* An error on read or a partial read means we asked
* for a nonexistant/corrupted piece of the device
* (including past-the-end of the media). Don't
* try to use the checksumming method then.
*/
int i;
fsid = 0;
for (i = 0; i < CHECKSUM_SIZE / sizeof (int); i++)
} else {
/*
* Fallback - use creation date
*/
}
return (fsid);
}
/*ARGSUSED*/
static int
char *path,
int mount_flags,
int isroot)
{
int error;
int fsid;
int use_rrip;
int use_vers2;
int use_joliet;
int has_rrip = 0;
int has_vers2 = 0;
int has_joliet = 0;
int force_rrip_off;
int force_vers2_off;
int force_joliet_off;
int redo_rootvp;
/*
* The rules for which extension will be used are:
* 1. No specific mount options given:
* - use rrip if available
* - use ISO9660:1999 if available
* - use joliet if available.
* - use next "lower" extension
* - disable rrip support even if available
* - disable IOS9660:1999 support even if available
*
* We need to adjust these flags as we discover the extensions
* present. See below. These are just the starting values.
*/
/*
* Open the device
*/
/*
* Open the target device (file) for read only.
*/
return (error);
}
/*
* Refuse to go any further if this
* device is being used for swapping
*/
goto cleanup;
}
goto cleanup;
}
/*
* Make sure we have a nonzero size partition.
* The current version of the SD driver will *not* fail the open
* of such a partition so we have to check for it here.
*/
goto cleanup;
}
/*
* Init a new hsfs structure.
*/
/* hardwire perms, uid, gid */
/*
* Look for a Standard File Structure Volume Descriptor,
* of which there must be at least one.
* If found, check for volume size consistency.
*
* If svp->lbn_size is != 0, we did find a ISO-9660:1999 SVD
* If jvp->lbn_size is != 0, we did find a Joliet SVD.
*/
if (error)
goto cleanup;
/*
* Generate a file system ID from the CD-ROM,
* and check it for uniqueness.
*
* What we are aiming for is some chance of integrity
* across disk change. That is, if a client has an fhandle,
* it will be valid as long as the same disk is mounted.
*/
} else /* make sure that the fsid is unique */
break;
}
}
hs_mounttab = fsp;
goto cleanup;
}
/*
* Attempt to discover a RR extension.
*/
if (use_rrip) {
}
force_rrip_off = !use_rrip ||
force_vers2_off = !use_vers2 ||
/*
* At the moment, we have references of all three possible
* extensions (RR, ISO9660:1999/v2 and Joliet) if present.
*
* The "active" volume descriptor is RRIP (or ISO9660:1988).
* We now switch to the user-requested one.
*/
redo_rootvp = 0;
if (force_rrip_off || !has_rrip) {
if (has_vers2 && !force_vers2_off) {
redo_rootvp = 1;
has_joliet = 0;
} else if (has_joliet && !force_joliet_off) {
redo_rootvp = 1;
has_vers2 = 0;
}
}
if (redo_rootvp) {
/*
* Make sure not to use Rock Ridge.
*/
has_rrip = 0;
goto cleanup;
}
}
if (IS_RRIP_IMPLEMENTED(fsp)) {
has_vers2 = 0;
has_joliet = 0;
}
if (force_vers2_off)
has_vers2 = 0;
if (force_joliet_off)
has_joliet = 0;
/*
* mark root node as VROOT
*/
/* Here we take care of some special case stuff for mountroot */
if (isroot) {
}
if (IS_RRIP_IMPLEMENTED(fsp)) {
/*
* if RRIP, don't copy NOMAPLCASE or NOTRAILDOT to hsfs_flags
*/
} else switch (fsp->hsfs_vol_type) {
case HS_VOL_TYPE_HS:
case HS_VOL_TYPE_ISO:
default:
/*
* if iso v1, don't allow trailing spaces in iso file names
*/
break;
case HS_VOL_TYPE_ISO_V2:
/*
* if iso v2, don't copy NOTRAILDOT to hsfs_flags
*/
break;
case HS_VOL_TYPE_JOLIET:
/*
* if Joliet, don't copy NOMAPLCASE or NOTRAILDOT to hsfs_flags
*/
if (mount_flags & HSFSMNT_JOLIETLONG)
else
break;
}
/*
* Add the HSFSMNT_INODE pseudo mount flag to the current mount flags.
*/
/*
* Setup I/O Scheduling structures
*/
if (do_schedio) {
}
/*
* Setup kstats
*/
/*
* set the magic word
*/
return (0);
if (fsp)
if (svp)
if (jvp)
return (error);
}
/*
* Get the rootvp associated with fsp->hsfs_vol
*/
static int
{
/*
* If the root directory does not appear to be
* valid, use what it points to as "." instead.
* Some Defense Mapping Agency disks are non-conformant
* in this way.
*/
return (0);
}
} else {
}
/* XXX - ignore the path table for now */
return (1);
}
/*
* hs_findhsvol()
*
* Locate the Standard File Structure Volume Descriptor and
* parse it into an hs_volume structure.
*
* XXX - May someday want to look for Coded Character Set FSVD, too.
*/
static int
{
int i;
int n;
int error;
if (error != 0) {
return (error);
}
/*
* To avoid that we read the whole medium in case that someone prepares
* a malicious "fs image", we read at most 32 blocks.
*/
for (n = 0; n < 32 &&
for (i = 0; i < HSV_ID_STRLEN; i++)
goto cantfind;
goto cantfind;
switch (HSV_DESC_TYPE(volp)) {
case VD_SFS:
/* Standard File Structure */
return (error);
case VD_CCFS:
/* Coded Character File Structure */
case VD_BOOT:
case VD_UNSPEC:
case VD_EOV:
break;
}
++secno;
if (error != 0) {
error);
return (error);
}
}
return (EINVAL);
}
/*
* hs_parsehsvol
*
* Parse the Standard File Structure Volume Descriptor into
* an hs_volume structure. We can't just bcopy it into the
* structure because of byte-ordering problems.
*
*/
static int
{
"SFSVD is zero");
return (EINVAL);
}
hvp->lbn_secshift =
#if defined(_LITTLE_ENDIAN)
#else
#endif
/*
* Make sure that lbn_size is a power of two and otherwise valid.
*/
"hsfs: %d-byte logical block size not supported",
return (EINVAL);
}
}
/*
* hs_findisovol()
*
* Locate the Primary Volume Descriptor
* parse it into an hs_volume structure.
*
* XXX - Partition not yet done
*
* Except for fsp->hsfs_vol_type, no fsp member may be modified.
* fsp->hsfs_vol is modified indirectly via the *hvp argument.
*/
static int
{
int i;
int n;
int error;
int foundpvd = 0;
int foundsvd = 0;
int foundjvd = 0;
int pvd_sum = 0;
if (error != 0) {
return (error);
}
/*
* To avoid that we read the whole medium in case that someone prepares
* a malicious "fs image", we read at most 32 blocks.
*/
for (n = 0; n < 32 &&
for (i = 0; i < ISO_ID_STRLEN; i++)
goto cantfind;
switch (ISO_DESC_TYPE(volp)) {
case ISO_VD_PVD:
/* Standard File Structure */
goto cantfind;
if (foundpvd != 1) {
return (error);
}
foundpvd = 1;
for (i = 0; i < ISO_SECTOR_SIZE; i++)
}
break;
case ISO_VD_SVD:
/* Supplementary Volume Descriptor */
foundsvd != 1) {
return (error);
}
foundsvd = 1;
}
return (error);
}
foundjvd = 1;
}
break;
case ISO_VD_BOOT:
break;
case ISO_VD_VPD:
/* currently cannot handle partition */
break;
case VD_EOV:
break;
}
++secno;
if (error != 0) {
error);
return (error);
}
}
for (n = 0; n < 16; n++) {
++secno;
if (error != 0) {
error);
return (error);
}
/*
* Check for the signature from mkisofs that grants that
* the current filesystem allows to use the extent lbn as
* inode number even in pure ISO9660 mode.
*/
int sum;
sum *= 256;
sum *= 256;
break;
}
}
if (foundpvd) {
return (0);
}
return (EINVAL);
}
/*
* Return 0 if no Joliet is found
* else return Joliet Level 1..3
*/
static int
{
case '@':
return (1);
case 'C':
return (2);
case 'E':
return (3);
}
}
return (0);
}
/*
* hs_parseisovol
*
* Parse the Primary Volume Descriptor into an hs_volume structure.
*
*/
static int
{
"PVD is zero");
return (EINVAL);
}
hvp->lbn_secshift =
#if defined(_LITTLE_ENDIAN)
#else
#endif
/*
* Make sure that lbn_size is a power of two and otherwise valid.
*/
"hsfs: %d-byte logical block size not supported",
return (EINVAL);
}
}
/*
* Common code for mount and umount.
* Check that the user's argument is a reasonable
* thing on which to mount, and return the device number if so.
*/
static int
{
int error;
/*
*/
if (error) {
goto out;
}
if (error > 0) {
goto out;
} else if (error == 0) {
} else {
goto out;
}
goto out;
}
/*
*/
goto out;
/*
* Ensure that this device isn't already mounted,
* unless this is a REMOUNT request or we are told to suppress
* mount checks.
*/
if ((flags & MS_NOCHECK) == 0) {
goto out;
goto out;
}
goto out;
}
error = 0;
out:
return (error);
}
static void
{
if (isjoliet) {
/*
* hs_joliet_cp() will output 16..48 bytes.
* We need to clear 'lbuf' to avoid junk chars past byte 15.
*/
}
/* cdrom volid is at most 32 bytes */
}
/*
* Mount root file system.
* "why" is ROOT_INIT on initial call, ROOT_REMOUNT if called to
* remount the root file system, and ROOT_UNMOUNT if called to
* unmount the root (e.g., as part of a system shutdown).
*
* XXX - this may be partially machine-dependent; it, along with the VFS_SWAPVP
* operation, goes along with auto-configuration. A mechanism should be
* provided by which machine-INdependent code in the kernel can say "get me the
* right root file system" and "get me the right initial swap area", and have
* that done in what may well be a machine-dependent fashion.
* Unfortunately, it is also file-system-type dependent (NFS gets it via
* bootparams calls, UFS gets it from various and sundry machine-dependent
* mechanisms, as SPECFS does for swap).
*/
static int
{
int error;
static int hsfsrootdone = 0;
if (hsfsrootdone++)
return (EBUSY);
rootdev = getrootdev();
return (ENODEV);
} else if (why == ROOT_REMOUNT) {
return (0);
} else if (why == ROOT_UNMOUNT) {
return (0);
}
if (error) {
return (error);
}
/*
* XXX - assumes root device is not indirect, because we don't set
* rootvp. Is rootvp used for anything? If so, make another arg
* to mountfs.
*/
if (error) {
if (rootvp) {
}
return (error);
}
#ifdef HSFS_CLKSET
"hsfs_mountroot: mod_date.tv_sec == 0");
clkset(-1L);
} else {
}
} else {
}
#else /* HSFS_CLKSET */
clkset(-1L);
#endif /* HSFS_CLKSET */
return (0);
}
/*
* hs_findvoldesc()
*
* Return the sector where the volume descriptor lives. This is
* a fixed value for "normal" cd-rom's, but can change for
* multisession cd's.
*
* desc_sec is the same for high-sierra and iso 9660 formats, why
* there are two different #defines used in the code for this is
* beyond me. These are standards, cast in concrete, right?
* To be general, however, this function supports passing in different
* values.
*/
static int
{
int secno;
int error;
int rval; /* ignored */
#ifdef CDROMREADOFFSET
/*
* Issue the Read Offset ioctl directly to the
* device. Ignore any errors and set starting
* secno to the default, otherwise add the
* VOLDESC sector number to the offset.
*/
if (error) {
} else {
}
#else
#endif
return (secno);
}