diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2005-06-25 10:28:56 -0400 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2005-06-25 10:28:56 -0400 |
commit | 3f2faef00c6af17542ea8672ed7d09367222b2d0 (patch) | |
tree | 8b5cf2d76f2af684988d79b04e21ae92aaea8711 /fs/ntfs/super.c | |
parent | 38b22b6e9f46ab8f73ef5734f0e0a000766a9258 (diff) |
NTFS: Stamp the transaction log ($UsnJrnl), aka user space journal, if it
is active on the volume and we are mounting read-write or remounting
from read-only to read-write.
Signed-off-by: Anton Altaparmakov <aia21@cantab.net>
Diffstat (limited to 'fs/ntfs/super.c')
-rw-r--r-- | fs/ntfs/super.c | 254 |
1 files changed, 251 insertions, 3 deletions
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 455cbe0a6296..92e1d28219b3 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "sysctl.h" | 34 | #include "sysctl.h" |
35 | #include "logfile.h" | 35 | #include "logfile.h" |
36 | #include "quota.h" | 36 | #include "quota.h" |
37 | #include "usnjrnl.h" | ||
37 | #include "dir.h" | 38 | #include "dir.h" |
38 | #include "debug.h" | 39 | #include "debug.h" |
39 | #include "index.h" | 40 | #include "index.h" |
@@ -497,6 +498,12 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) | |||
497 | NVolSetErrors(vol); | 498 | NVolSetErrors(vol); |
498 | return -EROFS; | 499 | return -EROFS; |
499 | } | 500 | } |
501 | if (!ntfs_stamp_usnjrnl(vol)) { | ||
502 | ntfs_error(sb, "Failed to stamp transation log " | ||
503 | "($UsnJrnl)%s", es); | ||
504 | NVolSetErrors(vol); | ||
505 | return -EROFS; | ||
506 | } | ||
500 | } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) { | 507 | } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) { |
501 | /* Remounting read-only. */ | 508 | /* Remounting read-only. */ |
502 | if (!NVolErrors(vol)) { | 509 | if (!NVolErrors(vol)) { |
@@ -1219,6 +1226,167 @@ static BOOL load_and_init_quota(ntfs_volume *vol) | |||
1219 | } | 1226 | } |
1220 | 1227 | ||
1221 | /** | 1228 | /** |
1229 | * load_and_init_usnjrnl - load and setup the transaction log if present | ||
1230 | * @vol: ntfs super block describing device whose usnjrnl file to load | ||
1231 | * | ||
1232 | * Return TRUE on success or FALSE on error. | ||
1233 | * | ||
1234 | * If $UsnJrnl is not present or in the process of being disabled, we set | ||
1235 | * NVolUsnJrnlStamped() and return success. | ||
1236 | * | ||
1237 | * If the $UsnJrnl $DATA/$J attribute has a size equal to the lowest valid usn, | ||
1238 | * i.e. transaction logging has only just been enabled or the journal has been | ||
1239 | * stamped and nothing has been logged since, we also set NVolUsnJrnlStamped() | ||
1240 | * and return success. | ||
1241 | */ | ||
1242 | static BOOL load_and_init_usnjrnl(ntfs_volume *vol) | ||
1243 | { | ||
1244 | MFT_REF mref; | ||
1245 | struct inode *tmp_ino; | ||
1246 | ntfs_inode *tmp_ni; | ||
1247 | struct page *page; | ||
1248 | ntfs_name *name = NULL; | ||
1249 | USN_HEADER *uh; | ||
1250 | static const ntfschar UsnJrnl[9] = { const_cpu_to_le16('$'), | ||
1251 | const_cpu_to_le16('U'), const_cpu_to_le16('s'), | ||
1252 | const_cpu_to_le16('n'), const_cpu_to_le16('J'), | ||
1253 | const_cpu_to_le16('r'), const_cpu_to_le16('n'), | ||
1254 | const_cpu_to_le16('l'), 0 }; | ||
1255 | static ntfschar Max[5] = { const_cpu_to_le16('$'), | ||
1256 | const_cpu_to_le16('M'), const_cpu_to_le16('a'), | ||
1257 | const_cpu_to_le16('x'), 0 }; | ||
1258 | static ntfschar J[3] = { const_cpu_to_le16('$'), | ||
1259 | const_cpu_to_le16('J'), 0 }; | ||
1260 | |||
1261 | ntfs_debug("Entering."); | ||
1262 | /* | ||
1263 | * Find the inode number for the transaction log file by looking up the | ||
1264 | * filename $UsnJrnl in the extended system files directory $Extend. | ||
1265 | */ | ||
1266 | down(&vol->extend_ino->i_sem); | ||
1267 | mref = ntfs_lookup_inode_by_name(NTFS_I(vol->extend_ino), UsnJrnl, 8, | ||
1268 | &name); | ||
1269 | up(&vol->extend_ino->i_sem); | ||
1270 | if (IS_ERR_MREF(mref)) { | ||
1271 | /* | ||
1272 | * If the file does not exist, transaction logging is disabled, | ||
1273 | * just return success. | ||
1274 | */ | ||
1275 | if (MREF_ERR(mref) == -ENOENT) { | ||
1276 | ntfs_debug("$UsnJrnl not present. Volume does not " | ||
1277 | "have transaction logging enabled."); | ||
1278 | not_enabled: | ||
1279 | /* | ||
1280 | * No need to try to stamp the transaction log if | ||
1281 | * transaction logging is not enabled. | ||
1282 | */ | ||
1283 | NVolSetUsnJrnlStamped(vol); | ||
1284 | return TRUE; | ||
1285 | } | ||
1286 | /* A real error occured. */ | ||
1287 | ntfs_error(vol->sb, "Failed to find inode number for " | ||
1288 | "$UsnJrnl."); | ||
1289 | return FALSE; | ||
1290 | } | ||
1291 | /* We do not care for the type of match that was found. */ | ||
1292 | kfree(name); | ||
1293 | /* Get the inode. */ | ||
1294 | tmp_ino = ntfs_iget(vol->sb, MREF(mref)); | ||
1295 | if (unlikely(IS_ERR(tmp_ino) || is_bad_inode(tmp_ino))) { | ||
1296 | if (!IS_ERR(tmp_ino)) | ||
1297 | iput(tmp_ino); | ||
1298 | ntfs_error(vol->sb, "Failed to load $UsnJrnl."); | ||
1299 | return FALSE; | ||
1300 | } | ||
1301 | vol->usnjrnl_ino = tmp_ino; | ||
1302 | /* | ||
1303 | * If the transaction log is in the process of being deleted, we can | ||
1304 | * ignore it. | ||
1305 | */ | ||
1306 | if (unlikely(vol->vol_flags & VOLUME_DELETE_USN_UNDERWAY)) { | ||
1307 | ntfs_debug("$UsnJrnl in the process of being disabled. " | ||
1308 | "Volume does not have transaction logging " | ||
1309 | "enabled."); | ||
1310 | goto not_enabled; | ||
1311 | } | ||
1312 | /* Get the $DATA/$Max attribute. */ | ||
1313 | tmp_ino = ntfs_attr_iget(vol->usnjrnl_ino, AT_DATA, Max, 4); | ||
1314 | if (IS_ERR(tmp_ino)) { | ||
1315 | ntfs_error(vol->sb, "Failed to load $UsnJrnl/$DATA/$Max " | ||
1316 | "attribute."); | ||
1317 | return FALSE; | ||
1318 | } | ||
1319 | vol->usnjrnl_max_ino = tmp_ino; | ||
1320 | if (unlikely(i_size_read(tmp_ino) < sizeof(USN_HEADER))) { | ||
1321 | ntfs_error(vol->sb, "Found corrupt $UsnJrnl/$DATA/$Max " | ||
1322 | "attribute (size is 0x%llx but should be at " | ||
1323 | "least 0x%x bytes).", i_size_read(tmp_ino), | ||
1324 | sizeof(USN_HEADER)); | ||
1325 | return FALSE; | ||
1326 | } | ||
1327 | /* Get the $DATA/$J attribute. */ | ||
1328 | tmp_ino = ntfs_attr_iget(vol->usnjrnl_ino, AT_DATA, J, 2); | ||
1329 | if (IS_ERR(tmp_ino)) { | ||
1330 | ntfs_error(vol->sb, "Failed to load $UsnJrnl/$DATA/$J " | ||
1331 | "attribute."); | ||
1332 | return FALSE; | ||
1333 | } | ||
1334 | vol->usnjrnl_j_ino = tmp_ino; | ||
1335 | /* Verify $J is non-resident and sparse. */ | ||
1336 | tmp_ni = NTFS_I(vol->usnjrnl_j_ino); | ||
1337 | if (unlikely(!NInoNonResident(tmp_ni) || !NInoSparse(tmp_ni))) { | ||
1338 | ntfs_error(vol->sb, "$UsnJrnl/$DATA/$J attribute is resident " | ||
1339 | "and/or not sparse."); | ||
1340 | return FALSE; | ||
1341 | } | ||
1342 | /* Read the USN_HEADER from $DATA/$Max. */ | ||
1343 | page = ntfs_map_page(vol->usnjrnl_max_ino->i_mapping, 0); | ||
1344 | if (IS_ERR(page)) { | ||
1345 | ntfs_error(vol->sb, "Failed to read from $UsnJrnl/$DATA/$Max " | ||
1346 | "attribute."); | ||
1347 | return FALSE; | ||
1348 | } | ||
1349 | uh = (USN_HEADER*)page_address(page); | ||
1350 | /* Sanity check the $Max. */ | ||
1351 | if (unlikely(sle64_to_cpu(uh->allocation_delta) > | ||
1352 | sle64_to_cpu(uh->maximum_size))) { | ||
1353 | ntfs_error(vol->sb, "Allocation delta (0x%llx) exceeds " | ||
1354 | "maximum size (0x%llx). $UsnJrnl is corrupt.", | ||
1355 | (long long)sle64_to_cpu(uh->allocation_delta), | ||
1356 | (long long)sle64_to_cpu(uh->maximum_size)); | ||
1357 | ntfs_unmap_page(page); | ||
1358 | return FALSE; | ||
1359 | } | ||
1360 | /* | ||
1361 | * If the transaction log has been stamped and nothing has been written | ||
1362 | * to it since, we do not need to stamp it. | ||
1363 | */ | ||
1364 | if (unlikely(sle64_to_cpu(uh->lowest_valid_usn) >= | ||
1365 | i_size_read(vol->usnjrnl_j_ino))) { | ||
1366 | if (likely(sle64_to_cpu(uh->lowest_valid_usn) == | ||
1367 | i_size_read(vol->usnjrnl_j_ino))) { | ||
1368 | ntfs_unmap_page(page); | ||
1369 | ntfs_debug("$UsnJrnl is enabled but nothing has been " | ||
1370 | "logged since it was last stamped. " | ||
1371 | "Treating this as if the volume does " | ||
1372 | "not have transaction logging " | ||
1373 | "enabled."); | ||
1374 | goto not_enabled; | ||
1375 | } | ||
1376 | ntfs_error(vol->sb, "$UsnJrnl has lowest valid usn (0x%llx) " | ||
1377 | "which is out of bounds (0x%llx). $UsnJrnl " | ||
1378 | "is corrupt.", | ||
1379 | (long long)sle64_to_cpu(uh->lowest_valid_usn), | ||
1380 | i_size_read(vol->usnjrnl_j_ino)); | ||
1381 | ntfs_unmap_page(page); | ||
1382 | return FALSE; | ||
1383 | } | ||
1384 | ntfs_unmap_page(page); | ||
1385 | ntfs_debug("Done."); | ||
1386 | return TRUE; | ||
1387 | } | ||
1388 | |||
1389 | /** | ||
1222 | * load_and_init_attrdef - load the attribute definitions table for a volume | 1390 | * load_and_init_attrdef - load the attribute definitions table for a volume |
1223 | * @vol: ntfs super block describing device whose attrdef to load | 1391 | * @vol: ntfs super block describing device whose attrdef to load |
1224 | * | 1392 | * |
@@ -1653,7 +1821,7 @@ get_ctx_vol_failed: | |||
1653 | goto iput_logfile_err_out; | 1821 | goto iput_logfile_err_out; |
1654 | } | 1822 | } |
1655 | /* If on NTFS versions before 3.0, we are done. */ | 1823 | /* If on NTFS versions before 3.0, we are done. */ |
1656 | if (vol->major_ver < 3) | 1824 | if (unlikely(vol->major_ver < 3)) |
1657 | return TRUE; | 1825 | return TRUE; |
1658 | /* NTFS 3.0+ specific initialization. */ | 1826 | /* NTFS 3.0+ specific initialization. */ |
1659 | /* Get the security descriptors inode. */ | 1827 | /* Get the security descriptors inode. */ |
@@ -1664,7 +1832,7 @@ get_ctx_vol_failed: | |||
1664 | ntfs_error(sb, "Failed to load $Secure."); | 1832 | ntfs_error(sb, "Failed to load $Secure."); |
1665 | goto iput_root_err_out; | 1833 | goto iput_root_err_out; |
1666 | } | 1834 | } |
1667 | // FIXME: Initialize security. | 1835 | // TODO: Initialize security. |
1668 | /* Get the extended system files' directory inode. */ | 1836 | /* Get the extended system files' directory inode. */ |
1669 | vol->extend_ino = ntfs_iget(sb, FILE_Extend); | 1837 | vol->extend_ino = ntfs_iget(sb, FILE_Extend); |
1670 | if (IS_ERR(vol->extend_ino) || is_bad_inode(vol->extend_ino)) { | 1838 | if (IS_ERR(vol->extend_ino) || is_bad_inode(vol->extend_ino)) { |
@@ -1715,10 +1883,60 @@ get_ctx_vol_failed: | |||
1715 | sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; | 1883 | sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; |
1716 | NVolSetErrors(vol); | 1884 | NVolSetErrors(vol); |
1717 | } | 1885 | } |
1718 | // TODO: Delete or checkpoint the $UsnJrnl if it exists. | 1886 | /* |
1887 | * Find the transaction log file ($UsnJrnl), load it if present, check | ||
1888 | * it, and set it up. | ||
1889 | */ | ||
1890 | if (!load_and_init_usnjrnl(vol)) { | ||
1891 | static const char *es1 = "Failed to load $UsnJrnl"; | ||
1892 | static const char *es2 = ". Run chkdsk."; | ||
1893 | |||
1894 | /* If a read-write mount, convert it to a read-only mount. */ | ||
1895 | if (!(sb->s_flags & MS_RDONLY)) { | ||
1896 | if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | | ||
1897 | ON_ERRORS_CONTINUE))) { | ||
1898 | ntfs_error(sb, "%s and neither on_errors=" | ||
1899 | "continue nor on_errors=" | ||
1900 | "remount-ro was specified%s", | ||
1901 | es1, es2); | ||
1902 | goto iput_usnjrnl_err_out; | ||
1903 | } | ||
1904 | sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; | ||
1905 | ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); | ||
1906 | } else | ||
1907 | ntfs_warning(sb, "%s. Will not be able to remount " | ||
1908 | "read-write%s", es1, es2); | ||
1909 | /* This will prevent a read-write remount. */ | ||
1910 | NVolSetErrors(vol); | ||
1911 | } | ||
1912 | /* If (still) a read-write mount, stamp the transaction log. */ | ||
1913 | if (!(sb->s_flags & MS_RDONLY) && !ntfs_stamp_usnjrnl(vol)) { | ||
1914 | static const char *es1 = "Failed to stamp transaction log " | ||
1915 | "($UsnJrnl)"; | ||
1916 | static const char *es2 = ". Run chkdsk."; | ||
1917 | |||
1918 | /* Convert to a read-only mount. */ | ||
1919 | if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | | ||
1920 | ON_ERRORS_CONTINUE))) { | ||
1921 | ntfs_error(sb, "%s and neither on_errors=continue nor " | ||
1922 | "on_errors=remount-ro was specified%s", | ||
1923 | es1, es2); | ||
1924 | goto iput_usnjrnl_err_out; | ||
1925 | } | ||
1926 | ntfs_error(sb, "%s. Mounting read-only%s", es1, es2); | ||
1927 | sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME; | ||
1928 | NVolSetErrors(vol); | ||
1929 | } | ||
1719 | #endif /* NTFS_RW */ | 1930 | #endif /* NTFS_RW */ |
1720 | return TRUE; | 1931 | return TRUE; |
1721 | #ifdef NTFS_RW | 1932 | #ifdef NTFS_RW |
1933 | iput_usnjrnl_err_out: | ||
1934 | if (vol->usnjrnl_j_ino) | ||
1935 | iput(vol->usnjrnl_j_ino); | ||
1936 | if (vol->usnjrnl_max_ino) | ||
1937 | iput(vol->usnjrnl_max_ino); | ||
1938 | if (vol->usnjrnl_ino) | ||
1939 | iput(vol->usnjrnl_ino); | ||
1722 | iput_quota_err_out: | 1940 | iput_quota_err_out: |
1723 | if (vol->quota_q_ino) | 1941 | if (vol->quota_q_ino) |
1724 | iput(vol->quota_q_ino); | 1942 | iput(vol->quota_q_ino); |
@@ -1792,6 +2010,12 @@ static void ntfs_put_super(struct super_block *sb) | |||
1792 | 2010 | ||
1793 | /* NTFS 3.0+ specific. */ | 2011 | /* NTFS 3.0+ specific. */ |
1794 | if (vol->major_ver >= 3) { | 2012 | if (vol->major_ver >= 3) { |
2013 | if (vol->usnjrnl_j_ino) | ||
2014 | ntfs_commit_inode(vol->usnjrnl_j_ino); | ||
2015 | if (vol->usnjrnl_max_ino) | ||
2016 | ntfs_commit_inode(vol->usnjrnl_max_ino); | ||
2017 | if (vol->usnjrnl_ino) | ||
2018 | ntfs_commit_inode(vol->usnjrnl_ino); | ||
1795 | if (vol->quota_q_ino) | 2019 | if (vol->quota_q_ino) |
1796 | ntfs_commit_inode(vol->quota_q_ino); | 2020 | ntfs_commit_inode(vol->quota_q_ino); |
1797 | if (vol->quota_ino) | 2021 | if (vol->quota_ino) |
@@ -1847,6 +2071,18 @@ static void ntfs_put_super(struct super_block *sb) | |||
1847 | /* NTFS 3.0+ specific clean up. */ | 2071 | /* NTFS 3.0+ specific clean up. */ |
1848 | if (vol->major_ver >= 3) { | 2072 | if (vol->major_ver >= 3) { |
1849 | #ifdef NTFS_RW | 2073 | #ifdef NTFS_RW |
2074 | if (vol->usnjrnl_j_ino) { | ||
2075 | iput(vol->usnjrnl_j_ino); | ||
2076 | vol->usnjrnl_j_ino = NULL; | ||
2077 | } | ||
2078 | if (vol->usnjrnl_max_ino) { | ||
2079 | iput(vol->usnjrnl_max_ino); | ||
2080 | vol->usnjrnl_max_ino = NULL; | ||
2081 | } | ||
2082 | if (vol->usnjrnl_ino) { | ||
2083 | iput(vol->usnjrnl_ino); | ||
2084 | vol->usnjrnl_ino = NULL; | ||
2085 | } | ||
1850 | if (vol->quota_q_ino) { | 2086 | if (vol->quota_q_ino) { |
1851 | iput(vol->quota_q_ino); | 2087 | iput(vol->quota_q_ino); |
1852 | vol->quota_q_ino = NULL; | 2088 | vol->quota_q_ino = NULL; |
@@ -2463,6 +2699,18 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) | |||
2463 | /* NTFS 3.0+ specific clean up. */ | 2699 | /* NTFS 3.0+ specific clean up. */ |
2464 | if (vol->major_ver >= 3) { | 2700 | if (vol->major_ver >= 3) { |
2465 | #ifdef NTFS_RW | 2701 | #ifdef NTFS_RW |
2702 | if (vol->usnjrnl_j_ino) { | ||
2703 | iput(vol->usnjrnl_j_ino); | ||
2704 | vol->usnjrnl_j_ino = NULL; | ||
2705 | } | ||
2706 | if (vol->usnjrnl_max_ino) { | ||
2707 | iput(vol->usnjrnl_max_ino); | ||
2708 | vol->usnjrnl_max_ino = NULL; | ||
2709 | } | ||
2710 | if (vol->usnjrnl_ino) { | ||
2711 | iput(vol->usnjrnl_ino); | ||
2712 | vol->usnjrnl_ino = NULL; | ||
2713 | } | ||
2466 | if (vol->quota_q_ino) { | 2714 | if (vol->quota_q_ino) { |
2467 | iput(vol->quota_q_ino); | 2715 | iput(vol->quota_q_ino); |
2468 | vol->quota_q_ino = NULL; | 2716 | vol->quota_q_ino = NULL; |