162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/fs/hfs/mdb.c 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1995-1997 Paul H. Hargrove 562306a36Sopenharmony_ci * (C) 2003 Ardis Technologies <roman@ardistech.com> 662306a36Sopenharmony_ci * This file may be distributed under the terms of the GNU General Public License. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This file contains functions for reading/writing the MDB. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/cdrom.h> 1262306a36Sopenharmony_ci#include <linux/blkdev.h> 1362306a36Sopenharmony_ci#include <linux/nls.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "hfs_fs.h" 1762306a36Sopenharmony_ci#include "btree.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/*================ File-local data types ================*/ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* 2262306a36Sopenharmony_ci * The HFS Master Directory Block (MDB). 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Also known as the Volume Information Block (VIB), this structure is 2562306a36Sopenharmony_ci * the HFS equivalent of a superblock. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Reference: _Inside Macintosh: Files_ pages 2-59 through 2-62 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * modified for HFS Extended 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic int hfs_get_last_session(struct super_block *sb, 3362306a36Sopenharmony_ci sector_t *start, sector_t *size) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci struct cdrom_device_info *cdi = disk_to_cdi(sb->s_bdev->bd_disk); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci /* default values */ 3862306a36Sopenharmony_ci *start = 0; 3962306a36Sopenharmony_ci *size = bdev_nr_sectors(sb->s_bdev); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (HFS_SB(sb)->session >= 0) { 4262306a36Sopenharmony_ci struct cdrom_tocentry te; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (!cdi) 4562306a36Sopenharmony_ci return -EINVAL; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci te.cdte_track = HFS_SB(sb)->session; 4862306a36Sopenharmony_ci te.cdte_format = CDROM_LBA; 4962306a36Sopenharmony_ci if (cdrom_read_tocentry(cdi, &te) || 5062306a36Sopenharmony_ci (te.cdte_ctrl & CDROM_DATA_TRACK) != 4) { 5162306a36Sopenharmony_ci pr_err("invalid session number or type of track\n"); 5262306a36Sopenharmony_ci return -EINVAL; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci *start = (sector_t)te.cdte_addr.lba << 2; 5662306a36Sopenharmony_ci } else if (cdi) { 5762306a36Sopenharmony_ci struct cdrom_multisession ms_info; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci ms_info.addr_format = CDROM_LBA; 6062306a36Sopenharmony_ci if (cdrom_multisession(cdi, &ms_info) == 0 && ms_info.xa_flag) 6162306a36Sopenharmony_ci *start = (sector_t)ms_info.addr.lba << 2; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* 6862306a36Sopenharmony_ci * hfs_mdb_get() 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * Build the in-core MDB for a filesystem, including 7162306a36Sopenharmony_ci * the B-trees and the volume bitmap. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ciint hfs_mdb_get(struct super_block *sb) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct buffer_head *bh; 7662306a36Sopenharmony_ci struct hfs_mdb *mdb, *mdb2; 7762306a36Sopenharmony_ci unsigned int block; 7862306a36Sopenharmony_ci char *ptr; 7962306a36Sopenharmony_ci int off2, len, size, sect; 8062306a36Sopenharmony_ci sector_t part_start, part_size; 8162306a36Sopenharmony_ci loff_t off; 8262306a36Sopenharmony_ci __be16 attrib; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* set the device driver to 512-byte blocks */ 8562306a36Sopenharmony_ci size = sb_min_blocksize(sb, HFS_SECTOR_SIZE); 8662306a36Sopenharmony_ci if (!size) 8762306a36Sopenharmony_ci return -EINVAL; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (hfs_get_last_session(sb, &part_start, &part_size)) 9062306a36Sopenharmony_ci return -EINVAL; 9162306a36Sopenharmony_ci while (1) { 9262306a36Sopenharmony_ci /* See if this is an HFS filesystem */ 9362306a36Sopenharmony_ci bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb); 9462306a36Sopenharmony_ci if (!bh) 9562306a36Sopenharmony_ci goto out; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (mdb->drSigWord == cpu_to_be16(HFS_SUPER_MAGIC)) 9862306a36Sopenharmony_ci break; 9962306a36Sopenharmony_ci brelse(bh); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* check for a partition block 10262306a36Sopenharmony_ci * (should do this only for cdrom/loop though) 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci if (hfs_part_find(sb, &part_start, &part_size)) 10562306a36Sopenharmony_ci goto out; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci HFS_SB(sb)->alloc_blksz = size = be32_to_cpu(mdb->drAlBlkSiz); 10962306a36Sopenharmony_ci if (!size || (size & (HFS_SECTOR_SIZE - 1))) { 11062306a36Sopenharmony_ci pr_err("bad allocation block size %d\n", size); 11162306a36Sopenharmony_ci goto out_bh; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci size = min(HFS_SB(sb)->alloc_blksz, (u32)PAGE_SIZE); 11562306a36Sopenharmony_ci /* size must be a multiple of 512 */ 11662306a36Sopenharmony_ci while (size & (size - 1)) 11762306a36Sopenharmony_ci size -= HFS_SECTOR_SIZE; 11862306a36Sopenharmony_ci sect = be16_to_cpu(mdb->drAlBlSt) + part_start; 11962306a36Sopenharmony_ci /* align block size to first sector */ 12062306a36Sopenharmony_ci while (sect & ((size - 1) >> HFS_SECTOR_SIZE_BITS)) 12162306a36Sopenharmony_ci size >>= 1; 12262306a36Sopenharmony_ci /* align block size to weird alloc size */ 12362306a36Sopenharmony_ci while (HFS_SB(sb)->alloc_blksz & (size - 1)) 12462306a36Sopenharmony_ci size >>= 1; 12562306a36Sopenharmony_ci brelse(bh); 12662306a36Sopenharmony_ci if (!sb_set_blocksize(sb, size)) { 12762306a36Sopenharmony_ci pr_err("unable to set blocksize to %u\n", size); 12862306a36Sopenharmony_ci goto out; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb); 13262306a36Sopenharmony_ci if (!bh) 13362306a36Sopenharmony_ci goto out; 13462306a36Sopenharmony_ci if (mdb->drSigWord != cpu_to_be16(HFS_SUPER_MAGIC)) 13562306a36Sopenharmony_ci goto out_bh; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci HFS_SB(sb)->mdb_bh = bh; 13862306a36Sopenharmony_ci HFS_SB(sb)->mdb = mdb; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* These parameters are read from the MDB, and never written */ 14162306a36Sopenharmony_ci HFS_SB(sb)->part_start = part_start; 14262306a36Sopenharmony_ci HFS_SB(sb)->fs_ablocks = be16_to_cpu(mdb->drNmAlBlks); 14362306a36Sopenharmony_ci HFS_SB(sb)->fs_div = HFS_SB(sb)->alloc_blksz >> sb->s_blocksize_bits; 14462306a36Sopenharmony_ci HFS_SB(sb)->clumpablks = be32_to_cpu(mdb->drClpSiz) / 14562306a36Sopenharmony_ci HFS_SB(sb)->alloc_blksz; 14662306a36Sopenharmony_ci if (!HFS_SB(sb)->clumpablks) 14762306a36Sopenharmony_ci HFS_SB(sb)->clumpablks = 1; 14862306a36Sopenharmony_ci HFS_SB(sb)->fs_start = (be16_to_cpu(mdb->drAlBlSt) + part_start) >> 14962306a36Sopenharmony_ci (sb->s_blocksize_bits - HFS_SECTOR_SIZE_BITS); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* These parameters are read from and written to the MDB */ 15262306a36Sopenharmony_ci HFS_SB(sb)->free_ablocks = be16_to_cpu(mdb->drFreeBks); 15362306a36Sopenharmony_ci HFS_SB(sb)->next_id = be32_to_cpu(mdb->drNxtCNID); 15462306a36Sopenharmony_ci HFS_SB(sb)->root_files = be16_to_cpu(mdb->drNmFls); 15562306a36Sopenharmony_ci HFS_SB(sb)->root_dirs = be16_to_cpu(mdb->drNmRtDirs); 15662306a36Sopenharmony_ci HFS_SB(sb)->file_count = be32_to_cpu(mdb->drFilCnt); 15762306a36Sopenharmony_ci HFS_SB(sb)->folder_count = be32_to_cpu(mdb->drDirCnt); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* TRY to get the alternate (backup) MDB. */ 16062306a36Sopenharmony_ci sect = part_start + part_size - 2; 16162306a36Sopenharmony_ci bh = sb_bread512(sb, sect, mdb2); 16262306a36Sopenharmony_ci if (bh) { 16362306a36Sopenharmony_ci if (mdb2->drSigWord == cpu_to_be16(HFS_SUPER_MAGIC)) { 16462306a36Sopenharmony_ci HFS_SB(sb)->alt_mdb_bh = bh; 16562306a36Sopenharmony_ci HFS_SB(sb)->alt_mdb = mdb2; 16662306a36Sopenharmony_ci } else 16762306a36Sopenharmony_ci brelse(bh); 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (!HFS_SB(sb)->alt_mdb) { 17162306a36Sopenharmony_ci pr_warn("unable to locate alternate MDB\n"); 17262306a36Sopenharmony_ci pr_warn("continuing without an alternate MDB\n"); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci HFS_SB(sb)->bitmap = kmalloc(8192, GFP_KERNEL); 17662306a36Sopenharmony_ci if (!HFS_SB(sb)->bitmap) 17762306a36Sopenharmony_ci goto out; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* read in the bitmap */ 18062306a36Sopenharmony_ci block = be16_to_cpu(mdb->drVBMSt) + part_start; 18162306a36Sopenharmony_ci off = (loff_t)block << HFS_SECTOR_SIZE_BITS; 18262306a36Sopenharmony_ci size = (HFS_SB(sb)->fs_ablocks + 8) / 8; 18362306a36Sopenharmony_ci ptr = (u8 *)HFS_SB(sb)->bitmap; 18462306a36Sopenharmony_ci while (size) { 18562306a36Sopenharmony_ci bh = sb_bread(sb, off >> sb->s_blocksize_bits); 18662306a36Sopenharmony_ci if (!bh) { 18762306a36Sopenharmony_ci pr_err("unable to read volume bitmap\n"); 18862306a36Sopenharmony_ci goto out; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci off2 = off & (sb->s_blocksize - 1); 19162306a36Sopenharmony_ci len = min((int)sb->s_blocksize - off2, size); 19262306a36Sopenharmony_ci memcpy(ptr, bh->b_data + off2, len); 19362306a36Sopenharmony_ci brelse(bh); 19462306a36Sopenharmony_ci ptr += len; 19562306a36Sopenharmony_ci off += len; 19662306a36Sopenharmony_ci size -= len; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp); 20062306a36Sopenharmony_ci if (!HFS_SB(sb)->ext_tree) { 20162306a36Sopenharmony_ci pr_err("unable to open extent tree\n"); 20262306a36Sopenharmony_ci goto out; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp); 20562306a36Sopenharmony_ci if (!HFS_SB(sb)->cat_tree) { 20662306a36Sopenharmony_ci pr_err("unable to open catalog tree\n"); 20762306a36Sopenharmony_ci goto out; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci attrib = mdb->drAtrb; 21162306a36Sopenharmony_ci if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) { 21262306a36Sopenharmony_ci pr_warn("filesystem was not cleanly unmounted, running fsck.hfs is recommended. mounting read-only.\n"); 21362306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) { 21662306a36Sopenharmony_ci pr_warn("filesystem is marked locked, mounting read-only.\n"); 21762306a36Sopenharmony_ci sb->s_flags |= SB_RDONLY; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 22062306a36Sopenharmony_ci /* Mark the volume uncleanly unmounted in case we crash */ 22162306a36Sopenharmony_ci attrib &= cpu_to_be16(~HFS_SB_ATTRIB_UNMNT); 22262306a36Sopenharmony_ci attrib |= cpu_to_be16(HFS_SB_ATTRIB_INCNSTNT); 22362306a36Sopenharmony_ci mdb->drAtrb = attrib; 22462306a36Sopenharmony_ci be32_add_cpu(&mdb->drWrCnt, 1); 22562306a36Sopenharmony_ci mdb->drLsMod = hfs_mtime(); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci mark_buffer_dirty(HFS_SB(sb)->mdb_bh); 22862306a36Sopenharmony_ci sync_dirty_buffer(HFS_SB(sb)->mdb_bh); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ciout_bh: 23462306a36Sopenharmony_ci brelse(bh); 23562306a36Sopenharmony_ciout: 23662306a36Sopenharmony_ci hfs_mdb_put(sb); 23762306a36Sopenharmony_ci return -EIO; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* 24162306a36Sopenharmony_ci * hfs_mdb_commit() 24262306a36Sopenharmony_ci * 24362306a36Sopenharmony_ci * Description: 24462306a36Sopenharmony_ci * This updates the MDB on disk. 24562306a36Sopenharmony_ci * It does not check, if the superblock has been modified, or 24662306a36Sopenharmony_ci * if the filesystem has been mounted read-only. It is mainly 24762306a36Sopenharmony_ci * called by hfs_sync_fs() and flush_mdb(). 24862306a36Sopenharmony_ci * Input Variable(s): 24962306a36Sopenharmony_ci * struct hfs_mdb *mdb: Pointer to the hfs MDB 25062306a36Sopenharmony_ci * int backup; 25162306a36Sopenharmony_ci * Output Variable(s): 25262306a36Sopenharmony_ci * NONE 25362306a36Sopenharmony_ci * Returns: 25462306a36Sopenharmony_ci * void 25562306a36Sopenharmony_ci * Preconditions: 25662306a36Sopenharmony_ci * 'mdb' points to a "valid" (struct hfs_mdb). 25762306a36Sopenharmony_ci * Postconditions: 25862306a36Sopenharmony_ci * The HFS MDB and on disk will be updated, by copying the possibly 25962306a36Sopenharmony_ci * modified fields from the in memory MDB (in native byte order) to 26062306a36Sopenharmony_ci * the disk block buffer. 26162306a36Sopenharmony_ci * If 'backup' is non-zero then the alternate MDB is also written 26262306a36Sopenharmony_ci * and the function doesn't return until it is actually on disk. 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_civoid hfs_mdb_commit(struct super_block *sb) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct hfs_mdb *mdb = HFS_SB(sb)->mdb; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (sb_rdonly(sb)) 26962306a36Sopenharmony_ci return; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci lock_buffer(HFS_SB(sb)->mdb_bh); 27262306a36Sopenharmony_ci if (test_and_clear_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags)) { 27362306a36Sopenharmony_ci /* These parameters may have been modified, so write them back */ 27462306a36Sopenharmony_ci mdb->drLsMod = hfs_mtime(); 27562306a36Sopenharmony_ci mdb->drFreeBks = cpu_to_be16(HFS_SB(sb)->free_ablocks); 27662306a36Sopenharmony_ci mdb->drNxtCNID = cpu_to_be32(HFS_SB(sb)->next_id); 27762306a36Sopenharmony_ci mdb->drNmFls = cpu_to_be16(HFS_SB(sb)->root_files); 27862306a36Sopenharmony_ci mdb->drNmRtDirs = cpu_to_be16(HFS_SB(sb)->root_dirs); 27962306a36Sopenharmony_ci mdb->drFilCnt = cpu_to_be32(HFS_SB(sb)->file_count); 28062306a36Sopenharmony_ci mdb->drDirCnt = cpu_to_be32(HFS_SB(sb)->folder_count); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* write MDB to disk */ 28362306a36Sopenharmony_ci mark_buffer_dirty(HFS_SB(sb)->mdb_bh); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* write the backup MDB, not returning until it is written. 28762306a36Sopenharmony_ci * we only do this when either the catalog or extents overflow 28862306a36Sopenharmony_ci * files grow. */ 28962306a36Sopenharmony_ci if (test_and_clear_bit(HFS_FLG_ALT_MDB_DIRTY, &HFS_SB(sb)->flags) && 29062306a36Sopenharmony_ci HFS_SB(sb)->alt_mdb) { 29162306a36Sopenharmony_ci hfs_inode_write_fork(HFS_SB(sb)->ext_tree->inode, mdb->drXTExtRec, 29262306a36Sopenharmony_ci &mdb->drXTFlSize, NULL); 29362306a36Sopenharmony_ci hfs_inode_write_fork(HFS_SB(sb)->cat_tree->inode, mdb->drCTExtRec, 29462306a36Sopenharmony_ci &mdb->drCTFlSize, NULL); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci lock_buffer(HFS_SB(sb)->alt_mdb_bh); 29762306a36Sopenharmony_ci memcpy(HFS_SB(sb)->alt_mdb, HFS_SB(sb)->mdb, HFS_SECTOR_SIZE); 29862306a36Sopenharmony_ci HFS_SB(sb)->alt_mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT); 29962306a36Sopenharmony_ci HFS_SB(sb)->alt_mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT); 30062306a36Sopenharmony_ci unlock_buffer(HFS_SB(sb)->alt_mdb_bh); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci mark_buffer_dirty(HFS_SB(sb)->alt_mdb_bh); 30362306a36Sopenharmony_ci sync_dirty_buffer(HFS_SB(sb)->alt_mdb_bh); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (test_and_clear_bit(HFS_FLG_BITMAP_DIRTY, &HFS_SB(sb)->flags)) { 30762306a36Sopenharmony_ci struct buffer_head *bh; 30862306a36Sopenharmony_ci sector_t block; 30962306a36Sopenharmony_ci char *ptr; 31062306a36Sopenharmony_ci int off, size, len; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci block = be16_to_cpu(HFS_SB(sb)->mdb->drVBMSt) + HFS_SB(sb)->part_start; 31362306a36Sopenharmony_ci off = (block << HFS_SECTOR_SIZE_BITS) & (sb->s_blocksize - 1); 31462306a36Sopenharmony_ci block >>= sb->s_blocksize_bits - HFS_SECTOR_SIZE_BITS; 31562306a36Sopenharmony_ci size = (HFS_SB(sb)->fs_ablocks + 7) / 8; 31662306a36Sopenharmony_ci ptr = (u8 *)HFS_SB(sb)->bitmap; 31762306a36Sopenharmony_ci while (size) { 31862306a36Sopenharmony_ci bh = sb_bread(sb, block); 31962306a36Sopenharmony_ci if (!bh) { 32062306a36Sopenharmony_ci pr_err("unable to read volume bitmap\n"); 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci len = min((int)sb->s_blocksize - off, size); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci lock_buffer(bh); 32662306a36Sopenharmony_ci memcpy(bh->b_data + off, ptr, len); 32762306a36Sopenharmony_ci unlock_buffer(bh); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci mark_buffer_dirty(bh); 33062306a36Sopenharmony_ci brelse(bh); 33162306a36Sopenharmony_ci block++; 33262306a36Sopenharmony_ci off = 0; 33362306a36Sopenharmony_ci ptr += len; 33462306a36Sopenharmony_ci size -= len; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci unlock_buffer(HFS_SB(sb)->mdb_bh); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_civoid hfs_mdb_close(struct super_block *sb) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci /* update volume attributes */ 34362306a36Sopenharmony_ci if (sb_rdonly(sb)) 34462306a36Sopenharmony_ci return; 34562306a36Sopenharmony_ci HFS_SB(sb)->mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT); 34662306a36Sopenharmony_ci HFS_SB(sb)->mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT); 34762306a36Sopenharmony_ci mark_buffer_dirty(HFS_SB(sb)->mdb_bh); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/* 35162306a36Sopenharmony_ci * hfs_mdb_put() 35262306a36Sopenharmony_ci * 35362306a36Sopenharmony_ci * Release the resources associated with the in-core MDB. */ 35462306a36Sopenharmony_civoid hfs_mdb_put(struct super_block *sb) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci if (!HFS_SB(sb)) 35762306a36Sopenharmony_ci return; 35862306a36Sopenharmony_ci /* free the B-trees */ 35962306a36Sopenharmony_ci hfs_btree_close(HFS_SB(sb)->ext_tree); 36062306a36Sopenharmony_ci hfs_btree_close(HFS_SB(sb)->cat_tree); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* free the buffers holding the primary and alternate MDBs */ 36362306a36Sopenharmony_ci brelse(HFS_SB(sb)->mdb_bh); 36462306a36Sopenharmony_ci brelse(HFS_SB(sb)->alt_mdb_bh); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci unload_nls(HFS_SB(sb)->nls_io); 36762306a36Sopenharmony_ci unload_nls(HFS_SB(sb)->nls_disk); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci kfree(HFS_SB(sb)->bitmap); 37062306a36Sopenharmony_ci kfree(HFS_SB(sb)); 37162306a36Sopenharmony_ci sb->s_fs_info = NULL; 37262306a36Sopenharmony_ci} 373