Mercurial > illumos > illumos-gate
changeset 4866:34d9e5474e96
4294956 hsfs creates wrong inode numbers for hard links
6489267 off by one last_offset computation in hsfs_readdir leads to panic
6490818 Memory leak in hs_mountfs()
author | frankho |
---|---|
date | Wed, 15 Aug 2007 05:40:25 -0700 |
parents | f99b3b9b2940 |
children | dd3be85f40a2 |
files | usr/src/uts/common/fs/hsfs/hsfs_node.c usr/src/uts/common/fs/hsfs/hsfs_rrip.c usr/src/uts/common/fs/hsfs/hsfs_subr.c usr/src/uts/common/fs/hsfs/hsfs_susp_subr.c usr/src/uts/common/fs/hsfs/hsfs_vfsops.c usr/src/uts/common/fs/hsfs/hsfs_vnops.c usr/src/uts/common/sys/fs/hsfs_impl.h usr/src/uts/common/sys/fs/hsfs_node.h usr/src/uts/common/sys/fs/hsfs_rrip.h usr/src/uts/common/sys/fs/hsfs_susp.h |
diffstat | 10 files changed, 362 insertions(+), 207 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/fs/hsfs/hsfs_node.c Tue Aug 14 19:57:00 2007 -0700 +++ b/usr/src/uts/common/fs/hsfs/hsfs_node.c Wed Aug 15 05:40:25 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -103,6 +103,12 @@ */ static int strict_iso9660_ordering = 0; +/* + * This tunable allows us to ignore inode numbers from rrip-1.12. + * In this case, we fall back to our default inode algorithm. + */ +int use_rrip_inodes = 1; + static void hs_hsnode_cache_reclaim(void *unused); static void hs_addfreeb(struct hsfs *fsp, struct hsnode *hp); static enum dirblock_result process_dirblock(struct fbuf *fbp, uint_t *offset, @@ -306,7 +312,7 @@ mutex_exit(&fsp->hsfs_free_lock); for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL; - tp = &(*tp)->hs_hash) { + tp = &(*tp)->hs_hash) { if (*tp == hp) { struct vnode *vp; @@ -320,14 +326,15 @@ * pvn_vplist_dirty will abort all old pages */ (void) pvn_vplist_dirty(vp, (u_offset_t)0, - hsfs_putapage, B_INVAL, (struct cred *)NULL); + hsfs_putapage, B_INVAL, + (struct cred *)NULL); *tp = hp->hs_hash; break; } } if (hp->hs_dirent.sym_link != (char *)NULL) { kmem_free(hp->hs_dirent.sym_link, - (size_t)(hp->hs_dirent.ext_size + 1)); + (size_t)(hp->hs_dirent.ext_size + 1)); } mutex_destroy(&hp->hs_contents_lock); @@ -362,12 +369,19 @@ /* * Look for hsnode in hash list. - * Check equality of fsid and nodeid. + * If the inode number is != HS_DUMMY_INO (16), then only the inode + * number is used for the check. + * If the inode number is == HS_DUMMY_INO, we additionally always + * check the directory offset for the file to avoid caching the + * meta data for all zero sized to the first zero sized file that + * was touched. + * * If found, reactivate it if inactive. + * * Must be entered with hsfs_hash_lock held. */ struct vnode * -hs_findhash(ino64_t nodeid, struct vfs *vfsp) +hs_findhash(ino64_t nodeid, uint_t lbn, uint_t off, struct vfs *vfsp) { struct hsnode *tp; struct hsfs *fsp; @@ -381,6 +395,21 @@ if (tp->hs_nodeid == nodeid) { struct vnode *vp; + if (nodeid == HS_DUMMY_INO) { + /* + * If this is the dummy inode number, look for + * matching dir_lbn and dir_off. + */ + for (; tp != NULL; tp = tp->hs_hash) { + if (tp->hs_nodeid == nodeid && + tp->hs_dir_lbn == lbn && + tp->hs_dir_off == off) + break; + } + if (tp == NULL) + return (NULL); + } + mutex_enter(&tp->hs_contents_lock); vp = HTOV(tp); VN_HOLD(vp); @@ -432,13 +461,14 @@ for (hp = fsp->hsfs_hash[i]; hp != NULL; hp = hp->hs_hash) { vp = HTOV(hp); if ((hp->hs_flags & HREF) && (vp != rvp || - (vp == rvp && vp->v_count > 1))) { + (vp == rvp && vp->v_count > 1))) { busy = 1; continue; } if (vn_has_cached_data(vp)) (void) pvn_vplist_dirty(vp, (u_offset_t)0, - hsfs_putapage, B_INVAL, (struct cred *)NULL); + hsfs_putapage, B_INVAL, + (struct cred *)NULL); } } if (busy) { @@ -498,14 +528,15 @@ fsp = VFS_TO_HSFS(vfsp); /* - * Construct the nodeid: in the case of a directory + * Construct the data that allows us to re-read the meta data without + * knowing the name of the file: in the case of a directory * entry, this should point to the canonical dirent, the "." * directory entry for the directory. This dirent is pointed * to by all directory entries for that dir (including the ".") * entry itself. * In the case of a file, simply point to the dirent for that - * file (there are no hard links in Rock Ridge, so there's no - * need to determine what the canonical dirent is. + * file (there are hard links in Rock Ridge, so we need to use + * different data to contruct the node id). */ if (dp->type == VDIR) { lbn = dp->ext_lbn; @@ -519,13 +550,30 @@ hvp = &fsp->hsfs_vol; lbn += off >> hvp->lbn_shift; off &= hvp->lbn_maxoffset; - nodeid = (ino64_t)MAKE_NODEID(lbn, off, vfsp); + /* + * If the media carries rrip-v1.12 or newer, and we trust the inodes + * from the rrip data (use_rrip_inodes != 0), use that data. If the + * media has been created by a recent mkisofs version, we may trust + * all numbers in the starting extent number; otherwise, we cannot + * do this for zero sized files and symlinks, because if we did we'd + * end up mapping all of them to the same node. + * We use HS_DUMMY_INO in this case and make sure that we will not + * map all files to the same meta data. + */ + if (dp->inode != 0 && use_rrip_inodes) { + nodeid = dp->inode; + } else if ((dp->ext_size == 0 || dp->sym_link != (char *)NULL) && + (fsp->hsfs_flags & HSFSMNT_INODE) == 0) { + nodeid = HS_DUMMY_INO; + } else { + nodeid = dp->ext_lbn; + } /* look for hsnode in cache first */ rw_enter(&fsp->hsfs_hash_lock, RW_READER); - if ((vp = hs_findhash(nodeid, vfsp)) == NULL) { + if ((vp = hs_findhash(nodeid, lbn, off, vfsp)) == NULL) { /* * Not in cache. However, someone else may have come @@ -535,7 +583,7 @@ rw_exit(&fsp->hsfs_hash_lock); rw_enter(&fsp->hsfs_hash_lock, RW_WRITER); - if ((vp = hs_findhash(nodeid, vfsp)) == NULL) { + if ((vp = hs_findhash(nodeid, lbn, off, vfsp)) == NULL) { /* * Now we are really sure that the hsnode is not * in the cache. Get one off freelist or else @@ -544,7 +592,7 @@ hp = hs_getfree(fsp); bcopy((caddr_t)dp, (caddr_t)&hp->hs_dirent, - sizeof (*dp)); + sizeof (*dp)); /* * We've just copied this pointer into hs_dirent, * and don't want 2 references to same symlink. @@ -578,10 +626,10 @@ if (IS_DEVVP(vp)) { rw_exit(&fsp->hsfs_hash_lock); newvp = specvp(vp, vp->v_rdev, vp->v_type, - CRED()); + CRED()); if (newvp == NULL) - cmn_err(CE_NOTE, - "hs_makenode: specvp failed"); + cmn_err(CE_NOTE, + "hs_makenode: specvp failed"); VN_RELE(vp); return (newvp); } @@ -624,7 +672,7 @@ if (nopage || (fsp->hsfs_nohsnode >= nhsnode)) { /* remove this node from the hash list, if it's there */ for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL; - tp = &(*tp)->hs_hash) { + tp = &(*tp)->hs_hash) { if (*tp == hp) { *tp = hp->hs_hash; @@ -634,7 +682,7 @@ if (hp->hs_dirent.sym_link != (char *)NULL) { kmem_free(hp->hs_dirent.sym_link, - (size_t)(hp->hs_dirent.ext_size + 1)); + (size_t)(hp->hs_dirent.ext_size + 1)); hp->hs_dirent.sym_link = NULL; } if (vn_has_cached_data(vp)) { @@ -691,7 +739,7 @@ dirp = (uchar_t *)secbp->b_un.b_addr; error = hs_parsedir(fsp, &dirp[off], &hd, (char *)NULL, (int *)NULL, - HS_SECTOR_SIZE - off); + HS_SECTOR_SIZE - off); if (!error) { *vpp = hs_makenode(&hd, lbn, off, vfsp); if (*vpp == NULL) @@ -722,7 +770,7 @@ struct hsfs *fsp; int error = 0; uint_t offset; /* real offset in directory */ - uint_t last_offset; /* last index into current dir block */ + uint_t last_offset; /* last index in directory */ char *cmpname; /* case-folded name */ int cmpname_size; /* how much memory we allocate for it */ int cmpnamelen; @@ -774,8 +822,8 @@ * remove it from the specified name */ if ((fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && - name[namlen-1] == '.' && - CAN_TRUNCATE_DOT(name, namlen)) + name[namlen-1] == '.' && + CAN_TRUNCATE_DOT(name, namlen)) name[--namlen] = '\0'; if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2 || fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { @@ -806,7 +854,7 @@ bytes_wanted = MIN(MAXBSIZE, dirsiz - (offset & MAXBMASK)); error = fbread(dvp, (offset_t)(offset & MAXBMASK), - (unsigned int)bytes_wanted, S_READ, &fbp); + (unsigned int)bytes_wanted, S_READ, &fbp); if (error) goto done; @@ -880,7 +928,7 @@ struct hs_direntry *hdp, char *dnp, int *dnlen, - int last_offset) + int last_offset) /* last offset in dirp */ { char *on_disk_name; int on_disk_namelen; @@ -924,8 +972,8 @@ hdp->gid = fsp -> hsfs_vol.vol_gid; hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777); } else if ((fsp->hsfs_vol_type == HS_VOL_TYPE_ISO) || - (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) || - (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET)) { + (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) || + (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET)) { flags = IDE_FLAGS(dirp); hs_parse_dirdate(IDE_cdate(dirp), &hdp->cdate); @@ -953,6 +1001,7 @@ hdp->uid = fsp -> hsfs_vol.vol_uid; hdp->gid = fsp -> hsfs_vol.vol_gid; hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777); + hdp->inode = 0; /* initialize with 0, then check rrip */ /* * Having this all filled in, let's see if we have any @@ -960,12 +1009,13 @@ */ if (IS_SUSP_IMPLEMENTED(fsp)) { error = parse_sua((uchar_t *)dnp, dnlen, - &name_change_flag, dirp, hdp, fsp, - (uchar_t *)NULL, NULL); + &name_change_flag, dirp, last_offset, + hdp, fsp, + (uchar_t *)NULL, NULL); if (error) { if (hdp->sym_link) { kmem_free(hdp->sym_link, - (size_t)(hdp->ext_size + 1)); + (size_t)(hdp->ext_size + 1)); hdp->sym_link = (char *)NULL; } return (error); @@ -986,7 +1036,7 @@ if (hdp->intlf_sz + hdp->intlf_sk) { if ((hdp->intlf_sz == 0) || (hdp->intlf_sk == 0)) { cmn_err(CE_NOTE, - "hsfs: interleaf size or skip factor error"); + "hsfs: interleaf size or skip factor error"); return (EINVAL); } if (hdp->ext_size == 0) { @@ -1024,19 +1074,18 @@ if (on_disk_dirlen < HDE_ROOT_DIR_REC_SIZE || ((on_disk_dirlen > last_offset) || ((HDE_FDESIZE + on_disk_namelen) > on_disk_dirlen))) { - hs_log_bogus_disk_warning(fsp, - HSFS_ERR_BAD_DIR_ENTRY, 0); + hs_log_bogus_disk_warning(fsp, + HSFS_ERR_BAD_DIR_ENTRY, 0); return (EINVAL); } if (on_disk_namelen > fsp->hsfs_namelen && hs_namelen(fsp, on_disk_name, on_disk_namelen) > - fsp->hsfs_namelen) { + fsp->hsfs_namelen) { hs_log_bogus_disk_warning(fsp, - fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ? - HSFS_ERR_BAD_JOLIET_FILE_LEN : - HSFS_ERR_BAD_FILE_LEN, - 0); + fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ? + HSFS_ERR_BAD_JOLIET_FILE_LEN : + HSFS_ERR_BAD_FILE_LEN, 0); } if (on_disk_namelen > ISO_NAMELEN_V2_MAX) on_disk_namelen = fsp->hsfs_namemax; /* Paranoia */ @@ -1044,9 +1093,8 @@ if (dnp != NULL) { if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { namelen = hs_jnamecopy(on_disk_name, dnp, - on_disk_namelen, - fsp->hsfs_namemax, - fsp->hsfs_flags); + on_disk_namelen, fsp->hsfs_namemax, + fsp->hsfs_flags); /* * A negative return value means that the file name * has been truncated to fsp->hsfs_namemax. @@ -1054,16 +1102,14 @@ if (namelen < 0) { namelen = -namelen; hs_log_bogus_disk_warning(fsp, - HSFS_ERR_TRUNC_JOLIET_FILE_LEN, - 0); + HSFS_ERR_TRUNC_JOLIET_FILE_LEN, 0); } } else { /* * HS_VOL_TYPE_ISO && HS_VOL_TYPE_ISO_V2 */ namelen = hs_namecopy(on_disk_name, dnp, - on_disk_namelen, - fsp->hsfs_flags); + on_disk_namelen, fsp->hsfs_flags); } if (namelen == 0) return (EINVAL); @@ -1273,7 +1319,7 @@ return; warned = 1; cmn_err(CE_CONT, "hsfs: Warning: " - "file name contains bad UCS-2 chacarter\n"); + "file name contains bad UCS-2 chacarter\n"); } @@ -1361,14 +1407,14 @@ if (vp->v_type != VDIR) { cmn_err(CE_WARN, "hsfs_filldirent: vp (0x%p) not a directory", - (void *)vp); + (void *)vp); return; } fsp = VFS_TO_HSFS(vp ->v_vfsp); secno = LBN_TO_SEC(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp); secoff = LBN_TO_BYTE(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp) & - MAXHSOFFSET; + MAXHSOFFSET; secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE); error = geterror(secbp); if (error != 0) { @@ -1384,7 +1430,7 @@ /* keep on going */ } (void) hs_parsedir(fsp, &secp[secoff], hdp, (char *)NULL, - (int *)NULL, HS_SECTOR_SIZE - secoff); + (int *)NULL, HS_SECTOR_SIZE - secoff); end: brelse(secbp); @@ -1412,7 +1458,7 @@ int dnamelen; /* length of name */ struct hs_direntry hd; int hdlen; - uchar_t *dirp; /* the directory entry */ + uchar_t *dirp; /* the directory entry */ int res; int parsedir_res; int is_rrip; @@ -1501,12 +1547,11 @@ HSFS_ERR_BAD_DIR_ENTRY, 0); goto skip_rec; } else if (dnamelen > fsp->hsfs_namelen && - hs_namelen(fsp, dname, dnamelen) > fsp->hsfs_namelen) { + hs_namelen(fsp, dname, dnamelen) > fsp->hsfs_namelen) { hs_log_bogus_disk_warning(fsp, - fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ? - HSFS_ERR_BAD_JOLIET_FILE_LEN : - HSFS_ERR_BAD_FILE_LEN, - 0); + fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ? + HSFS_ERR_BAD_JOLIET_FILE_LEN : + HSFS_ERR_BAD_FILE_LEN, 0); } if (dnamelen > ISO_NAMELEN_V2_MAX) dnamelen = fsp->hsfs_namemax; /* Paranoia */ @@ -1521,7 +1566,8 @@ rrip_name_str[0] = '\0'; rr_namelen = rrip_namecopy(nm, &rrip_name_str[0], - &rrip_tmp_name[0], dirp, fsp, &hd); + &rrip_tmp_name[0], dirp, last_offset - *offset, + fsp, &hd); if (hd.sym_link) { kmem_free(hd.sym_link, (size_t)(hd.ext_size+1)); @@ -1566,7 +1612,7 @@ if (i > 0) { dnamelen = i; } else if (fsp->hsfs_vol_type != HS_VOL_TYPE_ISO_V2 && - fsp->hsfs_vol_type != HS_VOL_TYPE_JOLIET) { + fsp->hsfs_vol_type != HS_VOL_TYPE_JOLIET) { dnamelen = strip_trailing(fsp, dname, dnamelen); } @@ -1576,9 +1622,9 @@ (void) strncpy(uppercase_name, dname, dnamelen); } else if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { dnamelen = hs_joliet_cp(dname, uppercase_name, - dnamelen); + dnamelen); } else if (uppercase_cp(dname, uppercase_name, - dnamelen)) { + dnamelen)) { hs_log_bogus_disk_warning(fsp, HSFS_ERR_LOWER_CASE_NM, 0); } @@ -1609,7 +1655,7 @@ /* name matches */ parsedir_res = hs_parsedir(fsp, dirp, &hd, (char *)NULL, (int *)NULL, - last_offset - rel_offset(*offset)); + last_offset - *offset); if (!parsedir_res) { uint_t lbn; /* logical block number */ @@ -1641,7 +1687,7 @@ PD_return(FOUND_ENTRY) } } else if (strict_iso9660_ordering && !is_rrip && - !HSFS_HAVE_LOWER_CASE(fsp) && res < 0) { + !HSFS_HAVE_LOWER_CASE(fsp) && res < 0) { /* name < dir entry */ RESTORE_NM(rrip_tmp_name, nm); PD_return(WENT_PAST)
--- a/usr/src/uts/common/fs/hsfs/hsfs_rrip.c Tue Aug 14 19:57:00 2007 -0700 +++ b/usr/src/uts/common/fs/hsfs/hsfs_rrip.c Wed Aug 15 05:40:25 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -129,6 +129,11 @@ hdp->uid = RRIP_UID(px_ptr); hdp->gid = RRIP_GID(px_ptr); + if (SUF_LEN(px_ptr) >= RRIP_PX_SIZE) + hdp->inode = (ino64_t)RRIP_INO(px_ptr); + else + hdp->inode = 0; + hdp->type = IFTOVT(hdp->mode); return (px_ptr + SUF_LEN(px_ptr)); @@ -211,6 +216,9 @@ int dst_size) /* limit dest string to */ /* this value */ { + size_t off; + size_t len; + if (IS_NAME_BIT_SET(rrip_flags, RRIP_NAME_ROOT)) (void) strcpy((char *)dst, "/"); @@ -249,17 +257,21 @@ * Unfortunately, strlcat() cannot deal with input strings * that are not NULL-terminated - like SUA_string can be in * our case here. So we can't use it :( - * We therefore have to emulate its behaviour using strncat(), - * which will never access more bytes from the input string - * than specified. Since strncat() doesn't necessarily NULL- - * terminate the result, make sure we've got space for the - * Nullbyte at the end. + * Now strncat() doesn't work either - because it doesn't deal + * with strings for which the 'potential NULL-termination' isn't + * accessible - strncat(dst, NULL, 0) crashes although it copies + * nothing in any case. If the SUA ends on a mapping boundary, + * then telling strncat() to copy no more than the remaining bytes + * in the buffer is of no avail if there's no NULL byte in them. + * + * Hence - binary copy. What are all these str* funcs for ?? */ dst_size--; /* trailing '\0' */ - (void) strncat((char *)dst, (char *)SUA_string, - MIN(dst_size - strlen((char *)dst), SUA_string_len)); - dst[dst_size] = '\0'; + off = strlen((char *)dst); + len = MIN(dst_size - off, SUA_string_len); + bcopy((char *)SUA_string, (char *)(dst + off), len); + dst[off + len] = '\0'; *dst_lenp = strlen((char *)dst); if (IS_NAME_BIT_SET(rrip_flags, RRIP_NAME_CONTINUE)) @@ -357,8 +369,8 @@ /* for all components */ for (comp_ptr = RRIP_sl_comp(sl_ptr); - comp_ptr < (sl_ptr + SUF_LEN(sl_ptr)); - comp_ptr += RRIP_COMP_LEN(comp_ptr)) { + comp_ptr < (sl_ptr + SUF_LEN(sl_ptr)); + comp_ptr += RRIP_COMP_LEN(comp_ptr)) { name_parse((int)RRIP_COMP_FLAGS(comp_ptr), RRIP_comp(comp_ptr), @@ -372,7 +384,7 @@ * And avoid 2 '//' in a row, or if '/' was wanted */ if (IS_NAME_BIT_SET(RRIP_COMP_FLAGS(comp_ptr), - RRIP_NAME_CONTINUE) || + RRIP_NAME_CONTINUE) || (sym_link[sym_link_len - 1] == '/')) { sym_link[sym_link_len] = '\0'; @@ -433,6 +445,7 @@ char *to, /* string to copy "from" to */ char *tmp_name, /* temp storage for original name */ uchar_t *dirp, /* directory entry pointer */ + uint_t last_offset, /* last index into current dir block */ struct hsfs *fsp, /* filesystem pointer */ struct hs_direntry *hdp) /* directory entry pointer to put */ /* all that good info in */ @@ -460,7 +473,8 @@ } - ret_val = parse_sua((uchar_t *)to, &size, &change_flag, dirp, + ret_val = parse_sua((uchar_t *)to, &size, &change_flag, + dirp, last_offset, hdp, fsp, (uchar_t *)NULL, NULL); if (IS_NAME_BIT_SET(change_flag, RRIP_NAME_CHANGE) && !ret_val)
--- a/usr/src/uts/common/fs/hsfs/hsfs_subr.c Tue Aug 14 19:57:00 2007 -0700 +++ b/usr/src/uts/common/fs/hsfs/hsfs_subr.c Wed Aug 15 05:40:25 2007 -0700 @@ -21,7 +21,7 @@ /* * Miscellaneous support subroutines for High Sierra filesystem * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -115,6 +115,16 @@ "has inconsistent data:", "invalid directory or file name length (ignored)\n", 1, 0, + /* HSFS_ERR_NEG_SUA_LEN */ + "hsfs: Warning: file system mounted on %s " + "has inconsistent Rock Ridge data:", + "negative SUA len\n", + 1, 0, + /* HSFS_ERR_BAD_SUA_LEN */ + "hsfs: Warning: file system mounted on %s " + "has inconsistent Rock Ridge data:", + "SUA len too big\n", + 1, 0, };
--- a/usr/src/uts/common/fs/hsfs/hsfs_susp_subr.c Tue Aug 14 19:57:00 2007 -0700 +++ b/usr/src/uts/common/fs/hsfs/hsfs_susp_subr.c Wed Aug 15 05:40:25 2007 -0700 @@ -22,7 +22,7 @@ * System Use Sharing protocol subroutines for High Sierra filesystem */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -84,6 +84,7 @@ int *name_len_p, /* location to put name len */ int *name_change_p, /* flags to signal name chg */ uchar_t *dirp, /* pointer to ISO dir entry */ + uint_t last_offset, /* last ind. in cur. dirblock */ struct hs_direntry *hdp, /* loc to store dir info */ struct hsfs *fsp, /* filesystem pointer */ uchar_t *search_sig, /* signature to search for */ @@ -110,8 +111,15 @@ * between sizes of SUA and ISO directory entry. This entry * is corrupted, return an appropriate error. */ - if (SUA_len < 0) + if (SUA_len < 0) { + hs_log_bogus_disk_warning(fsp, HSFS_ERR_NEG_SUA_LEN, 0); return (SUA_EINVAL); + } + + if ((tmp_SUA_p + tmp_SUA_len) > (dirp + last_offset)) { + hs_log_bogus_disk_warning(fsp, HSFS_ERR_BAD_SUA_LEN, 0); + return (SUA_EINVAL); + } /* * Make sure that the continuation lenth is zero, as that is @@ -141,7 +149,7 @@ while (ret_val == -1) { switch (parse_signatures(&sig_args, tmp_SUA_len, search_sig, - search_num)) { + search_num)) { case END_OF_SUA : if (cont_info.cont_len) { @@ -150,8 +158,8 @@ goto clean_up; } - sig_args.SUF_ptr = cont_p + - cont_info.cont_offset; + sig_args.SUF_ptr = + cont_p + cont_info.cont_offset; tmp_SUA_len = cont_info.cont_len; cont_info.cont_len = 0; @@ -373,13 +381,13 @@ fsp = VFS_TO_HSFS(vp->v_vfsp); secno = LBN_TO_SEC(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp); secoff = LBN_TO_BYTE(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp) & - MAXHSOFFSET; + MAXHSOFFSET; secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE); error = geterror(secbp); if (error != 0) { cmn_err(CE_NOTE, - "hs_check_root_dirent: bread: error=(%d)", error); + "hs_check_root_dirent: bread: error=(%d)", error); goto end; } @@ -409,7 +417,7 @@ goto end; if (strncmp(SUSP_SP, (char *)IDE_sys_use_area(root_ptr), - SUF_SIG_LEN) == 0) { + SUF_SIG_LEN) == 0) { /* * We have a match of the sharing signature, so let's * call the sig_handler to do what is necessary. We can @@ -421,11 +429,24 @@ if ((susp_sp->sig_handler)(&sig_args) == (uchar_t *)NULL) { goto end; } - } else + } else { goto end; + } - (void) hs_parsedir(fsp, root_ptr, hdp, (char *)NULL, (int *)NULL, - HS_SECTOR_SIZE - secoff); + /* + * If the "ER" signature in the root directory is past any non SU + * signature, the Rock Ridge signatures will be ignored. This happens + * e.g. for filesystems created by mkisofs. In this case, + * IS_RRIP_IMPLEMENTED(fsp) will return 0 when the "ER" signature is + * parsed. Unfortunately, the results of this run will be cached for + * the root vnode. The solution is to run hs_parsedir() a second time + * for the root directory. + */ + if (hs_parsedir(fsp, root_ptr, hdp, (char *)NULL, (int *)NULL, + HS_SECTOR_SIZE - secoff) == 0) { + (void) hs_parsedir(fsp, root_ptr, hdp, (char *)NULL, + (int *)NULL, HS_SECTOR_SIZE - secoff); + } /* * If we did not get at least 1 extension, let's assume ISO and @@ -503,21 +524,21 @@ bzero((char *)*buf_pp, HS_SECTOR_SIZE); partial_size = HS_SECTOR_SIZE - cont_info_p->cont_offset; bcopy(&secbp->b_un.b_addr[cont_info_p->cont_offset], - (char *)*buf_pp, partial_size); + (char *)*buf_pp, partial_size); cont_info_p->cont_offset = 0; brelse(secbp); secbp = bread(fsp->hsfs_devvp->v_rdev, (secno + 1) * 4, - HS_SECTOR_SIZE); + HS_SECTOR_SIZE); error = geterror(secbp); if (error != 0) { cmn_err(CE_NOTE, "get_cont_area: bread(2): error=(%d)", - error); + error); brelse(secbp); return (1); } bcopy(secbp->b_un.b_addr, (char *)&(*buf_pp)[partial_size], - cont_info_p->cont_len - partial_size); + cont_info_p->cont_len - partial_size); } brelse(secbp);
--- a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c Tue Aug 14 19:57:00 2007 -0700 +++ b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c Wed Aug 15 05:40:25 2007 -0700 @@ -305,25 +305,25 @@ */ flags = 0; if (vfs_optionisset(vfsp, HOPT_NOMAPLCASE, NULL)) - flags |= HSFSMNT_NOMAPLCASE; + flags |= HSFSMNT_NOMAPLCASE; if (vfs_optionisset(vfsp, HOPT_NOTRAILDOT, NULL)) - flags |= HSFSMNT_NOTRAILDOT; + flags |= HSFSMNT_NOTRAILDOT; if (vfs_optionisset(vfsp, HOPT_NRR, NULL)) - flags |= HSFSMNT_NORRIP; + flags |= HSFSMNT_NORRIP; if (vfs_optionisset(vfsp, HOPT_NOJOLIET, NULL)) - flags |= HSFSMNT_NOJOLIET; + flags |= HSFSMNT_NOJOLIET; if (vfs_optionisset(vfsp, HOPT_JOLIETLONG, NULL)) - flags |= HSFSMNT_JOLIETLONG; + flags |= HSFSMNT_JOLIETLONG; if (vfs_optionisset(vfsp, HOPT_NOVERS2, NULL)) - flags |= HSFSMNT_NOVERS2; + flags |= HSFSMNT_NOVERS2; error = pn_get(uap->dir, (uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, &dpn); if (error) return (error); - if ((error = hs_getmdev(vfsp, uap->spec, uap->flags, &dev, - &mode, cr)) != 0) { + error = hs_getmdev(vfsp, uap->spec, uap->flags, &dev, &mode, cr); + if (error != 0) { pn_free(&dpn); return (error); } @@ -392,12 +392,11 @@ VN_RELE(fsp->hsfs_devvp); /* free path table space */ if (fsp->hsfs_ptbl != NULL) - kmem_free(fsp->hsfs_ptbl, - (size_t)fsp->hsfs_vol.ptbl_len); + kmem_free(fsp->hsfs_ptbl, (size_t)fsp->hsfs_vol.ptbl_len); /* free path table index table */ if (fsp->hsfs_ptbl_idx != NULL) kmem_free(fsp->hsfs_ptbl_idx, (size_t) - (fsp->hsfs_ptbl_idx_size * sizeof (struct ptable_idx))); + (fsp->hsfs_ptbl_idx_size * sizeof (struct ptable_idx))); /* free "mounted on" pathame */ if (fsp->hsfs_fsmnt != NULL) @@ -476,9 +475,10 @@ rw_enter(&fsp->hsfs_hash_lock, RW_READER); - nodeid = (ino64_t)MAKE_NODEID(fid->hf_dir_lbn, fid->hf_dir_off, vfsp); + nodeid = fid->hf_ino; - if ((*vpp = hs_findhash(nodeid, vfsp)) == NULL) { + if ((*vpp = hs_findhash(nodeid, fid->hf_dir_lbn, + (uint_t)fid->hf_dir_off, vfsp)) == NULL) { /* * Not in cache, so we need to remake it. * hs_remakenode() will read the directory entry @@ -883,7 +883,10 @@ break; } - fsp->hsfs_flags = mount_flags; + /* + * Add the HSFSMNT_INODE pseudo mount flag to the current mount flags. + */ + fsp->hsfs_flags = mount_flags | (fsp->hsfs_flags & HSFSMNT_INODE); DTRACE_PROBE1(mount__done, struct hsfs *, fsp); @@ -893,6 +896,9 @@ fsp->hsfs_magic = HSFS_MAGIC; mutex_exit(&hs_mounttab_lock); + kmem_free(svp, sizeof (*svp)); + kmem_free(jvp, sizeof (*jvp)); + return (0); cleanup: @@ -929,7 +935,7 @@ if (!hsfs_valid_dir(&fsp->hsfs_vol.root_dir)) { hs_log_bogus_disk_warning(fsp, HSFS_ERR_BAD_ROOT_DIR, 0); if (hs_remakenode(fsp->hsfs_vol.root_dir.ext_lbn, - (uint_t)0, vfsp, &fsp->hsfs_rootvp)) { + (uint_t)0, vfsp, &fsp->hsfs_rootvp)) { hs_mounttab = hs_mounttab->hsfs_next; mutex_destroy(&fsp->hsfs_free_lock); rw_destroy(&fsp->hsfs_hash_lock); @@ -939,7 +945,7 @@ } } else { fsp->hsfs_rootvp = hs_makenode(&fsp->hsfs_vol.root_dir, - fsp->hsfs_vol.root_dir.ext_lbn, 0, vfsp); + fsp->hsfs_vol.root_dir.ext_lbn, 0, vfsp); } /* XXX - ignore the path table for now */ @@ -963,6 +969,7 @@ { struct buf *secbp; int i; + int n; uchar_t *volp; int error; uint_t secno; @@ -979,7 +986,12 @@ volp = (uchar_t *)secbp->b_un.b_addr; - while (HSV_DESC_TYPE(volp) != VD_EOV) { + /* + * 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 && + HSV_DESC_TYPE(volp) != VD_EOV; n++) { for (i = 0; i < HSV_ID_STRLEN; i++) if (HSV_STD_ID(volp)[i] != HSV_ID_STRING[i]) goto cantfind; @@ -1008,7 +1020,7 @@ if (error != 0) { cmn_err(CE_NOTE, "hs_findhsvol: bread: error=(%d)", - error); + error); brelse(secbp); return (error); } @@ -1035,12 +1047,12 @@ hvp->lbn_size = HSV_BLK_SIZE(volp); if (hvp->lbn_size == 0) { cmn_err(CE_NOTE, "hs_parsehsvol: logical block size in the " - "SFSVD is zero"); + "SFSVD is zero"); return (EINVAL); } hvp->lbn_shift = ffs((long)hvp->lbn_size) - 1; - hvp->lbn_secshift = ffs((long)howmany(HS_SECTOR_SIZE, - (int)hvp->lbn_size)) - 1; + hvp->lbn_secshift = + ffs((long)howmany(HS_SECTOR_SIZE, (int)hvp->lbn_size)) - 1; hvp->lbn_maxoffset = hvp->lbn_size - 1; hs_parse_longdate(HSV_cre_date(volp), &hvp->cre_date); hs_parse_longdate(HSV_mod_date(volp), &hvp->mod_date); @@ -1060,12 +1072,12 @@ */ if (hvp->lbn_size & ~(1 << hvp->lbn_shift)) { cmn_err(CE_NOTE, - "hsfs: %d-byte logical block size not supported", - hvp->lbn_size); + "hsfs: %d-byte logical block size not supported", + hvp->lbn_size); return (EINVAL); } return (hs_parsedir(fsp, HSV_ROOT_DIR(volp), &hvp->root_dir, - (char *)NULL, (int *)NULL, HDE_ROOT_DIR_REC_SIZE)); + (char *)NULL, (int *)NULL, HDE_ROOT_DIR_REC_SIZE)); } /* @@ -1087,12 +1099,14 @@ { struct buf *secbp; int i; + int n; uchar_t *volp; int error; uint_t secno; int foundpvd = 0; int foundsvd = 0; int foundjvd = 0; + int pvd_sum = 0; secno = hs_findvoldesc(vp->v_rdev, ISO_VOLDESC_SEC); secbp = bread(vp->v_rdev, secno * 4, ISO_SECTOR_SIZE); @@ -1106,7 +1120,12 @@ volp = (uchar_t *)secbp->b_un.b_addr; - while ((enum iso_voldesc_type) ISO_DESC_TYPE(volp) != ISO_VD_EOV) { + /* + * 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 && + (enum iso_voldesc_type) ISO_DESC_TYPE(volp) != ISO_VD_EOV; n++) { for (i = 0; i < ISO_ID_STRLEN; i++) if (ISO_STD_ID(volp)[i] != ISO_ID_STRING[i]) goto cantfind; @@ -1122,6 +1141,8 @@ return (error); } foundpvd = 1; + for (i = 0; i < ISO_SECTOR_SIZE; i++) + pvd_sum += volp[i]; } break; case ISO_VD_SVD: @@ -1159,13 +1180,45 @@ if (error != 0) { cmn_err(CE_NOTE, "hs_findisovol: bread: error=(%d)", - error); + error); brelse(secbp); return (error); } volp = (uchar_t *)secbp->b_un.b_addr; } + for (n = 0; n < 16; n++) { + brelse(secbp); + ++secno; + secbp = bread(vp->v_rdev, secno * 4, HS_SECTOR_SIZE); + error = geterror(secbp); + + if (error != 0) { + cmn_err(CE_NOTE, "hs_findisovol: bread: error=(%d)", + error); + brelse(secbp); + 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. + */ + volp = (uchar_t *)secbp->b_un.b_addr; + if (strncmp((char *)volp, "MKI ", 4) == 0) { + int sum; + + sum = volp[2045]; + sum *= 256; + sum += volp[2046]; + sum *= 256; + sum += volp[2047]; + if (sum == pvd_sum) + fsp->hsfs_flags |= HSFSMNT_INODE; + break; + } + } if (foundpvd) { brelse(secbp); return (0); @@ -1212,12 +1265,12 @@ hvp->lbn_size = ISO_BLK_SIZE(volp); if (hvp->lbn_size == 0) { cmn_err(CE_NOTE, "hs_parseisovol: logical block size in the " - "PVD is zero"); + "PVD is zero"); return (EINVAL); } hvp->lbn_shift = ffs((long)hvp->lbn_size) - 1; - hvp->lbn_secshift = ffs((long)howmany(ISO_SECTOR_SIZE, - (int)hvp->lbn_size)) - 1; + hvp->lbn_secshift = + ffs((long)howmany(ISO_SECTOR_SIZE, (int)hvp->lbn_size)) - 1; hvp->lbn_maxoffset = hvp->lbn_size - 1; hs_parse_longdate(ISO_cre_date(volp), &hvp->cre_date); hs_parse_longdate(ISO_mod_date(volp), &hvp->mod_date); @@ -1237,12 +1290,12 @@ */ if (hvp->lbn_size & ~(1 << hvp->lbn_shift)) { cmn_err(CE_NOTE, - "hsfs: %d-byte logical block size not supported", - hvp->lbn_size); + "hsfs: %d-byte logical block size not supported", + hvp->lbn_size); return (EINVAL); } return (hs_parsedir(fsp, ISO_ROOT_DIR(volp), &hvp->root_dir, - (char *)NULL, (int *)NULL, IDE_ROOT_DIR_REC_SIZE)); + (char *)NULL, (int *)NULL, IDE_ROOT_DIR_REC_SIZE)); } /* @@ -1393,15 +1446,18 @@ fvolp = &fsp->hsfs_vol; #ifdef HSFS_CLKSET if (fvolp->cre_date.tv_sec == 0) { - cmn_err(CE_NOTE, "hsfs_mountroot: cre_date.tv_sec == 0"); - if (fvolp->mod_date.tv_sec == 0) { - cmn_err(CE_NOTE, "hsfs_mountroot: mod_date.tv_sec == 0"); - cmn_err(CE_NOTE, "hsfs_mountroot: clkset(-1L)"); - clkset(-1L); - } else + cmn_err(CE_NOTE, "hsfs_mountroot: cre_date.tv_sec == 0"); + if (fvolp->mod_date.tv_sec == 0) { + cmn_err(CE_NOTE, + "hsfs_mountroot: mod_date.tv_sec == 0"); + cmn_err(CE_NOTE, "hsfs_mountroot: clkset(-1L)"); + clkset(-1L); + } else { + clkset(fvolp->mod_date.tv_sec); + } + } else { clkset(fvolp->mod_date.tv_sec); - } else - clkset(fvolp->mod_date.tv_sec); + } #else /* HSFS_CLKSET */ clkset(-1L); #endif /* HSFS_CLKSET */
--- a/usr/src/uts/common/fs/hsfs/hsfs_vnops.c Tue Aug 14 19:57:00 2007 -0700 +++ b/usr/src/uts/common/fs/hsfs/hsfs_vnops.c Wed Aug 15 05:40:25 2007 -0700 @@ -83,6 +83,13 @@ #include <fs/fs_subr.h> +/* + * This tunable allows us to ignore inode numbers from rrip-1.12. + * In this case, we fall back to our default inode algorithm. + */ +extern int use_rrip_inodes; + + /* ARGSUSED */ static int hsfs_fsync(vnode_t *cp, int syncflag, cred_t *cred) @@ -376,7 +383,6 @@ size_t dname_size; struct fbuf *fbp; uint_t last_offset; /* last index into current dir block */ - ulong_t dir_lbn; /* lbn of directory */ ino64_t dirino; /* temporary storage before storing in dirent */ off_t diroff; @@ -385,7 +391,6 @@ if (dhp->hs_dirent.ext_size == 0) hs_filldirent(vp, &dhp->hs_dirent); dirsiz = dhp->hs_dirent.ext_size; - dir_lbn = dhp->hs_dirent.ext_lbn; if (uiop->uio_loffset >= dirsiz) { /* at or beyond EOF */ if (eofp) *eofp = 1; @@ -405,7 +410,7 @@ bytes_wanted = MIN(MAXBSIZE, dirsiz - (offset & MAXBMASK)); error = fbread(vp, (offset_t)(offset & MAXBMASK), - (unsigned int)bytes_wanted, S_READ, &fbp); + (unsigned int)bytes_wanted, S_READ, &fbp); if (error) goto done; @@ -425,7 +430,7 @@ * a single utility function. */ hdlen = (int)((uchar_t) - HDE_DIR_LEN(&blkp[rel_offset(offset)])); + HDE_DIR_LEN(&blkp[rel_offset(offset)])); if (hdlen < HDE_ROOT_DIR_REC_SIZE || offset + hdlen > last_offset) { /* @@ -446,8 +451,7 @@ * XXX - maybe hs_parsedir() will detect EXISTENCE bit */ if (!hs_parsedir(fsp, &blkp[rel_offset(offset)], - &hd, dname, &dnamelen, - last_offset - rel_offset(offset))) { + &hd, dname, &dnamelen, last_offset - offset)) { /* * Determine if there is enough room */ @@ -461,34 +465,28 @@ diroff = offset + hdlen; /* - * Generate nodeid. - * If a directory, nodeid points to the - * canonical dirent describing the directory: - * the dirent of the "." entry for the - * directory, which is pointed to by all - * dirents for that directory. - * Otherwise, nodeid points to dirent of file. + * If the media carries rrip-v1.12 or newer, + * and we trust the inodes from the rrip data + * (use_rrip_inodes != 0), use that data. If the + * media has been created by a recent mkisofs + * version, we may trust all numbers in the + * starting extent number; otherwise, we cannot + * do this for zero sized files and symlinks, + * because if we did we'd end up mapping all of + * them to the same node. We use HS_DUMMY_INO + * in this case and make sure that we will not + * map all files to the same meta data. */ - if (hd.type == VDIR) { - dirino = (ino64_t) - MAKE_NODEID(hd.ext_lbn, 0, - vp->v_vfsp); + if (hd.inode != 0 && use_rrip_inodes) { + dirino = hd.inode; + } else if ((hd.ext_size == 0 || + hd.sym_link != (char *)NULL) && + (fsp->hsfs_flags & HSFSMNT_INODE) == 0) { + dirino = HS_DUMMY_INO; } else { - struct hs_volume *hvp; - offset_t lbn, off; - - /* - * Normalize lbn and off - */ - hvp = &fsp->hsfs_vol; - lbn = dir_lbn + - (offset >> hvp->lbn_shift); - off = offset & hvp->lbn_maxoffset; - dirino = (ino64_t)MAKE_NODEID(lbn, - off, vp->v_vfsp); + dirino = hd.ext_lbn; } - /* strncpy(9f) will zero uninitialized bytes */ ASSERT(strlen(dname) + 1 <= @@ -557,6 +555,7 @@ mutex_enter(&hp->hs_contents_lock); fid->hf_dir_lbn = hp->hs_dir_lbn; fid->hf_dir_off = (ushort_t)hp->hs_dir_off; + fid->hf_ino = hp->hs_nodeid; mutex_exit(&hp->hs_contents_lock); return (0); } @@ -717,8 +716,8 @@ if (hp->hs_dirent.intlf_sz == 0) { chunk_data_bytes = LBN_TO_BYTE(1, vp->v_vfsp); } else { - chunk_data_bytes = LBN_TO_BYTE(hp->hs_dirent.intlf_sz, - vp->v_vfsp); + chunk_data_bytes = + LBN_TO_BYTE(hp->hs_dirent.intlf_sz, vp->v_vfsp); } reread: @@ -824,8 +823,7 @@ searchp = pp; io_end = io_off + io_len; for (count = 0, byte_offset = io_off; - byte_offset < io_end; - count++) { + byte_offset < io_end; count++) { ASSERT(count < bufcnt); /* Compute disk address for interleaving. */ @@ -843,14 +841,13 @@ offset_extra = byte_offset % chunk_data_bytes; /* get virtual block number for driver */ - driver_block = lbtodb(bof + xarsiz - + offset_bytes + offset_extra); + driver_block = + lbtodb(bof + xarsiz + offset_bytes + offset_extra); if (lastp != searchp) { /* this branch taken first time through loop */ - va = vas[count] - = ppmapin(searchp, PROT_WRITE, - (caddr_t)-1); + va = vas[count] = + ppmapin(searchp, PROT_WRITE, (caddr_t)-1); /* ppmapin() guarantees not to return NULL */ } else { vas[count] = NULL; @@ -868,9 +865,9 @@ bufs[count].b_lblkno = driver_block; - remaining_bytes = ((which_chunk_lbn + 1) - * chunk_data_bytes) - - byte_offset; + remaining_bytes = + ((which_chunk_lbn + 1) * chunk_data_bytes) + - byte_offset; /* * remaining_bytes can't be zero, as we derived @@ -905,7 +902,7 @@ bufs[count].b_bufsize = bufs[count].b_bcount; if (((offset_t)byte_offset + bufs[count].b_bcount) > - HS_MAXFILEOFF) { + HS_MAXFILEOFF) { break; } byte_offset += bufs[count].b_bcount; @@ -976,7 +973,7 @@ for (soff = off + PAGESIZE; plsz > 0; soff += PAGESIZE, plsz -= PAGESIZE) { pp = page_lookup_nowait(vp, (u_offset_t)soff, - SE_SHARED); + SE_SHARED); if (pp == NULL) break; pl[index++] = pp; @@ -1100,10 +1097,9 @@ if (!vn_has_cached_data(vp)) /* no pages mapped */ return (0); - if (len == 0) /* from 'off' to EOF */ - error = pvn_vplist_dirty(vp, off, - hsfs_putapage, flags, cr); - else { + if (len == 0) { /* from 'off' to EOF */ + error = pvn_vplist_dirty(vp, off, hsfs_putapage, flags, cr); + } else { offset_t end_off = off + len; offset_t file_size = VTOH(vp)->hs_dirent.ext_size; offset_t io_off; @@ -1122,11 +1118,11 @@ */ if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) { pp = page_lookup(vp, io_off, - (flags & (B_INVAL | B_FREE)) ? - SE_EXCL : SE_SHARED); + (flags & (B_INVAL | B_FREE)) ? + SE_EXCL : SE_SHARED); } else { pp = page_lookup_nowait(vp, io_off, - (flags & B_FREE) ? SE_EXCL : SE_SHARED); + (flags & B_FREE) ? SE_EXCL : SE_SHARED); } if (pp == NULL) @@ -1142,7 +1138,7 @@ */ if (pvn_getdirty(pp, flags) == 1) { cmn_err(CE_NOTE, - "hsfs_putpage: dirty HSFS page"); + "hsfs_putpage: dirty HSFS page"); pvn_write_done(pp, flags | B_ERROR | B_WRITE | B_INVAL | B_FORCE); }
--- a/usr/src/uts/common/sys/fs/hsfs_impl.h Tue Aug 14 19:57:00 2007 -0700 +++ b/usr/src/uts/common/sys/fs/hsfs_impl.h Wed Aug 15 05:40:25 2007 -0700 @@ -22,7 +22,7 @@ * High Sierra filesystem internal routine definitions. */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -53,7 +53,8 @@ extern int hs_dirlook(struct vnode *dvp, char *name, int namlen, struct vnode **vpp, struct cred *cred); /* find an hsnode in the hash list */ -extern struct vnode *hs_findhash(ino64_t nodeid, struct vfs *vfsp); +extern struct vnode *hs_findhash(ino64_t nodeid, uint_t lbn, uint_t off, + struct vfs *vfsp); /* destroy an hsnode */ extern void hs_freenode(vnode_t *vp, struct hsfs *fsp, int nopage); /* parse a directory entry */
--- a/usr/src/uts/common/sys/fs/hsfs_node.h Tue Aug 14 19:57:00 2007 -0700 +++ b/usr/src/uts/common/sys/fs/hsfs_node.h Wed Aug 15 05:40:25 2007 -0700 @@ -22,7 +22,7 @@ * High Sierra filesystem structure definitions */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -46,6 +46,7 @@ uint_t nlink; /* no. of links to file */ uid_t uid; /* owner's user id */ gid_t gid; /* owner's group id */ + ino64_t inode; /* inode number from rrip data */ dev_t r_dev; /* major/minor device numbers */ uint_t xar_prot :1; /* 1 if protection in XAR */ uchar_t xar_len; /* no. of Logical blocks in XAR */ @@ -114,6 +115,7 @@ ushort_t hf_len; /* length of fid */ ushort_t hf_dir_off; /* offset in LBN of directory entry */ uint_t hf_dir_lbn; /* LBN of directory */ + uint32_t hf_ino; /* The inode number or HS_DUMMY_INO */ }; @@ -152,6 +154,17 @@ #define HS_HSNODESPACE 16384 /* approx. space used for hsnodes */ /* + * We usually use the starting extent LBA for the inode numbers of files and + * directories. As this will not work for zero sized files, we assign a dummy + * inode number to all zero sized files. We use the number 16 as this is the + * LBA for the PVD, this number cannot be a valid starting extent LBA for a + * file. In case that the node number is the HS_DUMMY_INO, we use the LBA and + * offset of the directory entry of this file (which is what we used before + * we started to support correct hard links). + */ +#define HS_DUMMY_INO 16 /* dummy inode number for empty files */ + +/* * High Sierra filesystem structure. * There is one of these for each mounted High Sierra filesystem. */ @@ -200,6 +213,8 @@ #define HSFS_ERR_BAD_JOLIET_FILE_LEN 5 #define HSFS_ERR_TRUNC_JOLIET_FILE_LEN 6 #define HSFS_ERR_BAD_DIR_ENTRY 7 +#define HSFS_ERR_NEG_SUA_LEN 8 +#define HSFS_ERR_BAD_SUA_LEN 9 #define HSFS_HAVE_LOWER_CASE(fsp) \ ((fsp)->hsfs_err_flags & (1 << HSFS_ERR_LOWER_CASE_NM)) @@ -241,18 +256,6 @@ #define BYTE_TO_LBN(boff, vfsp) ((boff)>>((struct hsfs *)((vfsp)->vfs_data))-> \ hsfs_vol.lbn_shift) -/* - * Create a nodeid. - * We construct the nodeid from the location of the directory - * entry which points to the file. We divide by 32 to - * compress the range of nodeids; we know that the minimum size - * for an ISO9660 dirent is 34, so we will never have adjacent - * dirents with the same nodeid. - */ -#define HSFS_MIN_DL_SHFT 5 -#define MAKE_NODEID(lbn, off, vfsp) \ - ((LBN_TO_BYTE((lbn), (vfsp)) + (off)) >> HSFS_MIN_DL_SHFT) - #ifdef __cplusplus } #endif
--- a/usr/src/uts/common/sys/fs/hsfs_rrip.h Tue Aug 14 19:57:00 2007 -0700 +++ b/usr/src/uts/common/sys/fs/hsfs_rrip.h Wed Aug 15 05:40:25 2007 -0700 @@ -22,7 +22,7 @@ * ISO 9660 RRIP extension filesystem specifications */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -48,6 +48,8 @@ #define HSFSMNT_NOJOLIET 0x20 /* ignore Joliet even if present */ #define HSFSMNT_JOLIETLONG 0x40 /* do not truncate Joliet filenames */ #define HSFSMNT_NOVERS2 0x80 /* ignore ISO-9660:1999 */ +#define HSFSMNT_INODE 0x1000 /* May use ext_lbn as inode #, */ + /* FS is from a recent mkisofs */ /* * XXX: The following flag was used in the past to instruct the kernel to @@ -177,6 +179,12 @@ #define RRIP_gid(x) (&((uchar_t *)x)[28]) #define RRIP_GID(x) (gid_t)BOTH_INT(RRIP_gid(x)) +#define RRIP_ino(x) (&((uchar_t *)x)[36]) +#define RRIP_INO(x) (uint32_t)BOTH_INT(RRIP_ino(x)) + +#define RRIP_PX_OLD_SIZE 36 +#define RRIP_PX_SIZE 44 + /* * "PN" Posix major/minor numbers */ @@ -290,7 +298,8 @@ extern uchar_t *rrip_reloc_dir(sig_args_t *); extern uchar_t *rrip_rock_ridge(sig_args_t *); extern void hs_check_root_dirent(struct vnode *vp, struct hs_direntry *hdp); -extern int rrip_namecopy(char *from, char *to, char *tmp_name, uchar_t *dirp, +extern int rrip_namecopy(char *from, char *to, char *tmp_name, + uchar_t *dirp, uint_t last_offset, struct hsfs *fsp, struct hs_direntry *hdp); #endif /* _KERNEL */
--- a/usr/src/uts/common/sys/fs/hsfs_susp.h Tue Aug 14 19:57:00 2007 -0700 +++ b/usr/src/uts/common/sys/fs/hsfs_susp.h Wed Aug 15 05:40:25 2007 -0700 @@ -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. @@ -21,8 +20,8 @@ */ /* * ISO 9660 RRIP extension filesystem specifications - * Copyright (c) 1991,1997-1998,2000 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _SYS_FS_HSFS_SUSP_H @@ -249,8 +248,8 @@ extern ext_signature_t *susp_sp; -extern int parse_sua(uchar_t *, int *name_len_p, int *, uchar_t *, struct - hs_direntry *, struct hsfs *, uchar_t *, int search_num); +extern int parse_sua(uchar_t *, int *name_len_p, int *, uchar_t *, uint_t, + struct hs_direntry *, struct hsfs *, uchar_t *, int search_num); #endif /* _KERNEL */