Implement read-only access to UDF 2.50 and UDF 2.60 discs that use metadata

partition mappings. This brings the NetBSD implementation to read all discs
upto date and will read all discs currently defined by OSTA.
This commit is contained in:
reinoud 2007-01-04 02:02:40 +00:00
parent 172a4c32bd
commit e54e795b0d
3 changed files with 176 additions and 37 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: udf.h,v 1.8 2006/09/29 01:36:28 reinoud Exp $ */
/* $NetBSD: udf.h,v 1.9 2007/01/04 02:02:40 reinoud Exp $ */
/*
* Copyright (c) 2006 Reinoud Zandijk
@ -173,10 +173,9 @@ struct udf_mount {
struct udf_sparing_table*sparing_table;
/* meta */
struct udf_node *metafile;
struct udf_node *metabitmapfile;
struct udf_node *metacopyfile;
struct udf_node *metabitmapcopyfile;
struct udf_node *metadata_file;
struct udf_node *metadatamirror_file;
struct udf_node *metadatabitmap_file;
/* disc allocation */
int data_alloc, meta_alloc; /* allocation scheme */

View File

@ -1,4 +1,4 @@
/* $NetBSD: udf_subr.c,v 1.25 2006/12/25 18:39:48 wiz Exp $ */
/* $NetBSD: udf_subr.c,v 1.26 2007/01/04 02:02:40 reinoud Exp $ */
/*
* Copyright (c) 2006 Reinoud Zandijk
@ -36,7 +36,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: udf_subr.c,v 1.25 2006/12/25 18:39:48 wiz Exp $");
__RCSID("$NetBSD: udf_subr.c,v 1.26 2007/01/04 02:02:40 reinoud Exp $");
#endif /* not lint */
@ -1298,7 +1298,7 @@ static int
udf_read_sparables(struct udf_mount *ump, union udf_pmap *mapping)
{
union dscrptr *dscr;
struct part_map_spare *pms = (struct part_map_spare *) mapping;
struct part_map_spare *pms = &mapping->pms;
uint32_t lb_num;
int spar, error;
@ -1338,6 +1338,76 @@ udf_read_sparables(struct udf_mount *ump, union udf_pmap *mapping)
/* --------------------------------------------------------------------- */
#define UDF_SET_SYSTEMFILE(vp) \
simple_lock(&(vp)->v_interlock); \
(vp)->v_flag |= VSYSTEM; \
simple_unlock(&(vp)->v_interlock);\
vref(vp); \
vput(vp); \
static int
udf_read_metadata_files(struct udf_mount *ump, union udf_pmap *mapping)
{
struct part_map_meta *pmm = &mapping->pmm;
struct long_ad icb_loc;
struct vnode *vp;
int error;
DPRINTF(VOLUMES, ("Reading in Metadata files\n"));
icb_loc.loc.part_num = pmm->part_num;
icb_loc.loc.lb_num = pmm->meta_file_lbn;
DPRINTF(VOLUMES, ("Metadata file\n"));
error = udf_get_node(ump, &icb_loc, &ump->metadata_file);
if (ump->metadata_file) {
vp = ump->metadata_file->vnode;
UDF_SET_SYSTEMFILE(vp);
}
icb_loc.loc.lb_num = pmm->meta_mirror_file_lbn;
if (icb_loc.loc.lb_num != -1) {
DPRINTF(VOLUMES, ("Metadata copy file\n"));
error = udf_get_node(ump, &icb_loc, &ump->metadatamirror_file);
if (ump->metadatamirror_file) {
vp = ump->metadatamirror_file->vnode;
UDF_SET_SYSTEMFILE(vp);
}
}
icb_loc.loc.lb_num = pmm->meta_bitmap_file_lbn;
if (icb_loc.loc.lb_num != -1) {
DPRINTF(VOLUMES, ("Metadata bitmap file\n"));
error = udf_get_node(ump, &icb_loc, &ump->metadatabitmap_file);
if (ump->metadatabitmap_file) {
vp = ump->metadatabitmap_file->vnode;
UDF_SET_SYSTEMFILE(vp);
}
}
/* if we're mounting read-only we relax the requirements */
if (ump->vfs_mountp->mnt_flag & MNT_RDONLY) {
error = EFAULT;
if (ump->metadata_file)
error = 0;
if ((ump->metadata_file == NULL) && (ump->metadatamirror_file)) {
printf( "udf mount: Metadata file not readable, "
"substituting Metadata copy file\n");
ump->metadata_file = ump->metadatamirror_file;
ump->metadatamirror_file = NULL;
error = 0;
}
} else {
/* mounting read/write */
DPRINTF(VOLUMES, ("udf mount: read only file system\n"));
error = EROFS;
}
DPRINTFIF(VOLUMES, error, ("udf mount: failed to read "
"metadata files\n"));
return error;
}
#undef UDF_SET_SYSTEMFILE
/* --------------------------------------------------------------------- */
int
udf_read_vds_tables(struct udf_mount *ump, struct udf_args *args)
{
@ -1372,8 +1442,11 @@ udf_read_vds_tables(struct udf_mount *ump, struct udf_args *args)
return ENOENT;
break;
case UDF_VTOP_TYPE_META :
/* TODO load metafile and metabitmapfile FE/EFEs */
return ENOENT;
/* load the associated file descriptors */
error = udf_read_metadata_files(ump, mapping);
if (error)
return ENOENT;
break;
default:
break;
}
@ -1514,9 +1587,16 @@ udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
{
struct part_desc *pdesc;
struct spare_map_entry *sme;
struct file_entry *fe;
struct extfile_entry *efe;
struct short_ad *s_ad;
struct long_ad *l_ad;
uint64_t cur_offset;
uint32_t *trans;
uint32_t lb_num, lb_rel, lb_packet;
int rel, vpart, part;
uint32_t lb_num, plb_num, lb_rel, lb_packet;
uint32_t sector_size, len, alloclen;
uint8_t *pos;
int rel, vpart, part, addr_type, icblen, icbflags, flags;
assert(ump && icb_loc && lb_numres);
@ -1525,6 +1605,9 @@ udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
if (vpart < 0 || vpart > UDF_VTOP_RAWPART)
return EINVAL;
part = ump->vtop[vpart];
pdesc = ump->partitions[part];
switch (ump->vtop_tp[vpart]) {
case UDF_VTOP_TYPE_RAW :
/* 1:1 to the end of the device */
@ -1533,8 +1616,6 @@ udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
return 0;
case UDF_VTOP_TYPE_PHYS :
/* transform into its disc logical block */
part = ump->vtop[vpart];
pdesc = ump->partitions[part];
if (lb_num > udf_rw32(pdesc->part_len))
return EINVAL;
*lb_numres = lb_num + udf_rw32(pdesc->start_loc);
@ -1552,8 +1633,6 @@ udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
lb_num = udf_rw32(trans[lb_num]);
/* transform into its disc logical block */
part = ump->vtop[vpart];
pdesc = ump->partitions[part];
if (lb_num > udf_rw32(pdesc->part_len))
return EINVAL;
*lb_numres = lb_num + udf_rw32(pdesc->start_loc);
@ -1577,8 +1656,6 @@ udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
}
/* transform into its disc logical block */
part = ump->vtop[vpart];
pdesc = ump->partitions[part];
if (lb_num > udf_rw32(pdesc->part_len))
return EINVAL;
*lb_numres = lb_num + udf_rw32(pdesc->start_loc);
@ -1587,6 +1664,61 @@ udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc,
*extres = ump->sparable_packet_len - lb_rel;
return 0;
case UDF_VTOP_TYPE_META :
/* we have to look into the file's allocation descriptors */
/* free after udf_translate_file_extent() */
/* XXX sector size or lb_size? */
sector_size = ump->discinfo.sector_size;
/* XXX should we claim exclusive access to the metafile ? */
fe = ump->metadata_file->fe;
efe = ump->metadata_file->efe;
if (fe) {
alloclen = udf_rw32(fe->l_ad);
pos = &fe->data[0] + udf_rw32(fe->l_ea);
icbflags = udf_rw16(fe->icbtag.flags);
}
if (efe) {
alloclen = udf_rw32(efe->l_ad);
pos = &efe->data[0] + udf_rw32(efe->l_ea);
icbflags = udf_rw16(efe->icbtag.flags);
}
addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK;
cur_offset = 0;
while (alloclen) {
if (addr_type == UDF_ICB_SHORT_ALLOC) {
icblen = sizeof(struct short_ad);
s_ad = (struct short_ad *) pos;
len = udf_rw32(s_ad->len);
plb_num = udf_rw32(s_ad->lb_num);
} else {
/* should not be present, but why not */
icblen = sizeof(struct long_ad);
l_ad = (struct long_ad *) pos;
len = udf_rw32(l_ad->len);
plb_num = udf_rw32(l_ad->loc.lb_num);
/* pvpart_num = udf_rw16(l_ad->loc.part_num); */
}
/* process extent */
flags = UDF_EXT_FLAGS(len);
len = UDF_EXT_LEN(len);
if (cur_offset + len > lb_num * sector_size) {
if (flags != UDF_EXT_ALLOCATED)
return EINVAL;
lb_rel = lb_num - cur_offset / sector_size;
/* remainder of this extent */
*lb_numres = plb_num + lb_rel +
udf_rw32(pdesc->start_loc);
*extres = (len / sector_size) - lb_rel;
return 0;
}
cur_offset += len;
pos += icblen;
alloclen -= icblen;
}
/* not found */
DPRINTF(TRANSLATE, ("Metadata partition translation failed\n"));
return EINVAL;
default:
printf("UDF vtop translation scheme %d unimplemented yet\n",
ump->vtop_tp[vpart]);

View File

@ -1,4 +1,4 @@
/* $NetBSD: udf_vfsops.c,v 1.18 2006/11/16 01:33:37 christos Exp $ */
/* $NetBSD: udf_vfsops.c,v 1.19 2007/01/04 02:02:40 reinoud Exp $ */
/*
* Copyright (c) 2006 Reinoud Zandijk
@ -36,7 +36,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: udf_vfsops.c,v 1.18 2006/11/16 01:33:37 christos Exp $");
__RCSID("$NetBSD: udf_vfsops.c,v 1.19 2007/01/04 02:02:40 reinoud Exp $");
#endif /* not lint */
@ -217,6 +217,17 @@ free_udf_mountinfo(struct mount *mp)
ump = VFSTOUDF(mp);
if (ump) {
/* dereference all system nodes */
if (ump->metadata_file)
vrele(ump->metadata_file->vnode);
if (ump->metadatamirror_file)
vrele(ump->metadatamirror_file->vnode);
if (ump->metadatabitmap_file)
vrele(ump->metadatabitmap_file->vnode);
/* vflush all (system) nodes if any */
(void) vflush(mp, NULLVP, FORCECLOSE);
/* dispose of our descriptor pool */
if (ump->desc_pool) {
pool_destroy(ump->desc_pool);
@ -402,26 +413,23 @@ udf_unmount(struct mount *mp, int mntflags, struct lwp *l)
DPRINTF(CALL, ("udf_umount called\n"));
/*
* By specifying SKIPSYSTEM we can skip vnodes marked with VSYSTEM.
* This hardly documented feature allows us to exempt certain files
* from being flushed.
*/
flags = SKIPSYSTEM; /* allow for system vnodes to stay alive */
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
ump = VFSTOUDF(mp);
if (!ump)
panic("UDF unmount: empty ump\n");
flags = (mntflags & MNT_FORCE) ? FORCECLOSE : 0;
/* TODO remove these paranoid functions */
#ifdef DEBUG
if (udf_verbose & UDF_DEBUG_LOCKING)
udf_unmount_sanity_check(mp);
#endif
if ((error = vflush(mp, NULLVP, flags)) != 0)
/*
* By specifying SKIPSYSTEM we can skip vnodes marked with VSYSTEM.
* This hardly documented feature allows us to exempt certain files
* from being flushed.
*/
if ((error = vflush(mp, NULLVP, flags | VSYSTEM)) != 0)
return error;
#ifdef DEBUG
@ -433,9 +441,6 @@ udf_unmount(struct mount *mp, int mntflags, struct lwp *l)
/*
* TODO close logical volume and close session if requested.
*
* XXX no system nodes defined yet. Code to reclaim them is calling
* VOP_RECLAIM on the nodes themselves.
*/
/* close device */
@ -539,7 +544,8 @@ udf_mountfs(struct vnode *devvp, struct mount *mp,
/* check consistency and completeness */
if ((error = udf_process_vds(ump, args))) {
printf("UDF mount: disc not properly formatted\n");
printf( "UDF mount: disc not properly formatted"
"(bad VDS)\n");
return error;
}
@ -555,13 +561,15 @@ udf_mountfs(struct vnode *devvp, struct mount *mp,
/* read vds support tables like VAT, sparable etc. */
if ((error = udf_read_vds_tables(ump, args))) {
printf("UDF mount: error in format or damaged disc\n");
printf( "UDF mount: error in format or damaged disc "
"(VDS tables failing)\n");
return error;
}
if ((error = udf_read_rootdirs(ump, args))) {
printf("UDF mount: "
"disc not properly formatted or damaged disc\n");
printf( "UDF mount: "
"disc not properly formatted or damaged disc "
"(rootdirs failing)\n");
return error;
}