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