[PATCH] hfsplus: don't modify journaled volume

Access to a journaled HFS+ volume is not officially supported under Linux, so
mount such a volume read-only, but users can override this behaviour using the
"force" mount option.

The minimum requirement to relax this check is to at least check that the
journal is empty and so nothing needs to be replayed to make sure the volume
is consistent.

Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Roman Zippel and committed by Linus Torvalds b0b623c3 576f6d79

+33 -6
+1
fs/hfsplus/hfsplus_fs.h
··· 151 152 #define HFSPLUS_SB_WRITEBACKUP 0x0001 153 #define HFSPLUS_SB_NODECOMPOSE 0x0002 154 155 156 struct hfsplus_inode_info {
··· 151 152 #define HFSPLUS_SB_WRITEBACKUP 0x0001 153 #define HFSPLUS_SB_NODECOMPOSE 0x0002 154 + #define HFSPLUS_SB_FORCE 0x0004 155 156 157 struct hfsplus_inode_info {
+7 -5
fs/hfsplus/hfsplus_raw.h
··· 123 } __packed; 124 125 /* HFS+ volume attributes */ 126 - #define HFSPLUS_VOL_UNMNT (1 << 8) 127 - #define HFSPLUS_VOL_SPARE_BLK (1 << 9) 128 - #define HFSPLUS_VOL_NOCACHE (1 << 10) 129 - #define HFSPLUS_VOL_INCNSTNT (1 << 11) 130 - #define HFSPLUS_VOL_SOFTLOCK (1 << 15) 131 132 /* HFS+ BTree node descriptor */ 133 struct hfs_bnode_desc {
··· 123 } __packed; 124 125 /* HFS+ volume attributes */ 126 + #define HFSPLUS_VOL_UNMNT (1 << 8) 127 + #define HFSPLUS_VOL_SPARE_BLK (1 << 9) 128 + #define HFSPLUS_VOL_NOCACHE (1 << 10) 129 + #define HFSPLUS_VOL_INCNSTNT (1 << 11) 130 + #define HFSPLUS_VOL_NODEID_REUSED (1 << 12) 131 + #define HFSPLUS_VOL_JOURNALED (1 << 13) 132 + #define HFSPLUS_VOL_SOFTLOCK (1 << 15) 133 134 /* HFS+ BTree node descriptor */ 135 struct hfs_bnode_desc {
+5 -1
fs/hfsplus/options.c
··· 22 opt_umask, opt_uid, opt_gid, 23 opt_part, opt_session, opt_nls, 24 opt_nodecompose, opt_decompose, 25 - opt_err 26 }; 27 28 static match_table_t tokens = { ··· 36 { opt_nls, "nls=%s" }, 37 { opt_decompose, "decompose" }, 38 { opt_nodecompose, "nodecompose" }, 39 { opt_err, NULL } 40 }; 41 ··· 145 break; 146 case opt_nodecompose: 147 sbi->flags |= HFSPLUS_SB_NODECOMPOSE; 148 break; 149 default: 150 return 0;
··· 22 opt_umask, opt_uid, opt_gid, 23 opt_part, opt_session, opt_nls, 24 opt_nodecompose, opt_decompose, 25 + opt_force, opt_err 26 }; 27 28 static match_table_t tokens = { ··· 36 { opt_nls, "nls=%s" }, 37 { opt_decompose, "decompose" }, 38 { opt_nodecompose, "nodecompose" }, 39 + { opt_force, "force" }, 40 { opt_err, NULL } 41 }; 42 ··· 144 break; 145 case opt_nodecompose: 146 sbi->flags |= HFSPLUS_SB_NODECOMPOSE; 147 + break; 148 + case opt_force: 149 + sbi->flags |= HFSPLUS_SB_FORCE; 150 break; 151 default: 152 return 0;
+20
fs/hfsplus/super.c
··· 251 return 0; 252 if (!(*flags & MS_RDONLY)) { 253 struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; 254 255 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { 256 printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " 257 "running fsck.hfsplus is recommended. leaving read-only.\n"); 258 sb->s_flags |= MS_RDONLY; 259 *flags |= MS_RDONLY; 260 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 261 printk("HFS+-fs: Filesystem is marked locked, leaving read-only.\n"); 262 sb->s_flags |= MS_RDONLY; 263 *flags |= MS_RDONLY; 264 } ··· 364 printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " 365 "running fsck.hfsplus is recommended. mounting read-only.\n"); 366 sb->s_flags |= MS_RDONLY; 367 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 368 if (!silent) 369 printk("HFS+-fs: Filesystem is marked locked, mounting read-only.\n"); 370 sb->s_flags |= MS_RDONLY; 371 } 372 373 /* Load metadata objects (B*Trees) */ 374 HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
··· 251 return 0; 252 if (!(*flags & MS_RDONLY)) { 253 struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; 254 + struct hfsplus_sb_info sbi; 255 + 256 + memset(&sbi, 0, sizeof(struct hfsplus_sb_info)); 257 + sbi.nls = HFSPLUS_SB(sb).nls; 258 + if (!hfsplus_parse_options(data, &sbi)) 259 + return -EINVAL; 260 261 if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { 262 printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " 263 "running fsck.hfsplus is recommended. leaving read-only.\n"); 264 sb->s_flags |= MS_RDONLY; 265 *flags |= MS_RDONLY; 266 + } else if (sbi.flags & HFSPLUS_SB_FORCE) { 267 + /* nothing */ 268 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 269 printk("HFS+-fs: Filesystem is marked locked, leaving read-only.\n"); 270 + sb->s_flags |= MS_RDONLY; 271 + *flags |= MS_RDONLY; 272 + } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { 273 + printk("HFS+-fs: Filesystem is marked journaled, leaving read-only.\n"); 274 sb->s_flags |= MS_RDONLY; 275 *flags |= MS_RDONLY; 276 } ··· 352 printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " 353 "running fsck.hfsplus is recommended. mounting read-only.\n"); 354 sb->s_flags |= MS_RDONLY; 355 + } else if (sbi->flags & HFSPLUS_SB_FORCE) { 356 + /* nothing */ 357 } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { 358 if (!silent) 359 printk("HFS+-fs: Filesystem is marked locked, mounting read-only.\n"); 360 sb->s_flags |= MS_RDONLY; 361 + } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { 362 + if (!silent) 363 + printk("HFS+-fs: write access to a jounaled filesystem is not supported, " 364 + "use the force option at your own risk, mounting read-only.\n"); 365 + sb->s_flags |= MS_RDONLY; 366 } 367 + sbi->flags &= ~HFSPLUS_SB_FORCE; 368 369 /* Load metadata objects (B*Trees) */ 370 HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);