diff options
Diffstat (limited to 'fs/xfs/xfs_mount.c')
-rw-r--r-- | fs/xfs/xfs_mount.c | 121 |
1 files changed, 82 insertions, 39 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 6409b3762995..2fec452afbcc 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -43,8 +43,9 @@ | |||
43 | #include "xfs_rw.h" | 43 | #include "xfs_rw.h" |
44 | #include "xfs_quota.h" | 44 | #include "xfs_quota.h" |
45 | #include "xfs_fsops.h" | 45 | #include "xfs_fsops.h" |
46 | #include "xfs_utils.h" | ||
46 | 47 | ||
47 | STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t); | 48 | STATIC int xfs_mount_log_sb(xfs_mount_t *, __int64_t); |
48 | STATIC int xfs_uuid_mount(xfs_mount_t *); | 49 | STATIC int xfs_uuid_mount(xfs_mount_t *); |
49 | STATIC void xfs_uuid_unmount(xfs_mount_t *mp); | 50 | STATIC void xfs_uuid_unmount(xfs_mount_t *mp); |
50 | STATIC void xfs_unmountfs_wait(xfs_mount_t *); | 51 | STATIC void xfs_unmountfs_wait(xfs_mount_t *); |
@@ -57,7 +58,7 @@ STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, | |||
57 | STATIC void xfs_icsb_sync_counters(xfs_mount_t *); | 58 | STATIC void xfs_icsb_sync_counters(xfs_mount_t *); |
58 | STATIC int xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t, | 59 | STATIC int xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t, |
59 | int64_t, int); | 60 | int64_t, int); |
60 | STATIC int xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t); | 61 | STATIC void xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t); |
61 | 62 | ||
62 | #else | 63 | #else |
63 | 64 | ||
@@ -119,6 +120,7 @@ static const struct { | |||
119 | { offsetof(xfs_sb_t, sb_logsectsize),0 }, | 120 | { offsetof(xfs_sb_t, sb_logsectsize),0 }, |
120 | { offsetof(xfs_sb_t, sb_logsunit), 0 }, | 121 | { offsetof(xfs_sb_t, sb_logsunit), 0 }, |
121 | { offsetof(xfs_sb_t, sb_features2), 0 }, | 122 | { offsetof(xfs_sb_t, sb_features2), 0 }, |
123 | { offsetof(xfs_sb_t, sb_bad_features2), 0 }, | ||
122 | { sizeof(xfs_sb_t), 0 } | 124 | { sizeof(xfs_sb_t), 0 } |
123 | }; | 125 | }; |
124 | 126 | ||
@@ -225,7 +227,7 @@ xfs_mount_validate_sb( | |||
225 | return XFS_ERROR(EWRONGFS); | 227 | return XFS_ERROR(EWRONGFS); |
226 | } | 228 | } |
227 | 229 | ||
228 | if (!XFS_SB_GOOD_VERSION(sbp)) { | 230 | if (!xfs_sb_good_version(sbp)) { |
229 | xfs_fs_mount_cmn_err(flags, "bad version"); | 231 | xfs_fs_mount_cmn_err(flags, "bad version"); |
230 | return XFS_ERROR(EWRONGFS); | 232 | return XFS_ERROR(EWRONGFS); |
231 | } | 233 | } |
@@ -300,7 +302,7 @@ xfs_mount_validate_sb( | |||
300 | /* | 302 | /* |
301 | * Version 1 directory format has never worked on Linux. | 303 | * Version 1 directory format has never worked on Linux. |
302 | */ | 304 | */ |
303 | if (unlikely(!XFS_SB_VERSION_HASDIRV2(sbp))) { | 305 | if (unlikely(!xfs_sb_version_hasdirv2(sbp))) { |
304 | xfs_fs_mount_cmn_err(flags, | 306 | xfs_fs_mount_cmn_err(flags, |
305 | "file system using version 1 directory format"); | 307 | "file system using version 1 directory format"); |
306 | return XFS_ERROR(ENOSYS); | 308 | return XFS_ERROR(ENOSYS); |
@@ -449,6 +451,7 @@ xfs_sb_from_disk( | |||
449 | to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize); | 451 | to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize); |
450 | to->sb_logsunit = be32_to_cpu(from->sb_logsunit); | 452 | to->sb_logsunit = be32_to_cpu(from->sb_logsunit); |
451 | to->sb_features2 = be32_to_cpu(from->sb_features2); | 453 | to->sb_features2 = be32_to_cpu(from->sb_features2); |
454 | to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2); | ||
452 | } | 455 | } |
453 | 456 | ||
454 | /* | 457 | /* |
@@ -781,7 +784,7 @@ xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) | |||
781 | * Update superblock with new values | 784 | * Update superblock with new values |
782 | * and log changes | 785 | * and log changes |
783 | */ | 786 | */ |
784 | if (XFS_SB_VERSION_HASDALIGN(sbp)) { | 787 | if (xfs_sb_version_hasdalign(sbp)) { |
785 | if (sbp->sb_unit != mp->m_dalign) { | 788 | if (sbp->sb_unit != mp->m_dalign) { |
786 | sbp->sb_unit = mp->m_dalign; | 789 | sbp->sb_unit = mp->m_dalign; |
787 | *update_flags |= XFS_SB_UNIT; | 790 | *update_flags |= XFS_SB_UNIT; |
@@ -792,7 +795,7 @@ xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) | |||
792 | } | 795 | } |
793 | } | 796 | } |
794 | } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN && | 797 | } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN && |
795 | XFS_SB_VERSION_HASDALIGN(&mp->m_sb)) { | 798 | xfs_sb_version_hasdalign(&mp->m_sb)) { |
796 | mp->m_dalign = sbp->sb_unit; | 799 | mp->m_dalign = sbp->sb_unit; |
797 | mp->m_swidth = sbp->sb_width; | 800 | mp->m_swidth = sbp->sb_width; |
798 | } | 801 | } |
@@ -869,7 +872,7 @@ xfs_set_rw_sizes(xfs_mount_t *mp) | |||
869 | STATIC void | 872 | STATIC void |
870 | xfs_set_inoalignment(xfs_mount_t *mp) | 873 | xfs_set_inoalignment(xfs_mount_t *mp) |
871 | { | 874 | { |
872 | if (XFS_SB_VERSION_HASALIGN(&mp->m_sb) && | 875 | if (xfs_sb_version_hasalign(&mp->m_sb) && |
873 | mp->m_sb.sb_inoalignmt >= | 876 | mp->m_sb.sb_inoalignmt >= |
874 | XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) | 877 | XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) |
875 | mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1; | 878 | mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1; |
@@ -954,7 +957,6 @@ xfs_mountfs( | |||
954 | { | 957 | { |
955 | xfs_sb_t *sbp = &(mp->m_sb); | 958 | xfs_sb_t *sbp = &(mp->m_sb); |
956 | xfs_inode_t *rip; | 959 | xfs_inode_t *rip; |
957 | bhv_vnode_t *rvp = NULL; | ||
958 | __uint64_t resblks; | 960 | __uint64_t resblks; |
959 | __int64_t update_flags = 0LL; | 961 | __int64_t update_flags = 0LL; |
960 | uint quotamount, quotaflags; | 962 | uint quotamount, quotaflags; |
@@ -962,14 +964,41 @@ xfs_mountfs( | |||
962 | int uuid_mounted = 0; | 964 | int uuid_mounted = 0; |
963 | int error = 0; | 965 | int error = 0; |
964 | 966 | ||
965 | if (mp->m_sb_bp == NULL) { | ||
966 | error = xfs_readsb(mp, mfsi_flags); | ||
967 | if (error) | ||
968 | return error; | ||
969 | } | ||
970 | xfs_mount_common(mp, sbp); | 967 | xfs_mount_common(mp, sbp); |
971 | 968 | ||
972 | /* | 969 | /* |
970 | * Check for a mismatched features2 values. Older kernels | ||
971 | * read & wrote into the wrong sb offset for sb_features2 | ||
972 | * on some platforms due to xfs_sb_t not being 64bit size aligned | ||
973 | * when sb_features2 was added, which made older superblock | ||
974 | * reading/writing routines swap it as a 64-bit value. | ||
975 | * | ||
976 | * For backwards compatibility, we make both slots equal. | ||
977 | * | ||
978 | * If we detect a mismatched field, we OR the set bits into the | ||
979 | * existing features2 field in case it has already been modified; we | ||
980 | * don't want to lose any features. We then update the bad location | ||
981 | * with the ORed value so that older kernels will see any features2 | ||
982 | * flags, and mark the two fields as needing updates once the | ||
983 | * transaction subsystem is online. | ||
984 | */ | ||
985 | if (xfs_sb_has_mismatched_features2(sbp)) { | ||
986 | cmn_err(CE_WARN, | ||
987 | "XFS: correcting sb_features alignment problem"); | ||
988 | sbp->sb_features2 |= sbp->sb_bad_features2; | ||
989 | sbp->sb_bad_features2 = sbp->sb_features2; | ||
990 | update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2; | ||
991 | |||
992 | /* | ||
993 | * Re-check for ATTR2 in case it was found in bad_features2 | ||
994 | * slot. | ||
995 | */ | ||
996 | if (xfs_sb_version_hasattr2(&mp->m_sb)) | ||
997 | mp->m_flags |= XFS_MOUNT_ATTR2; | ||
998 | |||
999 | } | ||
1000 | |||
1001 | /* | ||
973 | * Check if sb_agblocks is aligned at stripe boundary | 1002 | * Check if sb_agblocks is aligned at stripe boundary |
974 | * If sb_agblocks is NOT aligned turn off m_dalign since | 1003 | * If sb_agblocks is NOT aligned turn off m_dalign since |
975 | * allocator alignment is within an ag, therefore ag has | 1004 | * allocator alignment is within an ag, therefore ag has |
@@ -1129,7 +1158,6 @@ xfs_mountfs( | |||
1129 | } | 1158 | } |
1130 | 1159 | ||
1131 | ASSERT(rip != NULL); | 1160 | ASSERT(rip != NULL); |
1132 | rvp = XFS_ITOV(rip); | ||
1133 | 1161 | ||
1134 | if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) { | 1162 | if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) { |
1135 | cmn_err(CE_WARN, "XFS: corrupted root inode"); | 1163 | cmn_err(CE_WARN, "XFS: corrupted root inode"); |
@@ -1159,11 +1187,15 @@ xfs_mountfs( | |||
1159 | } | 1187 | } |
1160 | 1188 | ||
1161 | /* | 1189 | /* |
1162 | * If fs is not mounted readonly, then update the superblock | 1190 | * If fs is not mounted readonly, then update the superblock changes. |
1163 | * unit and width changes. | ||
1164 | */ | 1191 | */ |
1165 | if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) | 1192 | if (update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) { |
1166 | xfs_mount_log_sbunit(mp, update_flags); | 1193 | error = xfs_mount_log_sb(mp, update_flags); |
1194 | if (error) { | ||
1195 | cmn_err(CE_WARN, "XFS: failed to write sb changes"); | ||
1196 | goto error4; | ||
1197 | } | ||
1198 | } | ||
1167 | 1199 | ||
1168 | /* | 1200 | /* |
1169 | * Initialise the XFS quota management subsystem for this mount | 1201 | * Initialise the XFS quota management subsystem for this mount |
@@ -1200,12 +1232,15 @@ xfs_mountfs( | |||
1200 | * | 1232 | * |
1201 | * We default to 5% or 1024 fsbs of space reserved, whichever is smaller. | 1233 | * We default to 5% or 1024 fsbs of space reserved, whichever is smaller. |
1202 | * This may drive us straight to ENOSPC on mount, but that implies | 1234 | * This may drive us straight to ENOSPC on mount, but that implies |
1203 | * we were already there on the last unmount. | 1235 | * we were already there on the last unmount. Warn if this occurs. |
1204 | */ | 1236 | */ |
1205 | resblks = mp->m_sb.sb_dblocks; | 1237 | resblks = mp->m_sb.sb_dblocks; |
1206 | do_div(resblks, 20); | 1238 | do_div(resblks, 20); |
1207 | resblks = min_t(__uint64_t, resblks, 1024); | 1239 | resblks = min_t(__uint64_t, resblks, 1024); |
1208 | xfs_reserve_blocks(mp, &resblks, NULL); | 1240 | error = xfs_reserve_blocks(mp, &resblks, NULL); |
1241 | if (error) | ||
1242 | cmn_err(CE_WARN, "XFS: Unable to allocate reserve blocks. " | ||
1243 | "Continuing without a reserve pool."); | ||
1209 | 1244 | ||
1210 | return 0; | 1245 | return 0; |
1211 | 1246 | ||
@@ -1213,7 +1248,7 @@ xfs_mountfs( | |||
1213 | /* | 1248 | /* |
1214 | * Free up the root inode. | 1249 | * Free up the root inode. |
1215 | */ | 1250 | */ |
1216 | VN_RELE(rvp); | 1251 | IRELE(rip); |
1217 | error3: | 1252 | error3: |
1218 | xfs_log_unmount_dealloc(mp); | 1253 | xfs_log_unmount_dealloc(mp); |
1219 | error2: | 1254 | error2: |
@@ -1241,6 +1276,7 @@ int | |||
1241 | xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) | 1276 | xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) |
1242 | { | 1277 | { |
1243 | __uint64_t resblks; | 1278 | __uint64_t resblks; |
1279 | int error = 0; | ||
1244 | 1280 | ||
1245 | /* | 1281 | /* |
1246 | * We can potentially deadlock here if we have an inode cluster | 1282 | * We can potentially deadlock here if we have an inode cluster |
@@ -1284,9 +1320,15 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) | |||
1284 | * value does not matter.... | 1320 | * value does not matter.... |
1285 | */ | 1321 | */ |
1286 | resblks = 0; | 1322 | resblks = 0; |
1287 | xfs_reserve_blocks(mp, &resblks, NULL); | 1323 | error = xfs_reserve_blocks(mp, &resblks, NULL); |
1324 | if (error) | ||
1325 | cmn_err(CE_WARN, "XFS: Unable to free reserved block pool. " | ||
1326 | "Freespace may not be correct on next mount."); | ||
1288 | 1327 | ||
1289 | xfs_log_sbcount(mp, 1); | 1328 | error = xfs_log_sbcount(mp, 1); |
1329 | if (error) | ||
1330 | cmn_err(CE_WARN, "XFS: Unable to update superblock counters. " | ||
1331 | "Freespace may not be correct on next mount."); | ||
1290 | xfs_unmountfs_writesb(mp); | 1332 | xfs_unmountfs_writesb(mp); |
1291 | xfs_unmountfs_wait(mp); /* wait for async bufs */ | 1333 | xfs_unmountfs_wait(mp); /* wait for async bufs */ |
1292 | xfs_log_unmount(mp); /* Done! No more fs ops. */ | 1334 | xfs_log_unmount(mp); /* Done! No more fs ops. */ |
@@ -1378,9 +1420,8 @@ xfs_log_sbcount( | |||
1378 | xfs_mod_sb(tp, XFS_SB_IFREE | XFS_SB_ICOUNT | XFS_SB_FDBLOCKS); | 1420 | xfs_mod_sb(tp, XFS_SB_IFREE | XFS_SB_ICOUNT | XFS_SB_FDBLOCKS); |
1379 | if (sync) | 1421 | if (sync) |
1380 | xfs_trans_set_sync(tp); | 1422 | xfs_trans_set_sync(tp); |
1381 | xfs_trans_commit(tp, 0); | 1423 | error = xfs_trans_commit(tp, 0); |
1382 | 1424 | return error; | |
1383 | return 0; | ||
1384 | } | 1425 | } |
1385 | 1426 | ||
1386 | STATIC void | 1427 | STATIC void |
@@ -1429,7 +1470,6 @@ xfs_unmountfs_writesb(xfs_mount_t *mp) | |||
1429 | XFS_BUF_UNASYNC(sbp); | 1470 | XFS_BUF_UNASYNC(sbp); |
1430 | ASSERT(XFS_BUF_TARGET(sbp) == mp->m_ddev_targp); | 1471 | ASSERT(XFS_BUF_TARGET(sbp) == mp->m_ddev_targp); |
1431 | xfsbdstrat(mp, sbp); | 1472 | xfsbdstrat(mp, sbp); |
1432 | /* Nevermind errors we might get here. */ | ||
1433 | error = xfs_iowait(sbp); | 1473 | error = xfs_iowait(sbp); |
1434 | if (error) | 1474 | if (error) |
1435 | xfs_ioerror_alert("xfs_unmountfs_writesb", | 1475 | xfs_ioerror_alert("xfs_unmountfs_writesb", |
@@ -1875,25 +1915,30 @@ xfs_uuid_unmount( | |||
1875 | 1915 | ||
1876 | /* | 1916 | /* |
1877 | * Used to log changes to the superblock unit and width fields which could | 1917 | * Used to log changes to the superblock unit and width fields which could |
1878 | * be altered by the mount options. Only the first superblock is updated. | 1918 | * be altered by the mount options, as well as any potential sb_features2 |
1919 | * fixup. Only the first superblock is updated. | ||
1879 | */ | 1920 | */ |
1880 | STATIC void | 1921 | STATIC int |
1881 | xfs_mount_log_sbunit( | 1922 | xfs_mount_log_sb( |
1882 | xfs_mount_t *mp, | 1923 | xfs_mount_t *mp, |
1883 | __int64_t fields) | 1924 | __int64_t fields) |
1884 | { | 1925 | { |
1885 | xfs_trans_t *tp; | 1926 | xfs_trans_t *tp; |
1927 | int error; | ||
1886 | 1928 | ||
1887 | ASSERT(fields & (XFS_SB_UNIT|XFS_SB_WIDTH|XFS_SB_UUID)); | 1929 | ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID | |
1930 | XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2)); | ||
1888 | 1931 | ||
1889 | tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); | 1932 | tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); |
1890 | if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, | 1933 | error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, |
1891 | XFS_DEFAULT_LOG_COUNT)) { | 1934 | XFS_DEFAULT_LOG_COUNT); |
1935 | if (error) { | ||
1892 | xfs_trans_cancel(tp, 0); | 1936 | xfs_trans_cancel(tp, 0); |
1893 | return; | 1937 | return error; |
1894 | } | 1938 | } |
1895 | xfs_mod_sb(tp, fields); | 1939 | xfs_mod_sb(tp, fields); |
1896 | xfs_trans_commit(tp, 0); | 1940 | error = xfs_trans_commit(tp, 0); |
1941 | return error; | ||
1897 | } | 1942 | } |
1898 | 1943 | ||
1899 | 1944 | ||
@@ -2154,7 +2199,7 @@ xfs_icsb_counter_disabled( | |||
2154 | return test_bit(field, &mp->m_icsb_counters); | 2199 | return test_bit(field, &mp->m_icsb_counters); |
2155 | } | 2200 | } |
2156 | 2201 | ||
2157 | STATIC int | 2202 | STATIC void |
2158 | xfs_icsb_disable_counter( | 2203 | xfs_icsb_disable_counter( |
2159 | xfs_mount_t *mp, | 2204 | xfs_mount_t *mp, |
2160 | xfs_sb_field_t field) | 2205 | xfs_sb_field_t field) |
@@ -2172,7 +2217,7 @@ xfs_icsb_disable_counter( | |||
2172 | * the m_icsb_mutex. | 2217 | * the m_icsb_mutex. |
2173 | */ | 2218 | */ |
2174 | if (xfs_icsb_counter_disabled(mp, field)) | 2219 | if (xfs_icsb_counter_disabled(mp, field)) |
2175 | return 0; | 2220 | return; |
2176 | 2221 | ||
2177 | xfs_icsb_lock_all_counters(mp); | 2222 | xfs_icsb_lock_all_counters(mp); |
2178 | if (!test_and_set_bit(field, &mp->m_icsb_counters)) { | 2223 | if (!test_and_set_bit(field, &mp->m_icsb_counters)) { |
@@ -2195,8 +2240,6 @@ xfs_icsb_disable_counter( | |||
2195 | } | 2240 | } |
2196 | 2241 | ||
2197 | xfs_icsb_unlock_all_counters(mp); | 2242 | xfs_icsb_unlock_all_counters(mp); |
2198 | |||
2199 | return 0; | ||
2200 | } | 2243 | } |
2201 | 2244 | ||
2202 | STATIC void | 2245 | STATIC void |