cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mdb.c (10361B)


      1/*
      2 *  linux/fs/hfs/mdb.c
      3 *
      4 * Copyright (C) 1995-1997  Paul H. Hargrove
      5 * (C) 2003 Ardis Technologies <roman@ardistech.com>
      6 * This file may be distributed under the terms of the GNU General Public License.
      7 *
      8 * This file contains functions for reading/writing the MDB.
      9 */
     10
     11#include <linux/cdrom.h>
     12#include <linux/blkdev.h>
     13#include <linux/nls.h>
     14#include <linux/slab.h>
     15
     16#include "hfs_fs.h"
     17#include "btree.h"
     18
     19/*================ File-local data types ================*/
     20
     21/*
     22 * The HFS Master Directory Block (MDB).
     23 *
     24 * Also known as the Volume Information Block (VIB), this structure is
     25 * the HFS equivalent of a superblock.
     26 *
     27 * Reference: _Inside Macintosh: Files_ pages 2-59 through 2-62
     28 *
     29 * modified for HFS Extended
     30 */
     31
     32static int hfs_get_last_session(struct super_block *sb,
     33				sector_t *start, sector_t *size)
     34{
     35	struct cdrom_device_info *cdi = disk_to_cdi(sb->s_bdev->bd_disk);
     36
     37	/* default values */
     38	*start = 0;
     39	*size = bdev_nr_sectors(sb->s_bdev);
     40
     41	if (HFS_SB(sb)->session >= 0) {
     42		struct cdrom_tocentry te;
     43	
     44		if (!cdi)
     45			return -EINVAL;
     46
     47		te.cdte_track = HFS_SB(sb)->session;
     48		te.cdte_format = CDROM_LBA;
     49		if (cdrom_read_tocentry(cdi, &te) ||
     50		    (te.cdte_ctrl & CDROM_DATA_TRACK) != 4) {
     51			pr_err("invalid session number or type of track\n");
     52			return -EINVAL;
     53		}
     54
     55		*start = (sector_t)te.cdte_addr.lba << 2;
     56	} else if (cdi) {
     57		struct cdrom_multisession ms_info;
     58
     59		ms_info.addr_format = CDROM_LBA;
     60		if (cdrom_multisession(cdi, &ms_info) == 0 && ms_info.xa_flag)
     61			*start = (sector_t)ms_info.addr.lba << 2;
     62	}
     63
     64	return 0;
     65}
     66
     67/*
     68 * hfs_mdb_get()
     69 *
     70 * Build the in-core MDB for a filesystem, including
     71 * the B-trees and the volume bitmap.
     72 */
     73int hfs_mdb_get(struct super_block *sb)
     74{
     75	struct buffer_head *bh;
     76	struct hfs_mdb *mdb, *mdb2;
     77	unsigned int block;
     78	char *ptr;
     79	int off2, len, size, sect;
     80	sector_t part_start, part_size;
     81	loff_t off;
     82	__be16 attrib;
     83
     84	/* set the device driver to 512-byte blocks */
     85	size = sb_min_blocksize(sb, HFS_SECTOR_SIZE);
     86	if (!size)
     87		return -EINVAL;
     88
     89	if (hfs_get_last_session(sb, &part_start, &part_size))
     90		return -EINVAL;
     91	while (1) {
     92		/* See if this is an HFS filesystem */
     93		bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb);
     94		if (!bh)
     95			goto out;
     96
     97		if (mdb->drSigWord == cpu_to_be16(HFS_SUPER_MAGIC))
     98			break;
     99		brelse(bh);
    100
    101		/* check for a partition block
    102		 * (should do this only for cdrom/loop though)
    103		 */
    104		if (hfs_part_find(sb, &part_start, &part_size))
    105			goto out;
    106	}
    107
    108	HFS_SB(sb)->alloc_blksz = size = be32_to_cpu(mdb->drAlBlkSiz);
    109	if (!size || (size & (HFS_SECTOR_SIZE - 1))) {
    110		pr_err("bad allocation block size %d\n", size);
    111		goto out_bh;
    112	}
    113
    114	size = min(HFS_SB(sb)->alloc_blksz, (u32)PAGE_SIZE);
    115	/* size must be a multiple of 512 */
    116	while (size & (size - 1))
    117		size -= HFS_SECTOR_SIZE;
    118	sect = be16_to_cpu(mdb->drAlBlSt) + part_start;
    119	/* align block size to first sector */
    120	while (sect & ((size - 1) >> HFS_SECTOR_SIZE_BITS))
    121		size >>= 1;
    122	/* align block size to weird alloc size */
    123	while (HFS_SB(sb)->alloc_blksz & (size - 1))
    124		size >>= 1;
    125	brelse(bh);
    126	if (!sb_set_blocksize(sb, size)) {
    127		pr_err("unable to set blocksize to %u\n", size);
    128		goto out;
    129	}
    130
    131	bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb);
    132	if (!bh)
    133		goto out;
    134	if (mdb->drSigWord != cpu_to_be16(HFS_SUPER_MAGIC))
    135		goto out_bh;
    136
    137	HFS_SB(sb)->mdb_bh = bh;
    138	HFS_SB(sb)->mdb = mdb;
    139
    140	/* These parameters are read from the MDB, and never written */
    141	HFS_SB(sb)->part_start = part_start;
    142	HFS_SB(sb)->fs_ablocks = be16_to_cpu(mdb->drNmAlBlks);
    143	HFS_SB(sb)->fs_div = HFS_SB(sb)->alloc_blksz >> sb->s_blocksize_bits;
    144	HFS_SB(sb)->clumpablks = be32_to_cpu(mdb->drClpSiz) /
    145				 HFS_SB(sb)->alloc_blksz;
    146	if (!HFS_SB(sb)->clumpablks)
    147		HFS_SB(sb)->clumpablks = 1;
    148	HFS_SB(sb)->fs_start = (be16_to_cpu(mdb->drAlBlSt) + part_start) >>
    149			       (sb->s_blocksize_bits - HFS_SECTOR_SIZE_BITS);
    150
    151	/* These parameters are read from and written to the MDB */
    152	HFS_SB(sb)->free_ablocks = be16_to_cpu(mdb->drFreeBks);
    153	HFS_SB(sb)->next_id = be32_to_cpu(mdb->drNxtCNID);
    154	HFS_SB(sb)->root_files = be16_to_cpu(mdb->drNmFls);
    155	HFS_SB(sb)->root_dirs = be16_to_cpu(mdb->drNmRtDirs);
    156	HFS_SB(sb)->file_count = be32_to_cpu(mdb->drFilCnt);
    157	HFS_SB(sb)->folder_count = be32_to_cpu(mdb->drDirCnt);
    158
    159	/* TRY to get the alternate (backup) MDB. */
    160	sect = part_start + part_size - 2;
    161	bh = sb_bread512(sb, sect, mdb2);
    162	if (bh) {
    163		if (mdb2->drSigWord == cpu_to_be16(HFS_SUPER_MAGIC)) {
    164			HFS_SB(sb)->alt_mdb_bh = bh;
    165			HFS_SB(sb)->alt_mdb = mdb2;
    166		} else
    167			brelse(bh);
    168	}
    169
    170	if (!HFS_SB(sb)->alt_mdb) {
    171		pr_warn("unable to locate alternate MDB\n");
    172		pr_warn("continuing without an alternate MDB\n");
    173	}
    174
    175	HFS_SB(sb)->bitmap = kmalloc(8192, GFP_KERNEL);
    176	if (!HFS_SB(sb)->bitmap)
    177		goto out;
    178
    179	/* read in the bitmap */
    180	block = be16_to_cpu(mdb->drVBMSt) + part_start;
    181	off = (loff_t)block << HFS_SECTOR_SIZE_BITS;
    182	size = (HFS_SB(sb)->fs_ablocks + 8) / 8;
    183	ptr = (u8 *)HFS_SB(sb)->bitmap;
    184	while (size) {
    185		bh = sb_bread(sb, off >> sb->s_blocksize_bits);
    186		if (!bh) {
    187			pr_err("unable to read volume bitmap\n");
    188			goto out;
    189		}
    190		off2 = off & (sb->s_blocksize - 1);
    191		len = min((int)sb->s_blocksize - off2, size);
    192		memcpy(ptr, bh->b_data + off2, len);
    193		brelse(bh);
    194		ptr += len;
    195		off += len;
    196		size -= len;
    197	}
    198
    199	HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp);
    200	if (!HFS_SB(sb)->ext_tree) {
    201		pr_err("unable to open extent tree\n");
    202		goto out;
    203	}
    204	HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp);
    205	if (!HFS_SB(sb)->cat_tree) {
    206		pr_err("unable to open catalog tree\n");
    207		goto out;
    208	}
    209
    210	attrib = mdb->drAtrb;
    211	if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) {
    212		pr_warn("filesystem was not cleanly unmounted, running fsck.hfs is recommended.  mounting read-only.\n");
    213		sb->s_flags |= SB_RDONLY;
    214	}
    215	if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) {
    216		pr_warn("filesystem is marked locked, mounting read-only.\n");
    217		sb->s_flags |= SB_RDONLY;
    218	}
    219	if (!sb_rdonly(sb)) {
    220		/* Mark the volume uncleanly unmounted in case we crash */
    221		attrib &= cpu_to_be16(~HFS_SB_ATTRIB_UNMNT);
    222		attrib |= cpu_to_be16(HFS_SB_ATTRIB_INCNSTNT);
    223		mdb->drAtrb = attrib;
    224		be32_add_cpu(&mdb->drWrCnt, 1);
    225		mdb->drLsMod = hfs_mtime();
    226
    227		mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
    228		sync_dirty_buffer(HFS_SB(sb)->mdb_bh);
    229	}
    230
    231	return 0;
    232
    233out_bh:
    234	brelse(bh);
    235out:
    236	hfs_mdb_put(sb);
    237	return -EIO;
    238}
    239
    240/*
    241 * hfs_mdb_commit()
    242 *
    243 * Description:
    244 *   This updates the MDB on disk.
    245 *   It does not check, if the superblock has been modified, or
    246 *   if the filesystem has been mounted read-only. It is mainly
    247 *   called by hfs_sync_fs() and flush_mdb().
    248 * Input Variable(s):
    249 *   struct hfs_mdb *mdb: Pointer to the hfs MDB
    250 *   int backup;
    251 * Output Variable(s):
    252 *   NONE
    253 * Returns:
    254 *   void
    255 * Preconditions:
    256 *   'mdb' points to a "valid" (struct hfs_mdb).
    257 * Postconditions:
    258 *   The HFS MDB and on disk will be updated, by copying the possibly
    259 *   modified fields from the in memory MDB (in native byte order) to
    260 *   the disk block buffer.
    261 *   If 'backup' is non-zero then the alternate MDB is also written
    262 *   and the function doesn't return until it is actually on disk.
    263 */
    264void hfs_mdb_commit(struct super_block *sb)
    265{
    266	struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
    267
    268	if (sb_rdonly(sb))
    269		return;
    270
    271	lock_buffer(HFS_SB(sb)->mdb_bh);
    272	if (test_and_clear_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags)) {
    273		/* These parameters may have been modified, so write them back */
    274		mdb->drLsMod = hfs_mtime();
    275		mdb->drFreeBks = cpu_to_be16(HFS_SB(sb)->free_ablocks);
    276		mdb->drNxtCNID = cpu_to_be32(HFS_SB(sb)->next_id);
    277		mdb->drNmFls = cpu_to_be16(HFS_SB(sb)->root_files);
    278		mdb->drNmRtDirs = cpu_to_be16(HFS_SB(sb)->root_dirs);
    279		mdb->drFilCnt = cpu_to_be32(HFS_SB(sb)->file_count);
    280		mdb->drDirCnt = cpu_to_be32(HFS_SB(sb)->folder_count);
    281
    282		/* write MDB to disk */
    283		mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
    284	}
    285
    286	/* write the backup MDB, not returning until it is written.
    287	 * we only do this when either the catalog or extents overflow
    288	 * files grow. */
    289	if (test_and_clear_bit(HFS_FLG_ALT_MDB_DIRTY, &HFS_SB(sb)->flags) &&
    290	    HFS_SB(sb)->alt_mdb) {
    291		hfs_inode_write_fork(HFS_SB(sb)->ext_tree->inode, mdb->drXTExtRec,
    292				     &mdb->drXTFlSize, NULL);
    293		hfs_inode_write_fork(HFS_SB(sb)->cat_tree->inode, mdb->drCTExtRec,
    294				     &mdb->drCTFlSize, NULL);
    295
    296		lock_buffer(HFS_SB(sb)->alt_mdb_bh);
    297		memcpy(HFS_SB(sb)->alt_mdb, HFS_SB(sb)->mdb, HFS_SECTOR_SIZE);
    298		HFS_SB(sb)->alt_mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
    299		HFS_SB(sb)->alt_mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
    300		unlock_buffer(HFS_SB(sb)->alt_mdb_bh);
    301
    302		mark_buffer_dirty(HFS_SB(sb)->alt_mdb_bh);
    303		sync_dirty_buffer(HFS_SB(sb)->alt_mdb_bh);
    304	}
    305
    306	if (test_and_clear_bit(HFS_FLG_BITMAP_DIRTY, &HFS_SB(sb)->flags)) {
    307		struct buffer_head *bh;
    308		sector_t block;
    309		char *ptr;
    310		int off, size, len;
    311
    312		block = be16_to_cpu(HFS_SB(sb)->mdb->drVBMSt) + HFS_SB(sb)->part_start;
    313		off = (block << HFS_SECTOR_SIZE_BITS) & (sb->s_blocksize - 1);
    314		block >>= sb->s_blocksize_bits - HFS_SECTOR_SIZE_BITS;
    315		size = (HFS_SB(sb)->fs_ablocks + 7) / 8;
    316		ptr = (u8 *)HFS_SB(sb)->bitmap;
    317		while (size) {
    318			bh = sb_bread(sb, block);
    319			if (!bh) {
    320				pr_err("unable to read volume bitmap\n");
    321				break;
    322			}
    323			len = min((int)sb->s_blocksize - off, size);
    324
    325			lock_buffer(bh);
    326			memcpy(bh->b_data + off, ptr, len);
    327			unlock_buffer(bh);
    328
    329			mark_buffer_dirty(bh);
    330			brelse(bh);
    331			block++;
    332			off = 0;
    333			ptr += len;
    334			size -= len;
    335		}
    336	}
    337	unlock_buffer(HFS_SB(sb)->mdb_bh);
    338}
    339
    340void hfs_mdb_close(struct super_block *sb)
    341{
    342	/* update volume attributes */
    343	if (sb_rdonly(sb))
    344		return;
    345	HFS_SB(sb)->mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
    346	HFS_SB(sb)->mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
    347	mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
    348}
    349
    350/*
    351 * hfs_mdb_put()
    352 *
    353 * Release the resources associated with the in-core MDB.  */
    354void hfs_mdb_put(struct super_block *sb)
    355{
    356	if (!HFS_SB(sb))
    357		return;
    358	/* free the B-trees */
    359	hfs_btree_close(HFS_SB(sb)->ext_tree);
    360	hfs_btree_close(HFS_SB(sb)->cat_tree);
    361
    362	/* free the buffers holding the primary and alternate MDBs */
    363	brelse(HFS_SB(sb)->mdb_bh);
    364	brelse(HFS_SB(sb)->alt_mdb_bh);
    365
    366	unload_nls(HFS_SB(sb)->nls_io);
    367	unload_nls(HFS_SB(sb)->nls_disk);
    368
    369	kfree(HFS_SB(sb)->bitmap);
    370	kfree(HFS_SB(sb));
    371	sb->s_fs_info = NULL;
    372}