linux/fs/hfs/mdb.c
<<
>>
Prefs
   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/genhd.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 = i_size_read(sb->s_bdev->bd_inode) >> 9;
  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}
 373