aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Sandeen <sandeen@redhat.com>2013-08-28 19:05:07 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-08-28 19:05:07 -0400
commitad4eec613536dc7e5ea0c6e59849e6edca634d8b (patch)
tree12481650ae957d60cebed50ee142c3cf159cad9a
parentbdfb6ff4a255dcebeb09a901250e13a97eff75af (diff)
ext4: allow specifying external journal by pathname mount option
It's always been a hassle that if an external journal's device number changes, the filesystem won't mount. And since boot-time enumeration can change, device number changes aren't unusual. The current mechanism to update the journal location is by passing in a mount option w/ a new devnum, but that's a hassle; it's a manual approach, fixing things after the fact. Adding a mount option, "-o journal_path=/dev/$DEVICE" would help, since then we can do i.e. # mount -o journal_path=/dev/disk/by-label/$JOURNAL_LABEL ... and it'll mount even if the devnum has changed, as shown here: # losetup /dev/loop0 journalfile # mke2fs -L mylabel-journal -O journal_dev /dev/loop0 # mkfs.ext4 -L mylabel -J device=/dev/loop0 /dev/sdb1 Change the journal device number: # losetup -d /dev/loop0 # losetup /dev/loop1 journalfile And today it will fail: # mount /dev/sdb1 /mnt/test mount: wrong fs type, bad option, bad superblock on /dev/sdb1, missing codepage or helper program, or other error In some cases useful info is found in syslog - try dmesg | tail or so # dmesg | tail -n 1 [17343.240702] EXT4-fs (sdb1): error: couldn't read superblock of external journal But with this new mount option, we can specify the new path: # mount -o journal_path=/dev/loop1 /dev/sdb1 /mnt/test # (which does update the encoded device number, incidentally): # umount /dev/sdb1 # dumpe2fs -h /dev/sdb1 | grep "Journal device" dumpe2fs 1.41.12 (17-May-2010) Journal device: 0x0701 But best of all we can just always mount by journal-path, and it'll always work: # mount -o journal_path=/dev/disk/by-label/mylabel-journal /dev/sdb1 /mnt/test # So the journal_path option can be specified in fstab, and as long as the disk is available somewhere, and findable by label (or by UUID), we can mount. Signed-off-by: Eric Sandeen <sandeen@redhat.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Carlos Maiolino <cmaiolino@redhat.com>
-rw-r--r--Documentation/filesystems/ext4.txt7
-rw-r--r--fs/ext4/super.c47
2 files changed, 48 insertions, 6 deletions
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index f7cbf574a875..b91cfaaf6a0f 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -144,11 +144,12 @@ journal_async_commit Commit block can be written to disk without waiting
144 mount the device. This will enable 'journal_checksum' 144 mount the device. This will enable 'journal_checksum'
145 internally. 145 internally.
146 146
147journal_path=path
147journal_dev=devnum When the external journal device's major/minor numbers 148journal_dev=devnum When the external journal device's major/minor numbers
148 have changed, this option allows the user to specify 149 have changed, these options allow the user to specify
149 the new journal location. The journal device is 150 the new journal location. The journal device is
150 identified through its new major/minor numbers encoded 151 identified through either its new major/minor numbers
151 in devnum. 152 encoded in devnum, or via a path to the device.
152 153
153norecovery Don't load the journal on mounting. Note that 154norecovery Don't load the journal on mounting. Note that
154noload if the filesystem was not unmounted cleanly, 155noload if the filesystem was not unmounted cleanly,
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index b59373b625e9..42337141e79f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1134,8 +1134,8 @@ enum {
1134 Opt_nouid32, Opt_debug, Opt_removed, 1134 Opt_nouid32, Opt_debug, Opt_removed,
1135 Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, 1135 Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
1136 Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload, 1136 Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload,
1137 Opt_commit, Opt_min_batch_time, Opt_max_batch_time, 1137 Opt_commit, Opt_min_batch_time, Opt_max_batch_time, Opt_journal_dev,
1138 Opt_journal_dev, Opt_journal_checksum, Opt_journal_async_commit, 1138 Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit,
1139 Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, 1139 Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
1140 Opt_data_err_abort, Opt_data_err_ignore, 1140 Opt_data_err_abort, Opt_data_err_ignore,
1141 Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, 1141 Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
@@ -1179,6 +1179,7 @@ static const match_table_t tokens = {
1179 {Opt_min_batch_time, "min_batch_time=%u"}, 1179 {Opt_min_batch_time, "min_batch_time=%u"},
1180 {Opt_max_batch_time, "max_batch_time=%u"}, 1180 {Opt_max_batch_time, "max_batch_time=%u"},
1181 {Opt_journal_dev, "journal_dev=%u"}, 1181 {Opt_journal_dev, "journal_dev=%u"},
1182 {Opt_journal_path, "journal_path=%s"},
1182 {Opt_journal_checksum, "journal_checksum"}, 1183 {Opt_journal_checksum, "journal_checksum"},
1183 {Opt_journal_async_commit, "journal_async_commit"}, 1184 {Opt_journal_async_commit, "journal_async_commit"},
1184 {Opt_abort, "abort"}, 1185 {Opt_abort, "abort"},
@@ -1338,6 +1339,7 @@ static int clear_qf_name(struct super_block *sb, int qtype)
1338#define MOPT_NO_EXT2 0x0100 1339#define MOPT_NO_EXT2 0x0100
1339#define MOPT_NO_EXT3 0x0200 1340#define MOPT_NO_EXT3 0x0200
1340#define MOPT_EXT4_ONLY (MOPT_NO_EXT2 | MOPT_NO_EXT3) 1341#define MOPT_EXT4_ONLY (MOPT_NO_EXT2 | MOPT_NO_EXT3)
1342#define MOPT_STRING 0x0400
1341 1343
1342static const struct mount_opts { 1344static const struct mount_opts {
1343 int token; 1345 int token;
@@ -1387,6 +1389,7 @@ static const struct mount_opts {
1387 {Opt_resuid, 0, MOPT_GTE0}, 1389 {Opt_resuid, 0, MOPT_GTE0},
1388 {Opt_resgid, 0, MOPT_GTE0}, 1390 {Opt_resgid, 0, MOPT_GTE0},
1389 {Opt_journal_dev, 0, MOPT_GTE0}, 1391 {Opt_journal_dev, 0, MOPT_GTE0},
1392 {Opt_journal_path, 0, MOPT_STRING},
1390 {Opt_journal_ioprio, 0, MOPT_GTE0}, 1393 {Opt_journal_ioprio, 0, MOPT_GTE0},
1391 {Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_NO_EXT2 | MOPT_DATAJ}, 1394 {Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_NO_EXT2 | MOPT_DATAJ},
1392 {Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_NO_EXT2 | MOPT_DATAJ}, 1395 {Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_NO_EXT2 | MOPT_DATAJ},
@@ -1480,7 +1483,7 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
1480 return -1; 1483 return -1;
1481 } 1484 }
1482 1485
1483 if (args->from && match_int(args, &arg)) 1486 if (args->from && !(m->flags & MOPT_STRING) && match_int(args, &arg))
1484 return -1; 1487 return -1;
1485 if (args->from && (m->flags & MOPT_GTE0) && (arg < 0)) 1488 if (args->from && (m->flags & MOPT_GTE0) && (arg < 0))
1486 return -1; 1489 return -1;
@@ -1544,6 +1547,44 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
1544 return -1; 1547 return -1;
1545 } 1548 }
1546 *journal_devnum = arg; 1549 *journal_devnum = arg;
1550 } else if (token == Opt_journal_path) {
1551 char *journal_path;
1552 struct inode *journal_inode;
1553 struct path path;
1554 int error;
1555
1556 if (is_remount) {
1557 ext4_msg(sb, KERN_ERR,
1558 "Cannot specify journal on remount");
1559 return -1;
1560 }
1561 journal_path = match_strdup(&args[0]);
1562 if (!journal_path) {
1563 ext4_msg(sb, KERN_ERR, "error: could not dup "
1564 "journal device string");
1565 return -1;
1566 }
1567
1568 error = kern_path(journal_path, LOOKUP_FOLLOW, &path);
1569 if (error) {
1570 ext4_msg(sb, KERN_ERR, "error: could not find "
1571 "journal device path: error %d", error);
1572 kfree(journal_path);
1573 return -1;
1574 }
1575
1576 journal_inode = path.dentry->d_inode;
1577 if (!S_ISBLK(journal_inode->i_mode)) {
1578 ext4_msg(sb, KERN_ERR, "error: journal path %s "
1579 "is not a block device", journal_path);
1580 path_put(&path);
1581 kfree(journal_path);
1582 return -1;
1583 }
1584
1585 *journal_devnum = new_encode_dev(journal_inode->i_rdev);
1586 path_put(&path);
1587 kfree(journal_path);
1547 } else if (token == Opt_journal_ioprio) { 1588 } else if (token == Opt_journal_ioprio) {
1548 if (arg > 7) { 1589 if (arg > 7) {
1549 ext4_msg(sb, KERN_ERR, "Invalid journal IO priority" 1590 ext4_msg(sb, KERN_ERR, "Invalid journal IO priority"