udf_vfsops.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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.
*
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/resource.h>
#include <sys/pathname.h>
#include <sys/bootconf.h>
#include <vm/seg_kmem.h>
extern kmutex_t ud_sync_busy;
void ud_destroy_fsp(struct udf_vfs *);
void ud_convert_to_superblock(struct udf_vfs *,
struct log_vol_int_desc *);
void ud_update_superblock(struct vfs *);
static int udfinit(int, char *);
static mntopts_t udfs_mntopts;
"udfs",
};
static mntopts_t udfs_mntopts = {
0,
};
/*
* Module linkage information for the kernel.
*/
};
static struct modlinkage modlinkage = {
};
char _depends_on[] = "fs/specfs";
int
_init()
{
return (mod_install(&modlinkage));
}
int
_fini()
{
return (EBUSY);
}
int
{
}
/* -------------------- vfs routines -------------------- */
/*
* XXX - this appears only to be used by the VM code to handle the case where
* UNIX is running off the mini-root. That probably wants to be done
* differently.
*/
#ifndef __lint
#endif
static int32_t
{
enum whymountroot why;
ud_printf("udf_mount\n");
return (error);
}
return (ENOTDIR);
}
return (EBUSY);
}
return (error);
}
/*
* Resolve path name of special file being mounted.
*/
&bvp)) {
return (error);
}
goto out;
}
/*
* Ensure that this device isn't already mounted,
* unless this is a REMOUNT request
*/
goto out;
}
if (vfs_devismounted(dev)) {
why = ROOT_REMOUNT;
} else {
goto out;
}
} else {
}
goto out;
}
/*
* If the device is a tape, mount it read only
*/
}
}
/*
* Set mount options.
*/
}
}
/*
* Verify that the caller can open the device special file as
* required. It is not until this moment that we know whether
* we're mounting "ro" or not.
*/
} else {
}
goto out;
}
/*
* Mount the filesystem.
*/
out:
return (error);
}
/*
* unmount the file system pointed
* by vfsp
*/
/* ARGSUSED */
static int32_t
{
ud_printf("udf_unmount\n");
return (EPERM);
}
/*
* forced unmount is not supported by this file system
* and thus, ENOTSUP, is being returned.
*/
return (ENOTSUP);
(void) ud_release_cache(udf_vfsp);
/* Flush all inodes except root */
return (EBUSY);
}
}
return (0);
}
/*
* Get the root vp for the
* file system
*/
static int32_t
{
ud_printf("udf_root\n");
return (0);
}
/*
* Get file system statistics.
*/
static int32_t
{
ud_printf("udf_statvfs\n");
parts++;
}
/*
* Since there are no real inodes allocated
* we will approximate
* each new file will occupy :
* 38(over head each dent) + MAXNAMLEN / 2 + inode_size(==block size)
*/
/*
* The total number of inodes is
* the sum of files + directories + free inodes
*/
return (0);
}
/*
* Flush any pending I/O to file system vfsp.
* The ud_update() routine will only flush *all* udf files.
*/
/*ARGSUSED*/
/* ARGSUSED */
static int32_t
{
ud_printf("udf_sync\n");
return (0);
}
/* ARGSUSED */
static int32_t
{
ud_printf("udf_vget\n");
return (0);
}
return (error);
}
return (EINVAL);
}
return (0);
}
/*
* 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).
*/
/* ARGSUSED */
static int32_t
{
static int32_t udf_rootdone = 0;
ud_printf("udf_mountroot\n");
if (udf_rootdone++) {
return (EBUSY);
}
rootdev = getrootdev();
return (ENODEV);
}
} else if (why == ROOT_REMOUNT) {
(void) dnlc_purge_vfsp(vfsp, 0);
} else if (why == ROOT_UNMOUNT) {
ud_update(0);
return (0);
}
return (error);
}
if (error) {
if (why == ROOT_REMOUNT) {
}
if (rootvp) {
}
return (error);
}
}
return (0);
}
/* ------------------------- local routines ------------------------- */
static int32_t
{
struct log_vol_int_desc *lvid;
ud_printf("ud_mountfs\n");
/*
* Open the device.
*/
/*
* Open block device mounted on.
* When bio is fixed for vnodes this can all be vnode
* operations.
*/
if (error) {
goto out;
}
needclose = 1;
/*
* Refuse to go any further if this
* device is being used for swapping.
*/
goto out;
}
}
/*
* check for dev already mounted on
*/
/* cannot remount to RDONLY */
return (EINVAL);
}
return (EINVAL);
}
/*
* fsck may have altered the file system; discard
* as much incore data as possible. Don't flush
* if this is a rw to rw remount; it's just resetting
* the options.
*/
(void) dnlc_purge_vfsp(vfsp, 0);
}
/*
* We could read UDF1.50 and write UDF1.50 only
* disallow mount of any highier version
*/
goto remountout;
}
/*
*/
goto remountout;
}
/*
* Does the media type allow a writable mount
*/
goto remountout;
}
/*
* Read the metadata
* and check if it is possible to
* mount in rw mode
*/
goto remountout;
}
1, desc_len) == 0) {
struct log_vol_int_desc *lvid;
goto remountout;
}
/*
* Copy new data to old data
*/
break;
}
}
}
return (error);
}
/*
* Flush back any dirty pages on the block device to
* try and keep the buffer cache in sync with the page
* cache if someone is trying to use block devices when
* they really should be using the raw device.
*/
/*
* Check if the file system
* is a valid udfs and fill
* the required fields in udf_vfs
*/
#ifndef __lint
#endif
goto out;
}
goto out;
}
/*
* Fill in vfs private data
*/
/*
* We could read only UDF1.50
* disallow mount of any highier version
*/
goto out;
}
} else {
/* Do we have a VAT at the end of the recorded media */
break;
}
map++;
}
goto out;
}
}
} else {
/*
* We could read UDF1.50 and write UDF1.50 only
* disallow mount of any highier version
*/
goto out;
}
/*
* Check if the media allows
*/
goto out;
}
/*
* Check if we have VAT on a writable media
* we cannot use the media in presence of VAT
* Dent RW mount.
*/
goto out;
}
map++;
}
/*
* Check if the domain Id allows
* us to write
*/
goto out;
}
} else {
if (isroot) {
} else {
goto out;
}
}
}
#ifndef __lint
#endif
goto out;
}
/*
* Get the root inode and
* initialize the root vnode
*/
}
return (0);
out:
if (needclose) {
}
return (error);
}
static struct udf_vfs *
{
struct anch_vol_desc_ptr *avdp;
struct file_set_desc *fsd;
ud_printf("ud_validate_and_fill_superblock\n");
return (NULL);
}
shift = 0;
shift++;
}
/*
* Read Anchor Volume Descriptor
* Verify it and get the location of
* Main Volume Descriptor Sequence
*/
"udfs : Could not read Anchor Volume Desc %x", error);
return (NULL);
}
return (NULL);
}
/*
* Read Main Volume Descriptor Sequence
* and process it
*/
"udfs : Could not read Main Volume Desc %x", error);
"udfs : Could not read Res Volume Desc %x", error);
return (NULL);
}
}
1, desc_len) == 0) {
(struct pri_vol_desc *)ttag;
} else {
sizeof (charspec_t)) == 0)) {
}
} else {
goto out;
}
}
1, desc_len) == 0) {
struct log_vol_desc *lvd;
UDF_DOMAIN_NAME, 23) != 0) {
printf("Domain ID in lvd is not valid\n");
goto out;
}
} else {
struct log_vol_desc *olvd;
sizeof (charspec_t)) == 0) &&
}
} else {
goto out;
}
}
1, desc_len) == 0) {
int32_t i;
if (pold->udp_number ==
pold->udp_access =
pold->udp_length =
}
goto loop_end;
}
pold ++;
}
if (pold) {
sizeof (struct ud_part) *
sizeof (struct ud_part) *
}
part->udp_last_alloc = 0;
/*
* Figure out space bitmaps
* or space tables
*/
} else {
}
1, desc_len) == 0) {
break;
}
;
}
goto out;
}
/*
* Process Primary Volume Descriptor
*/
/*
* Process Logical Volume Descriptor
*/
/*
* Check if the media is in
* proper domain.
*/
UDF_DOMAIN_NAME) != 0) {
goto out;
}
/*
* AVDS offset does not match with the lbsize
* in the lvd
*/
goto out;
}
/*
* process paritions
*/
}
}
}
kmem_zalloc(sizeof (struct ud_map) *
KM_SLEEP);
}
UDF_VIRT_PART, 23) == 0) {
/*
* Add this to the normal
* partition table so that
* we donot
*/
kmem_zalloc(sizeof (struct ud_map) *
KM_SLEEP);
sizeof (struct ud_map) *
sizeof (struct ud_map) *
}
goto out;
}
goto out;
}
UDF_SPAR_PART, 23) == 0) {
"Packet Length is not valid %x\n",
goto out;
}
goto out;
}
kmem_zalloc(sizeof (struct ud_map) *
KM_SLEEP);
sizeof (struct ud_map) *
sizeof (struct ud_map) *
}
goto out;
}
} else {
/*
* Unknown type of partition
* Bail out
*/
goto out;
}
} else {
/*
* Unknown type of partition
* Bail out
*/
goto out;
}
}
/*
* Read Logical Volume Integrity Sequence
* and process it
*/
"udfs : Could not read Logical Volume Integrity Sequence %x",
error);
goto out;
}
1, desc_len) == 0) {
struct log_vol_int_desc *lvid;
} else {
}
/*
* update superblock with the metadata
*/
break;
}
}
goto out;
}
1, &dummy)) == 0) {
goto out;
}
"udfs : Could not read File Set Descriptor %x", error);
goto out;
}
goto out;
}
1, &dummy);
return (udf_vfsp);
out:
return (NULL);
}
/*
* ud_validate_and_fill_superblock() and fields may later point to
* valid data
*/
static void
{
uint32_t n;
}
}
}
}
}
for (n = 0; n < MAX_SPM; n++) {
}
}
}
}
void
{
int32_t i;
ud_printf("ud_destroy_fsp\n");
return;
}
}
}
}
}
}
void
struct log_vol_int_desc *lvid)
{
int32_t i, c;
for (i = 0; i < c; i++) {
continue;
}
ud_part++;
}
}
void
{
ud_printf("ud_update_superblock\n");
}
/*
* This part of the code is known
* to work with only sparc. It needs
* to be evluated before using it with x86
*/
{
return (error);
}
return (EINVAL);
}
return (error);
}
return (EINVAL);
}
return (0);
}
/* Search sequentially N - 2, N, N - 152, N - 150 for vat icb */
/*
* int32_t ud_sub_blks[] = {2, 0, 152, 150};
*/
/*
* Validate the VAT ICB
*/
static int32_t
{
struct file_entry *fe;
int err = 0;
for (i = 0; i < ud_sub_count; i++) {
0, 0) == 0) {
break;
}
}
}
}
if (i == ud_sub_count) {
return (EINVAL);
}
if (ad_type == ICB_FLAG_ONE_AD) {
} else if (ad_type == ICB_FLAG_SHORT_AD) {
} else if (ad_type == ICB_FLAG_LONG_AD) {
} else {
goto end;
}
KM_SLEEP);
KM_SLEEP);
KM_SLEEP);
if (ad_type == ICB_FLAG_ONE_AD) {
sizeof (uint32_t);
return (0);
}
if (ad_type == ICB_FLAG_SHORT_AD) {
sad += i;
} else {
lad += i;
}
if ((count & 0x3FFFFFFF) == 0) {
break;
}
} else {
}
break;
}
}
break;
}
break;
}
}
end:
if (err)
return (err);
}
{
if (sz == 0) {
return (0);
}
continue;
}
printf("Sparing Identifier does not match\n");
continue;
}
#ifdef UNDEF
{
struct stbl_entry *te;
for (i = 0; i < tbl_len; i++) {
te ++;
}
}
#endif
valid ++;
}
if (valid) {
return (0);
}
return (EINVAL);
}
{
struct anch_vol_desc_ptr *avdp;
uint32_t session_offset = 0;
end_index = 1;
} else {
end_index = 3;
}
session_offset = 0;
}
if (index == 0) {
avd_loc = 256;
if (bsize <= 2048) {
avd_loc +=
} else {
avd_loc +=
}
} else if (index == 1) {
} else {
}
continue;
}
/*
* Verify if we have avdp here
*/
1, ANCHOR_VOL_DESC_LEN) != 0) {
continue;
}
return (bsize);
}
}
/*
* Did not find AVD at all the locations
*/
return (0);
}
static int
{
static const fs_operation_def_t udf_vfsops_template[] = {
};
extern struct vnodeops *udf_vnodeops;
extern const fs_operation_def_t udf_vnodeops_template[];
int error;
ud_printf("udfinit\n");
if (error != 0) {
return (error);
}
if (error != 0) {
(void) vfs_freevfsops_by_type(fstype);
return (error);
}
udf_fstype = fstype;
return (0);
}