From e54e795b0d00ae507fe6bfc65226987d50cdf057 Mon Sep 17 00:00:00 2001 From: reinoud Date: Thu, 4 Jan 2007 02:02:40 +0000 Subject: [PATCH] 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. --- sys/fs/udf/udf.h | 9 +-- sys/fs/udf/udf_subr.c | 158 ++++++++++++++++++++++++++++++++++++---- sys/fs/udf/udf_vfsops.c | 46 +++++++----- 3 files changed, 176 insertions(+), 37 deletions(-) diff --git a/sys/fs/udf/udf.h b/sys/fs/udf/udf.h index e511a7e5a932..b2e084c28fea 100644 --- a/sys/fs/udf/udf.h +++ b/sys/fs/udf/udf.h @@ -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 */ diff --git a/sys/fs/udf/udf_subr.c b/sys/fs/udf/udf_subr.c index 709cac3d6276..85fa6769c6ee 100644 --- a/sys/fs/udf/udf_subr.c +++ b/sys/fs/udf/udf_subr.c @@ -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 #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]); diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c index ddd5c85cfea4..95bf452570f8 100644 --- a/sys/fs/udf/udf_vfsops.c +++ b/sys/fs/udf/udf_vfsops.c @@ -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 #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; }