1/* 2 * linux/fs/hfsplus/super.c 3 * 4 * Copyright (C) 2001 5 * Brad Boyer (flar@allandria.com) 6 * (C) 2003 Ardis Technologies <roman@ardistech.com> 7 * 8 */ 9 10#include <linux/module.h> 11#include <linux/init.h> 12#include <linux/pagemap.h> 13#include <linux/fs.h> 14#include <linux/slab.h> 15#include <linux/vfs.h> 16#include <linux/nls.h> 17 18static struct inode *hfsplus_alloc_inode(struct super_block *sb); 19static void hfsplus_destroy_inode(struct inode *inode); 20 21#include "hfsplus_fs.h" 22 23static void hfsplus_read_inode(struct inode *inode) 24{ 25 struct hfs_find_data fd; 26 struct hfsplus_vh *vhdr; 27 hfsplus_handle_t hfsplus_handle; 28 int err; 29 30 INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); 31 init_MUTEX(&HFSPLUS_I(inode).extents_lock); 32 HFSPLUS_I(inode).flags = 0; 33 HFSPLUS_I(inode).rsrc_inode = NULL; 34 atomic_set(&HFSPLUS_I(inode).opencnt, 0); 35 36 if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) { 37 read_inode: 38 hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd); 39 if (hfsplus_journal_start(__FUNCTION__, inode->i_sb, &hfsplus_handle)) 40 goto bad_inode; 41 err = hfsplus_find_cat(&hfsplus_handle, inode->i_sb, inode->i_ino, &fd); 42 if (!err) 43 err = hfsplus_cat_read_inode(inode, &fd); 44 hfs_find_exit(&hfsplus_handle, &fd); 45 hfsplus_journal_stop(&hfsplus_handle); 46 if (err) 47 goto bad_inode; 48 return; 49 } 50 vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr; 51 switch(inode->i_ino) { 52 case HFSPLUS_ROOT_CNID: 53 goto read_inode; 54 case HFSPLUS_EXT_CNID: 55 hfsplus_inode_read_fork(inode, &vhdr->ext_file); 56 if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) 57 inode->i_mapping->a_ops = &hfsplus_journalled_btree_aops; 58 else 59 inode->i_mapping->a_ops = &hfsplus_btree_aops; 60 break; 61 case HFSPLUS_CAT_CNID: 62 hfsplus_inode_read_fork(inode, &vhdr->cat_file); 63 if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) 64 inode->i_mapping->a_ops = &hfsplus_journalled_btree_aops; 65 else 66 inode->i_mapping->a_ops = &hfsplus_btree_aops; 67 break; 68 case HFSPLUS_ALLOC_CNID: 69 hfsplus_inode_read_fork(inode, &vhdr->alloc_file); 70 if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) 71 inode->i_mapping->a_ops = &hfsplus_journalled_aops; 72 else 73 inode->i_mapping->a_ops = &hfsplus_aops; 74 break; 75 case HFSPLUS_START_CNID: 76 hfsplus_inode_read_fork(inode, &vhdr->start_file); 77 break; 78 case HFSPLUS_ATTR_CNID: 79 hfsplus_inode_read_fork(inode, &vhdr->attr_file); 80 if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) 81 inode->i_mapping->a_ops = &hfsplus_journalled_btree_aops; 82 else 83 inode->i_mapping->a_ops = &hfsplus_btree_aops; 84 break; 85 default: 86 goto bad_inode; 87 } 88 89 return; 90 91 bad_inode: 92 make_bad_inode(inode); 93} 94 95static int hfsplus_write_inode(struct inode *inode, int unused) 96{ 97 struct hfsplus_vh *vhdr; 98 hfsplus_handle_t hfsplus_handle; 99 int ret = 0; 100 101 if ((HFSPLUS_SB(inode->i_sb).jnl.journaled == HFSPLUS_JOURNAL_PRESENT) && 102 ((inode->i_mapping->a_ops == &hfsplus_journalled_btree_aops) || 103 (inode->i_mapping->a_ops == &hfsplus_journalled_aops))) { 104 if (current->flags & PF_MEMALLOC) 105 return 0; 106 107 if (hfsplus_jbd_current_handle()) { 108 hfsplus_jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n"); 109 dump_stack(); 110 return -EIO; 111 } 112 113 if (!unused) 114 return 0; 115 116 return hfsplus_force_commit(inode->i_sb); 117 } 118 119 dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino); 120 hfsplus_handle.journaled = !HFSPLUS_JOURNAL_PRESENT; 121 122 hfsplus_ext_write_extent(&hfsplus_handle, inode); 123 if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) { 124 ret = hfsplus_cat_write_inode(&hfsplus_handle, inode); 125 return ret; 126 } 127 vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr; 128 switch (inode->i_ino) { 129 case HFSPLUS_ROOT_CNID: 130 ret = hfsplus_cat_write_inode(&hfsplus_handle, inode); 131 break; 132 case HFSPLUS_EXT_CNID: 133 if (vhdr->ext_file.total_size != cpu_to_be64(inode->i_size)) { 134 HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP; 135 inode->i_sb->s_dirt = 1; 136 } 137 hfsplus_inode_write_fork(inode, &vhdr->ext_file); 138 hfs_btree_write(&hfsplus_handle, HFSPLUS_SB(inode->i_sb).ext_tree); 139 break; 140 case HFSPLUS_CAT_CNID: 141 if (vhdr->cat_file.total_size != cpu_to_be64(inode->i_size)) { 142 HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP; 143 inode->i_sb->s_dirt = 1; 144 } 145 hfsplus_inode_write_fork(inode, &vhdr->cat_file); 146 hfs_btree_write(&hfsplus_handle, HFSPLUS_SB(inode->i_sb).cat_tree); 147 break; 148 case HFSPLUS_ALLOC_CNID: 149 if (vhdr->alloc_file.total_size != cpu_to_be64(inode->i_size)) { 150 HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP; 151 inode->i_sb->s_dirt = 1; 152 } 153 hfsplus_inode_write_fork(inode, &vhdr->alloc_file); 154 break; 155 case HFSPLUS_START_CNID: 156 if (vhdr->start_file.total_size != cpu_to_be64(inode->i_size)) { 157 HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP; 158 inode->i_sb->s_dirt = 1; 159 } 160 hfsplus_inode_write_fork(inode, &vhdr->start_file); 161 break; 162 case HFSPLUS_ATTR_CNID: 163 if (vhdr->attr_file.total_size != cpu_to_be64(inode->i_size)) { 164 HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP; 165 inode->i_sb->s_dirt = 1; 166 } 167 hfsplus_inode_write_fork(inode, &vhdr->attr_file); 168 hfs_btree_write(&hfsplus_handle, HFSPLUS_SB(inode->i_sb).attr_tree); 169 break; 170 } 171 return ret; 172} 173 174static void hfsplus_clear_inode(struct inode *inode) 175{ 176 dprint(DBG_INODE, "hfsplus_clear_inode: %lu\n", inode->i_ino); 177 if (HFSPLUS_IS_RSRC(inode)) { 178 HFSPLUS_I(HFSPLUS_I(inode).rsrc_inode).rsrc_inode = NULL; 179 iput(HFSPLUS_I(inode).rsrc_inode); 180 } 181} 182 183static void hfsplus_write_super(struct super_block *sb) 184{ 185 struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; 186 hfsplus_handle_t hfsplus_handle; 187 188 dprint(DBG_SUPER, "hfsplus_write_super\n"); 189 sb->s_dirt = 0; 190 if (sb->s_flags & MS_RDONLY) 191 /* warn? */ 192 return; 193 194 if (hfsplus_journal_start(__FUNCTION__, sb, &hfsplus_handle)) 195 return; 196 197 vhdr->free_blocks = cpu_to_be32(HFSPLUS_SB(sb).free_blocks); 198 vhdr->next_alloc = cpu_to_be32(HFSPLUS_SB(sb).next_alloc); 199 vhdr->next_cnid = cpu_to_be32(HFSPLUS_SB(sb).next_cnid); 200 vhdr->folder_count = cpu_to_be32(HFSPLUS_SB(sb).folder_count); 201 vhdr->file_count = cpu_to_be32(HFSPLUS_SB(sb).file_count); 202 203 if (hfsplus_handle.journaled == HFSPLUS_JOURNAL_PRESENT) { 204 int err; 205 206 BUG_ON(!buffer_mapped(HFSPLUS_SB(sb).s_vhbh)); 207 208 err = hfsplus_journal_get_write_access(__FUNCTION__, &hfsplus_handle, HFSPLUS_SB(sb).s_vhbh); 209 if (err) { 210 printk(KERN_ERR "%s: Error in journal_get_write_access\n", __FUNCTION__); 211 goto write_super_out; 212 } 213 err = hfsplus_jbd_dirty_metadata(hfsplus_handle.handle, HFSPLUS_SB(sb).s_vhbh); 214 if (err) { 215 printk(KERN_ERR "%s: Error in hfsplus_jbd_dirty_metadata\n", __FUNCTION__); 216 goto write_super_out; 217 } 218 } 219 else 220 mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh); 221 if (HFSPLUS_SB(sb).flags & HFSPLUS_SB_WRITEBACKUP) { 222 if (HFSPLUS_SB(sb).sect_count) { 223 struct buffer_head *bh; 224 u32 block, offset; 225 226 block = HFSPLUS_SB(sb).blockoffset; 227 block += (HFSPLUS_SB(sb).sect_count - 2) >> (sb->s_blocksize_bits - 9); 228 offset = ((HFSPLUS_SB(sb).sect_count - 2) << 9) & (sb->s_blocksize - 1); 229 printk("backup: %u,%u,%u,%u\n", HFSPLUS_SB(sb).blockoffset, 230 HFSPLUS_SB(sb).sect_count, block, offset); 231 bh = sb_bread(sb, block); 232 if (bh) { 233 vhdr = (struct hfsplus_vh *)(bh->b_data + offset); 234 if (be16_to_cpu(vhdr->signature) == HFSPLUS_VOLHEAD_SIG) { 235 memcpy(vhdr, HFSPLUS_SB(sb).s_vhdr, sizeof(*vhdr)); 236 if (hfsplus_handle.journaled == HFSPLUS_JOURNAL_PRESENT) 237 hfsplus_jbd_dirty_metadata(hfsplus_handle.handle, bh); 238 else 239 mark_buffer_dirty(bh); 240 brelse(bh); 241 } else 242 printk("backup not found!\n"); 243 } 244 } 245 HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP; 246 } 247write_super_out: 248 hfsplus_journal_stop(&hfsplus_handle); 249} 250 251static void hfsplus_put_super(struct super_block *sb) 252{ 253 dprint(DBG_SUPER, "hfsplus_put_super\n"); 254 if (!sb->s_fs_info) 255 return; 256 hfsplus_journalled_deinit(sb); 257 if (!(sb->s_flags & MS_RDONLY) && HFSPLUS_SB(sb).s_vhdr) { 258 struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; 259 260 vhdr->modify_date = hfsp_now2mt(); 261 vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT); 262 vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT); 263 mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh); 264 sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh); 265 } 266 267 hfs_btree_close(HFSPLUS_SB(sb).cat_tree); 268 hfs_btree_close(HFSPLUS_SB(sb).ext_tree); 269 iput(HFSPLUS_SB(sb).alloc_file); 270 iput(HFSPLUS_SB(sb).hidden_dir); 271 if (HFSPLUS_SB(sb).s_vhbh) 272 brelse(HFSPLUS_SB(sb).s_vhbh); 273 if (HFSPLUS_SB(sb).nls) 274 unload_nls(HFSPLUS_SB(sb).nls); 275 kfree(sb->s_fs_info); 276 sb->s_fs_info = NULL; 277} 278 279static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf) 280{ 281 struct super_block *sb = dentry->d_sb; 282 283 buf->f_type = HFSPLUS_SUPER_MAGIC; 284 buf->f_bsize = sb->s_blocksize; 285 buf->f_blocks = HFSPLUS_SB(sb).total_blocks << HFSPLUS_SB(sb).fs_shift; 286 buf->f_bfree = HFSPLUS_SB(sb).free_blocks << HFSPLUS_SB(sb).fs_shift; 287 buf->f_bavail = buf->f_bfree; 288 buf->f_files = 0xFFFFFFFF; 289 buf->f_ffree = 0xFFFFFFFF - HFSPLUS_SB(sb).next_cnid; 290 buf->f_namelen = HFSPLUS_MAX_STRLEN; 291 292 return 0; 293} 294 295static int hfsplus_remount(struct super_block *sb, int *flags, char *data) 296{ 297 if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) 298 return 0; 299 if (!(*flags & MS_RDONLY)) { 300 struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; 301 struct hfsplus_sb_info sbi; 302 303 memset(&sbi, 0, sizeof(struct hfsplus_sb_info)); 304 sbi.nls = HFSPLUS_SB(sb).nls; 305 if (!hfsplus_parse_options(data, &sbi)) 306 return -EINVAL; 307 308 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { 309 printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " 310 "running fsck.hfsplus is recommended.\n"); 311 } else 312 if (sbi.flags & HFSPLUS_SB_FORCE) { 313 /* nothing */ 314 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 315 printk("HFS+-fs: Filesystem is marked locked, leaving read-only.\n"); 316 sb->s_flags |= MS_RDONLY; 317 *flags |= MS_RDONLY; 318 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { 319 if (hfsplus_journalled_check(sb)) { 320 printk("HFS+-fs: Filesystem is marked journaled, leaving read-only.\n"); 321 sb->s_flags |= MS_RDONLY; 322 *flags |= MS_RDONLY; 323 } else 324 printk("HFS+-fs: Able to mount journaled hfsplus volume in read-write mode\n"); 325 } 326 } 327 return 0; 328} 329 330static const struct super_operations hfsplus_sops = { 331 .alloc_inode = hfsplus_alloc_inode, 332 .destroy_inode = hfsplus_destroy_inode, 333 .read_inode = hfsplus_read_inode, 334 .write_inode = hfsplus_write_inode, 335 .clear_inode = hfsplus_clear_inode, 336 .put_super = hfsplus_put_super, 337 .write_super = hfsplus_write_super, 338 .statfs = hfsplus_statfs, 339 .remount_fs = hfsplus_remount, 340 .show_options = hfsplus_show_options, 341}; 342 343static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) 344{ 345 struct hfsplus_vh *vhdr; 346 struct hfsplus_sb_info *sbi; 347 hfsplus_cat_entry entry; 348 struct hfs_find_data fd; 349 struct inode *root; 350 struct qstr str; 351 struct nls_table *nls = NULL; 352 hfsplus_handle_t hfsplus_handle; 353 int err = -EINVAL; 354 355 sbi = kmalloc(sizeof(struct hfsplus_sb_info), GFP_KERNEL); 356 if (!sbi) 357 return -ENOMEM; 358 359 memset(sbi, 0, sizeof(HFSPLUS_SB(sb))); 360 sb->s_fs_info = sbi; 361 INIT_HLIST_HEAD(&sbi->rsrc_inodes); 362 hfsplus_fill_defaults(sbi); 363 if (!hfsplus_parse_options(data, sbi)) { 364 printk(KERN_ERR "hfs: unable to parse mount options\n"); 365 err = -EINVAL; 366 goto cleanup; 367 } 368 369 /* temporarily use utf8 to correctly find the hidden dir below */ 370 nls = sbi->nls; 371 sbi->nls = load_nls("utf8"); 372 if (!sbi->nls) { 373 printk(KERN_ERR "hfs: unable to load nls for utf8\n"); 374 err = -EINVAL; 375 goto cleanup; 376 } 377 378 /* Grab the volume header */ 379 if (hfsplus_read_wrapper(sb)) { 380 if (!silent) 381 printk(KERN_WARNING "hfs: unable to find HFS+ superblock\n"); 382 err = -EINVAL; 383 goto cleanup; 384 } 385 vhdr = HFSPLUS_SB(sb).s_vhdr; 386 387 /* Copy parts of the volume header into the superblock */ 388 sb->s_magic = HFSPLUS_VOLHEAD_SIG; 389 if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION || 390 be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) { 391 printk(KERN_ERR "hfs: wrong filesystem version\n"); 392 goto cleanup; 393 } 394 395 hfsplus_journalled_init(sb, vhdr); 396 HFSPLUS_SB(sb).jnl.s_journal = NULL; 397 if (HFSPLUS_SB(sb).jnl.journaled == HFSPLUS_JOURNAL_PRESENT) { 398 if (hfsplus_journalled_check(sb)) { 399 if (!silent) 400 printk("HFS+-fs: Error in journal, use the force option at your own risk, mounting read-only.\n"); 401 if (HFSPLUS_SB(sb).s_vhdr == NULL) { 402 printk("HFS+-fs: Error in Volume Header\n"); 403 goto cleanup; 404 } 405 sb->s_flags |= MS_RDONLY; 406 } else { 407 hfsplus_jbd_t *journal; 408 409 journal = hfsplus_get_dev_journal(sb); 410 if (journal == NULL) { 411 printk("HFS+-fs: Error in getting journal device from JBD layer\n"); 412 sb->s_flags |= MS_RDONLY; 413 } else { 414 int err; 415 err = hfsplus_jbd_load(journal); 416 if (err == 0) { 417 dprint(DBG_JOURNAL, "HFS+-fs: Successfully load journal\n"); 418 HFSPLUS_SB(sb).jnl.s_journal = journal; 419 } else { 420 printk("HFS+-fs: Error in loading journal\n"); 421 hfsplus_jbd_destroy(journal); 422 sb->s_flags |= MS_RDONLY; 423 } 424 } 425 if (sb->s_flags & MS_RDONLY) 426 printk("HFS+-fs: Error in journal, mounting read-only.\n"); 427 else 428 dprint(DBG_JOURNAL, "HFS+-fs: No problem in journal. Should be able to mount hfsplus volume in read-write mode\n"); 429 } 430 } 431 432 HFSPLUS_SB(sb).total_blocks = be32_to_cpu(vhdr->total_blocks); 433 HFSPLUS_SB(sb).free_blocks = be32_to_cpu(vhdr->free_blocks); 434 HFSPLUS_SB(sb).next_alloc = be32_to_cpu(vhdr->next_alloc); 435 HFSPLUS_SB(sb).next_cnid = be32_to_cpu(vhdr->next_cnid); 436 HFSPLUS_SB(sb).file_count = be32_to_cpu(vhdr->file_count); 437 HFSPLUS_SB(sb).folder_count = be32_to_cpu(vhdr->folder_count); 438 HFSPLUS_SB(sb).data_clump_blocks = be32_to_cpu(vhdr->data_clump_sz) >> HFSPLUS_SB(sb).alloc_blksz_shift; 439 if (!HFSPLUS_SB(sb).data_clump_blocks) 440 HFSPLUS_SB(sb).data_clump_blocks = 1; 441 HFSPLUS_SB(sb).rsrc_clump_blocks = be32_to_cpu(vhdr->rsrc_clump_sz) >> HFSPLUS_SB(sb).alloc_blksz_shift; 442 if (!HFSPLUS_SB(sb).rsrc_clump_blocks) 443 HFSPLUS_SB(sb).rsrc_clump_blocks = 1; 444 445 /* Set up operations so we can load metadata */ 446 sb->s_op = &hfsplus_sops; 447 sb->s_maxbytes = MAX_LFS_FILESIZE; 448 449 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { 450 printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, " 451 "running fsck.hfsplus is recommended. mounting read-only.\n"); 452 /* Foxconn removed start pling 05/31/2010 */ 453 /* Ignore this flag to force writeable */ 454#if 0 455 sb->s_flags |= MS_RDONLY; 456#endif 457 /* Foxconn removed end pling 05/31/2010 */ 458 } else if (sbi->flags & HFSPLUS_SB_FORCE) { 459 /* nothing */ 460 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 461 printk("HFS+-fs: Filesystem is marked locked, mounting read-only.\n"); 462 sb->s_flags |= MS_RDONLY; 463 } 464 sbi->flags &= ~HFSPLUS_SB_FORCE; 465 466 /* Load metadata objects (B*Trees) */ 467 HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); 468 if (!HFSPLUS_SB(sb).ext_tree) { 469 printk(KERN_ERR "hfs: failed to load extents file\n"); 470 goto cleanup; 471 } 472 HFSPLUS_SB(sb).cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID); 473 if (!HFSPLUS_SB(sb).cat_tree) { 474 printk(KERN_ERR "hfs: failed to load catalog file\n"); 475 goto cleanup; 476 } 477 478 HFSPLUS_SB(sb).alloc_file = iget(sb, HFSPLUS_ALLOC_CNID); 479 if (!HFSPLUS_SB(sb).alloc_file) { 480 printk(KERN_ERR "hfs: failed to load allocation file\n"); 481 goto cleanup; 482 } 483 484 /* Load the root directory */ 485 root = iget(sb, HFSPLUS_ROOT_CNID); 486 sb->s_root = d_alloc_root(root); 487 if (!sb->s_root) { 488 printk(KERN_ERR "hfs: failed to load root directory\n"); 489 iput(root); 490 goto cleanup; 491 } 492 493 str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; 494 str.name = HFSP_HIDDENDIR_NAME; 495 hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); 496 hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str); 497 if (hfsplus_journal_start(__FUNCTION__, sb, &hfsplus_handle)) 498 goto cleanup; 499 if (!hfs_brec_read(&hfsplus_handle, &fd, &entry, sizeof(entry))) { 500 hfs_find_exit(&hfsplus_handle, &fd); 501 if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) { 502 hfsplus_journal_stop(&hfsplus_handle); 503 goto cleanup; 504 } 505 HFSPLUS_SB(sb).hidden_dir = iget(sb, be32_to_cpu(entry.folder.id)); 506 if (!HFSPLUS_SB(sb).hidden_dir) { 507 hfsplus_journal_stop(&hfsplus_handle); 508 goto cleanup; 509 } 510 hfsplus_journal_stop(&hfsplus_handle); 511 } else { 512 hfsplus_journal_stop(&hfsplus_handle); 513 hfs_find_exit(NULL, &fd); 514 } 515 516 if (sb->s_flags & MS_RDONLY) 517 goto out; 518 519 /* H+LX == hfsplusutils, H+Lx == this driver, H+lx is unused 520 * all three are registered with Apple for our use 521 */ 522 if (HFSPLUS_SB(sb).jnl.journaled == HFSPLUS_JOURNAL_PRESENT) 523 vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_JOURNALED_VERSION); 524 else 525 vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION); 526 vhdr->modify_date = hfsp_now2mt(); 527 vhdr->write_count = cpu_to_be32(be32_to_cpu(vhdr->write_count) + 1); 528 vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT); 529 vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT); 530 mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh); 531 sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh); 532 533 if (!HFSPLUS_SB(sb).hidden_dir) { 534 printk("HFS+: create hidden dir...\n"); 535 536 if (hfsplus_journal_start(__FUNCTION__, sb, &hfsplus_handle)) 537 goto out; 538 HFSPLUS_SB(sb).hidden_dir = hfsplus_new_inode(&hfsplus_handle, sb, S_IFDIR); 539 hfsplus_create_cat(&hfsplus_handle, HFSPLUS_SB(sb).hidden_dir->i_ino, sb->s_root->d_inode, 540 &str, HFSPLUS_SB(sb).hidden_dir); 541 hfsplus_journalled_mark_inode_dirty(__FUNCTION__, &hfsplus_handle, HFSPLUS_SB(sb).hidden_dir); 542 hfsplus_journal_stop(&hfsplus_handle); 543 } 544out: 545 unload_nls(sbi->nls); 546 sbi->nls = nls; 547 return 0; 548 549cleanup: 550 if (HFSPLUS_SB(sb).jnl.s_journal != NULL) 551 HFSPLUS_SB(sb).jnl.s_journal->j_flags |= JFS_ABORT; 552 hfsplus_put_super(sb); 553 if (nls) 554 unload_nls(nls); 555 return err; 556} 557 558MODULE_AUTHOR("Brad Boyer"); 559MODULE_DESCRIPTION("Extended Macintosh Filesystem"); 560MODULE_LICENSE("GPL"); 561 562static struct kmem_cache *hfsplus_inode_cachep; 563 564static struct inode *hfsplus_alloc_inode(struct super_block *sb) 565{ 566 struct hfsplus_inode_info *i; 567 568 i = kmem_cache_alloc(hfsplus_inode_cachep, GFP_KERNEL); 569 return i ? &i->vfs_inode : NULL; 570} 571 572static void hfsplus_destroy_inode(struct inode *inode) 573{ 574 kmem_cache_free(hfsplus_inode_cachep, &HFSPLUS_I(inode)); 575} 576 577#define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info) 578 579static int hfsplus_get_sb(struct file_system_type *fs_type, 580 int flags, const char *dev_name, void *data, 581 struct vfsmount *mnt) 582{ 583 return get_sb_bdev(fs_type, flags, dev_name, data, hfsplus_fill_super, 584 mnt); 585} 586 587static struct file_system_type hfsplus_fs_type = { 588 .owner = THIS_MODULE, 589 .name = "hfsplus", 590 .get_sb = hfsplus_get_sb, 591 .kill_sb = kill_block_super, 592 .fs_flags = FS_REQUIRES_DEV, 593}; 594 595static void hfsplus_init_once(void *p, struct kmem_cache *cachep, unsigned long flags) 596{ 597 struct hfsplus_inode_info *i = p; 598 599 inode_init_once(&i->vfs_inode); 600} 601 602static int __init init_hfsplus_fs(void) 603{ 604 int err; 605 606 hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache", 607 HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN, 608 hfsplus_init_once, NULL); 609 if (!hfsplus_inode_cachep) 610 return -ENOMEM; 611 err = hfsplus_jbd_init(); 612 if (err) { 613 printk(KERN_ERR "Error in initializing hfsplus-jbd caches\n"); 614 kmem_cache_destroy(hfsplus_inode_cachep); 615 return -ENOMEM; 616 } 617 err = register_filesystem(&hfsplus_fs_type); 618 if (err) { 619 hfsplus_jbd_exit(); 620 kmem_cache_destroy(hfsplus_inode_cachep); 621 } 622 return err; 623} 624 625static void __exit exit_hfsplus_fs(void) 626{ 627 unregister_filesystem(&hfsplus_fs_type); 628 hfsplus_jbd_exit(); 629 kmem_cache_destroy(hfsplus_inode_cachep); 630} 631 632module_init(init_hfsplus_fs) 633module_exit(exit_hfsplus_fs) 634