diff options
author | Eric Sandeen <sandeen@redhat.com> | 2013-08-28 19:05:07 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-08-28 19:05:07 -0400 |
commit | ad4eec613536dc7e5ea0c6e59849e6edca634d8b (patch) | |
tree | 12481650ae957d60cebed50ee142c3cf159cad9a | |
parent | bdfb6ff4a255dcebeb09a901250e13a97eff75af (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.txt | 7 | ||||
-rw-r--r-- | fs/ext4/super.c | 47 |
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 | ||
147 | journal_path=path | ||
147 | journal_dev=devnum When the external journal device's major/minor numbers | 148 | journal_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 | ||
153 | norecovery Don't load the journal on mounting. Note that | 154 | norecovery Don't load the journal on mounting. Note that |
154 | noload if the filesystem was not unmounted cleanly, | 155 | noload 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 | ||
1342 | static const struct mount_opts { | 1344 | static 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" |