Commit | Line | Data |
---|---|---|
0b61f8a4 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 | 2 | /* |
a805bad5 | 3 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
7b718769 | 4 | * All Rights Reserved. |
1da177e4 | 5 | */ |
0b1b213f | 6 | |
1da177e4 | 7 | #include "xfs.h" |
70a9883c | 8 | #include "xfs_shared.h" |
6ca1c906 | 9 | #include "xfs_format.h" |
239880ef DC |
10 | #include "xfs_log_format.h" |
11 | #include "xfs_trans_resv.h" | |
1da177e4 | 12 | #include "xfs_sb.h" |
1da177e4 | 13 | #include "xfs_mount.h" |
1da177e4 | 14 | #include "xfs_inode.h" |
a844f451 | 15 | #include "xfs_btree.h" |
1da177e4 | 16 | #include "xfs_bmap.h" |
a4fbe6ab | 17 | #include "xfs_alloc.h" |
9909c4aa | 18 | #include "xfs_fsops.h" |
239880ef | 19 | #include "xfs_trans.h" |
1da177e4 | 20 | #include "xfs_buf_item.h" |
239880ef | 21 | #include "xfs_log.h" |
a67d7c5f | 22 | #include "xfs_log_priv.h" |
2b9ab5ab | 23 | #include "xfs_dir2.h" |
9f8868ff CH |
24 | #include "xfs_extfree_item.h" |
25 | #include "xfs_mru_cache.h" | |
26 | #include "xfs_inode_item.h" | |
6d8b79cf | 27 | #include "xfs_icache.h" |
0b1b213f | 28 | #include "xfs_trace.h" |
3ebe7d2d | 29 | #include "xfs_icreate_item.h" |
a4fbe6ab DC |
30 | #include "xfs_filestream.h" |
31 | #include "xfs_quota.h" | |
65b65735 | 32 | #include "xfs_sysfs.h" |
30cbc591 | 33 | #include "xfs_ondisk.h" |
5880f2d7 | 34 | #include "xfs_rmap_item.h" |
baf4bcac | 35 | #include "xfs_refcount_item.h" |
6413a014 | 36 | #include "xfs_bmap_item.h" |
5e7e605c | 37 | #include "xfs_reflink.h" |
894ecacf | 38 | #include "xfs_pwork.h" |
9bbafc71 | 39 | #include "xfs_ag.h" |
f3c799c2 | 40 | #include "xfs_defer.h" |
4136e38a | 41 | #include "xfs_attr_item.h" |
d9c61ccb | 42 | #include "xfs_xattr.h" |
784eb7d8 | 43 | #include "xfs_iunlink_item.h" |
3cfb9290 | 44 | #include "xfs_dahash_test.h" |
fa5a3872 | 45 | #include "xfs_rtbitmap.h" |
6c08f434 | 46 | #include "xfs_exchmaps_item.h" |
b7c62d90 | 47 | #include "xfs_parent.h" |
18618e71 | 48 | #include "xfs_rtalloc.h" |
080d01c4 | 49 | #include "xfs_zone_alloc.h" |
d7a74cad | 50 | #include "scrub/stats.h" |
7fbaab57 | 51 | #include "scrub/rcbag_btree.h" |
1da177e4 | 52 | |
dddde68b | 53 | #include <linux/magic.h> |
73e5fff9 IK |
54 | #include <linux/fs_context.h> |
55 | #include <linux/fs_parser.h> | |
1da177e4 | 56 | |
b87221de | 57 | static const struct super_operations xfs_super_operations; |
65b65735 | 58 | |
a76dba3b | 59 | static struct dentry *xfs_debugfs; /* top-level xfs debugfs dir */ |
e3aed1a0 | 60 | static struct kset *xfs_kset; /* top-level xfs sysfs dir */ |
65b65735 BF |
61 | #ifdef DEBUG |
62 | static struct xfs_kobj xfs_dbg_kobj; /* global debug sysfs attrs */ | |
63 | #endif | |
1da177e4 | 64 | |
8d6c3446 IW |
65 | enum xfs_dax_mode { |
66 | XFS_DAX_INODE = 0, | |
67 | XFS_DAX_ALWAYS = 1, | |
68 | XFS_DAX_NEVER = 2, | |
69 | }; | |
70 | ||
d5d9dd5b DW |
71 | /* Were quota mount options provided? Must use the upper 16 bits of qflags. */ |
72 | #define XFS_QFLAGS_MNTOPTS (1U << 31) | |
73 | ||
8d6c3446 IW |
74 | static void |
75 | xfs_mount_set_dax_mode( | |
76 | struct xfs_mount *mp, | |
77 | enum xfs_dax_mode mode) | |
78 | { | |
79 | switch (mode) { | |
80 | case XFS_DAX_INODE: | |
0560f31a | 81 | mp->m_features &= ~(XFS_FEAT_DAX_ALWAYS | XFS_FEAT_DAX_NEVER); |
8d6c3446 IW |
82 | break; |
83 | case XFS_DAX_ALWAYS: | |
0560f31a DC |
84 | mp->m_features |= XFS_FEAT_DAX_ALWAYS; |
85 | mp->m_features &= ~XFS_FEAT_DAX_NEVER; | |
8d6c3446 IW |
86 | break; |
87 | case XFS_DAX_NEVER: | |
0560f31a DC |
88 | mp->m_features |= XFS_FEAT_DAX_NEVER; |
89 | mp->m_features &= ~XFS_FEAT_DAX_ALWAYS; | |
8d6c3446 IW |
90 | break; |
91 | } | |
92 | } | |
93 | ||
94 | static const struct constant_table dax_param_enums[] = { | |
95 | {"inode", XFS_DAX_INODE }, | |
96 | {"always", XFS_DAX_ALWAYS }, | |
97 | {"never", XFS_DAX_NEVER }, | |
98 | {} | |
99 | }; | |
100 | ||
62a877e3 CH |
101 | /* |
102 | * Table driven mount option parser. | |
62a877e3 CH |
103 | */ |
104 | enum { | |
8da57c5c | 105 | Opt_logbufs, Opt_logbsize, Opt_logdev, Opt_rtdev, |
2e74af0e | 106 | Opt_wsync, Opt_noalign, Opt_swalloc, Opt_sunit, Opt_swidth, Opt_nouuid, |
94079285 | 107 | Opt_grpid, Opt_nogrpid, Opt_bsdgroups, Opt_sysvgroups, |
1c02d502 ES |
108 | Opt_allocsize, Opt_norecovery, Opt_inode64, Opt_inode32, Opt_ikeep, |
109 | Opt_noikeep, Opt_largeio, Opt_nolargeio, Opt_attr2, Opt_noattr2, | |
110 | Opt_filestreams, Opt_quota, Opt_noquota, Opt_usrquota, Opt_grpquota, | |
111 | Opt_prjquota, Opt_uquota, Opt_gquota, Opt_pquota, | |
2e74af0e | 112 | Opt_uqnoenforce, Opt_gqnoenforce, Opt_pqnoenforce, Opt_qnoenforce, |
7452a6da | 113 | Opt_discard, Opt_nodiscard, Opt_dax, Opt_dax_enum, Opt_max_open_zones, |
4528b905 | 114 | Opt_lifetime, Opt_nolifetime, Opt_max_atomic_write, |
62a877e3 CH |
115 | }; |
116 | ||
d7167b14 | 117 | static const struct fs_parameter_spec xfs_fs_parameters[] = { |
73e5fff9 IK |
118 | fsparam_u32("logbufs", Opt_logbufs), |
119 | fsparam_string("logbsize", Opt_logbsize), | |
120 | fsparam_string("logdev", Opt_logdev), | |
121 | fsparam_string("rtdev", Opt_rtdev), | |
122 | fsparam_flag("wsync", Opt_wsync), | |
123 | fsparam_flag("noalign", Opt_noalign), | |
124 | fsparam_flag("swalloc", Opt_swalloc), | |
125 | fsparam_u32("sunit", Opt_sunit), | |
126 | fsparam_u32("swidth", Opt_swidth), | |
127 | fsparam_flag("nouuid", Opt_nouuid), | |
128 | fsparam_flag("grpid", Opt_grpid), | |
129 | fsparam_flag("nogrpid", Opt_nogrpid), | |
130 | fsparam_flag("bsdgroups", Opt_bsdgroups), | |
131 | fsparam_flag("sysvgroups", Opt_sysvgroups), | |
132 | fsparam_string("allocsize", Opt_allocsize), | |
133 | fsparam_flag("norecovery", Opt_norecovery), | |
134 | fsparam_flag("inode64", Opt_inode64), | |
135 | fsparam_flag("inode32", Opt_inode32), | |
136 | fsparam_flag("ikeep", Opt_ikeep), | |
137 | fsparam_flag("noikeep", Opt_noikeep), | |
138 | fsparam_flag("largeio", Opt_largeio), | |
139 | fsparam_flag("nolargeio", Opt_nolargeio), | |
140 | fsparam_flag("attr2", Opt_attr2), | |
141 | fsparam_flag("noattr2", Opt_noattr2), | |
142 | fsparam_flag("filestreams", Opt_filestreams), | |
143 | fsparam_flag("quota", Opt_quota), | |
144 | fsparam_flag("noquota", Opt_noquota), | |
145 | fsparam_flag("usrquota", Opt_usrquota), | |
146 | fsparam_flag("grpquota", Opt_grpquota), | |
147 | fsparam_flag("prjquota", Opt_prjquota), | |
148 | fsparam_flag("uquota", Opt_uquota), | |
149 | fsparam_flag("gquota", Opt_gquota), | |
150 | fsparam_flag("pquota", Opt_pquota), | |
151 | fsparam_flag("uqnoenforce", Opt_uqnoenforce), | |
152 | fsparam_flag("gqnoenforce", Opt_gqnoenforce), | |
153 | fsparam_flag("pqnoenforce", Opt_pqnoenforce), | |
154 | fsparam_flag("qnoenforce", Opt_qnoenforce), | |
155 | fsparam_flag("discard", Opt_discard), | |
156 | fsparam_flag("nodiscard", Opt_nodiscard), | |
157 | fsparam_flag("dax", Opt_dax), | |
8d6c3446 | 158 | fsparam_enum("dax", Opt_dax_enum, dax_param_enums), |
7452a6da | 159 | fsparam_u32("max_open_zones", Opt_max_open_zones), |
64d03611 HH |
160 | fsparam_flag("lifetime", Opt_lifetime), |
161 | fsparam_flag("nolifetime", Opt_nolifetime), | |
4528b905 | 162 | fsparam_string("max_atomic_write", Opt_max_atomic_write), |
73e5fff9 | 163 | {} |
62a877e3 CH |
164 | }; |
165 | ||
a67d7c5f | 166 | struct proc_xfs_info { |
cbe4dab1 DC |
167 | uint64_t flag; |
168 | char *str; | |
a67d7c5f DC |
169 | }; |
170 | ||
21f55993 CH |
171 | static int |
172 | xfs_fs_show_options( | |
173 | struct seq_file *m, | |
174 | struct dentry *root) | |
a67d7c5f DC |
175 | { |
176 | static struct proc_xfs_info xfs_info_set[] = { | |
177 | /* the few simple ones we can get from the mount struct */ | |
0560f31a DC |
178 | { XFS_FEAT_IKEEP, ",ikeep" }, |
179 | { XFS_FEAT_WSYNC, ",wsync" }, | |
180 | { XFS_FEAT_NOALIGN, ",noalign" }, | |
181 | { XFS_FEAT_SWALLOC, ",swalloc" }, | |
182 | { XFS_FEAT_NOUUID, ",nouuid" }, | |
183 | { XFS_FEAT_NORECOVERY, ",norecovery" }, | |
184 | { XFS_FEAT_ATTR2, ",attr2" }, | |
185 | { XFS_FEAT_FILESTREAMS, ",filestreams" }, | |
186 | { XFS_FEAT_GRPID, ",grpid" }, | |
187 | { XFS_FEAT_DISCARD, ",discard" }, | |
188 | { XFS_FEAT_LARGE_IOSIZE, ",largeio" }, | |
189 | { XFS_FEAT_DAX_ALWAYS, ",dax=always" }, | |
190 | { XFS_FEAT_DAX_NEVER, ",dax=never" }, | |
64d03611 | 191 | { XFS_FEAT_NOLIFETIME, ",nolifetime" }, |
a67d7c5f DC |
192 | { 0, NULL } |
193 | }; | |
21f55993 | 194 | struct xfs_mount *mp = XFS_M(root->d_sb); |
a67d7c5f DC |
195 | struct proc_xfs_info *xfs_infop; |
196 | ||
197 | for (xfs_infop = xfs_info_set; xfs_infop->flag; xfs_infop++) { | |
0560f31a | 198 | if (mp->m_features & xfs_infop->flag) |
a67d7c5f DC |
199 | seq_puts(m, xfs_infop->str); |
200 | } | |
1775c506 | 201 | |
0560f31a | 202 | seq_printf(m, ",inode%d", xfs_has_small_inums(mp) ? 32 : 64); |
a67d7c5f | 203 | |
0560f31a | 204 | if (xfs_has_allocsize(mp)) |
2e74af0e | 205 | seq_printf(m, ",allocsize=%dk", |
aa58d445 | 206 | (1 << mp->m_allocsize_log) >> 10); |
a67d7c5f DC |
207 | |
208 | if (mp->m_logbufs > 0) | |
2e74af0e | 209 | seq_printf(m, ",logbufs=%d", mp->m_logbufs); |
a67d7c5f | 210 | if (mp->m_logbsize > 0) |
2e74af0e | 211 | seq_printf(m, ",logbsize=%dk", mp->m_logbsize >> 10); |
a67d7c5f DC |
212 | |
213 | if (mp->m_logname) | |
2e74af0e | 214 | seq_show_option(m, "logdev", mp->m_logname); |
a67d7c5f | 215 | if (mp->m_rtname) |
2e74af0e | 216 | seq_show_option(m, "rtdev", mp->m_rtname); |
a67d7c5f DC |
217 | |
218 | if (mp->m_dalign > 0) | |
2e74af0e | 219 | seq_printf(m, ",sunit=%d", |
a67d7c5f DC |
220 | (int)XFS_FSB_TO_BB(mp, mp->m_dalign)); |
221 | if (mp->m_swidth > 0) | |
2e74af0e | 222 | seq_printf(m, ",swidth=%d", |
a67d7c5f DC |
223 | (int)XFS_FSB_TO_BB(mp, mp->m_swidth)); |
224 | ||
149e53af CH |
225 | if (mp->m_qflags & XFS_UQUOTA_ENFD) |
226 | seq_puts(m, ",usrquota"); | |
227 | else if (mp->m_qflags & XFS_UQUOTA_ACCT) | |
228 | seq_puts(m, ",uqnoenforce"); | |
a67d7c5f | 229 | |
149e53af CH |
230 | if (mp->m_qflags & XFS_PQUOTA_ENFD) |
231 | seq_puts(m, ",prjquota"); | |
232 | else if (mp->m_qflags & XFS_PQUOTA_ACCT) | |
233 | seq_puts(m, ",pqnoenforce"); | |
234 | ||
235 | if (mp->m_qflags & XFS_GQUOTA_ENFD) | |
236 | seq_puts(m, ",grpquota"); | |
237 | else if (mp->m_qflags & XFS_GQUOTA_ACCT) | |
238 | seq_puts(m, ",gqnoenforce"); | |
a67d7c5f DC |
239 | |
240 | if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) | |
2e74af0e | 241 | seq_puts(m, ",noquota"); |
21f55993 | 242 | |
7452a6da CH |
243 | if (mp->m_max_open_zones) |
244 | seq_printf(m, ",max_open_zones=%u", mp->m_max_open_zones); | |
4528b905 DW |
245 | if (mp->m_awu_max_bytes) |
246 | seq_printf(m, ",max_atomic_write=%lluk", | |
247 | mp->m_awu_max_bytes >> 10); | |
7452a6da | 248 | |
21f55993 | 249 | return 0; |
a67d7c5f | 250 | } |
91083269 | 251 | |
7ac2ff8b DC |
252 | static bool |
253 | xfs_set_inode_alloc_perag( | |
254 | struct xfs_perag *pag, | |
255 | xfs_ino_t ino, | |
256 | xfs_agnumber_t max_metadata) | |
257 | { | |
e9c4d8bf | 258 | if (!xfs_is_inode32(pag_mount(pag))) { |
7ac2ff8b DC |
259 | set_bit(XFS_AGSTATE_ALLOWS_INODES, &pag->pag_opstate); |
260 | clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate); | |
261 | return false; | |
262 | } | |
263 | ||
264 | if (ino > XFS_MAXINUMBER_32) { | |
265 | clear_bit(XFS_AGSTATE_ALLOWS_INODES, &pag->pag_opstate); | |
266 | clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate); | |
267 | return false; | |
268 | } | |
269 | ||
270 | set_bit(XFS_AGSTATE_ALLOWS_INODES, &pag->pag_opstate); | |
e9c4d8bf | 271 | if (pag_agno(pag) < max_metadata) |
7ac2ff8b DC |
272 | set_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate); |
273 | else | |
274 | clear_bit(XFS_AGSTATE_PREFERS_METADATA, &pag->pag_opstate); | |
275 | return true; | |
276 | } | |
277 | ||
9de67c3b | 278 | /* |
12c3f05c ES |
279 | * Set parameters for inode allocation heuristics, taking into account |
280 | * filesystem size and inode32/inode64 mount options; i.e. specifically | |
0560f31a | 281 | * whether or not XFS_FEAT_SMALL_INUMS is set. |
12c3f05c ES |
282 | * |
283 | * Inode allocation patterns are altered only if inode32 is requested | |
0560f31a | 284 | * (XFS_FEAT_SMALL_INUMS), and the filesystem is sufficiently large. |
2e973b2c | 285 | * If altered, XFS_OPSTATE_INODE32 is set as well. |
12c3f05c ES |
286 | * |
287 | * An agcount independent of that in the mount structure is provided | |
288 | * because in the growfs case, mp->m_sb.sb_agcount is not yet updated | |
289 | * to the potentially higher ag count. | |
290 | * | |
291 | * Returns the maximum AG index which may contain inodes. | |
9de67c3b | 292 | */ |
2d2194f6 | 293 | xfs_agnumber_t |
12c3f05c ES |
294 | xfs_set_inode_alloc( |
295 | struct xfs_mount *mp, | |
296 | xfs_agnumber_t agcount) | |
2d2194f6 | 297 | { |
12c3f05c | 298 | xfs_agnumber_t index; |
4056c1d0 | 299 | xfs_agnumber_t maxagi = 0; |
2d2194f6 CM |
300 | xfs_sb_t *sbp = &mp->m_sb; |
301 | xfs_agnumber_t max_metadata; | |
54aa61f8 ES |
302 | xfs_agino_t agino; |
303 | xfs_ino_t ino; | |
2d2194f6 | 304 | |
12c3f05c ES |
305 | /* |
306 | * Calculate how much should be reserved for inodes to meet | |
307 | * the max inode percentage. Used only for inode32. | |
2d2194f6 | 308 | */ |
ef325959 | 309 | if (M_IGEO(mp)->maxicount) { |
c8ce540d | 310 | uint64_t icount; |
2d2194f6 CM |
311 | |
312 | icount = sbp->sb_dblocks * sbp->sb_imax_pct; | |
313 | do_div(icount, 100); | |
314 | icount += sbp->sb_agblocks - 1; | |
315 | do_div(icount, sbp->sb_agblocks); | |
316 | max_metadata = icount; | |
317 | } else { | |
9de67c3b | 318 | max_metadata = agcount; |
2d2194f6 CM |
319 | } |
320 | ||
12c3f05c | 321 | /* Get the last possible inode in the filesystem */ |
43004b2a | 322 | agino = XFS_AGB_TO_AGINO(mp, sbp->sb_agblocks - 1); |
12c3f05c ES |
323 | ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); |
324 | ||
325 | /* | |
326 | * If user asked for no more than 32-bit inodes, and the fs is | |
2e973b2c | 327 | * sufficiently large, set XFS_OPSTATE_INODE32 if we must alter |
12c3f05c ES |
328 | * the allocator to accommodate the request. |
329 | */ | |
0560f31a | 330 | if (xfs_has_small_inums(mp) && ino > XFS_MAXINUMBER_32) |
ca57120d | 331 | xfs_set_inode32(mp); |
12c3f05c | 332 | else |
ca57120d | 333 | xfs_clear_inode32(mp); |
54aa61f8 | 334 | |
9de67c3b | 335 | for (index = 0; index < agcount; index++) { |
12c3f05c | 336 | struct xfs_perag *pag; |
4056c1d0 | 337 | |
12c3f05c | 338 | ino = XFS_AGINO_TO_INO(mp, index, agino); |
2d2194f6 CM |
339 | |
340 | pag = xfs_perag_get(mp, index); | |
7ac2ff8b DC |
341 | if (xfs_set_inode_alloc_perag(pag, ino, max_metadata)) |
342 | maxagi++; | |
2d2194f6 CM |
343 | xfs_perag_put(pag); |
344 | } | |
345 | ||
2e973b2c | 346 | return xfs_is_inode32(mp) ? maxagi : agcount; |
2d2194f6 CM |
347 | } |
348 | ||
679a9949 CH |
349 | static int |
350 | xfs_setup_dax_always( | |
351 | struct xfs_mount *mp) | |
a384f088 | 352 | { |
7b0800d0 CH |
353 | if (!mp->m_ddev_targp->bt_daxdev && |
354 | (!mp->m_rtdev_targp || !mp->m_rtdev_targp->bt_daxdev)) { | |
679a9949 CH |
355 | xfs_alert(mp, |
356 | "DAX unsupported by block device. Turning off DAX."); | |
357 | goto disable_dax; | |
7b0800d0 CH |
358 | } |
359 | ||
360 | if (mp->m_super->s_blocksize != PAGE_SIZE) { | |
361 | xfs_alert(mp, | |
362 | "DAX not supported for blocksize. Turning off DAX."); | |
363 | goto disable_dax; | |
679a9949 CH |
364 | } |
365 | ||
35fcd75a SR |
366 | if (xfs_has_reflink(mp) && |
367 | bdev_is_partition(mp->m_ddev_targp->bt_bdev)) { | |
368 | xfs_alert(mp, | |
369 | "DAX and reflink cannot work with multi-partitions!"); | |
679a9949 CH |
370 | return -EINVAL; |
371 | } | |
372 | ||
679a9949 CH |
373 | return 0; |
374 | ||
375 | disable_dax: | |
376 | xfs_mount_set_dax_mode(mp, XFS_DAX_NEVER); | |
377 | return 0; | |
a384f088 CH |
378 | } |
379 | ||
3180e66d | 380 | STATIC int |
1da177e4 LT |
381 | xfs_blkdev_get( |
382 | xfs_mount_t *mp, | |
383 | const char *name, | |
1b9e2d90 | 384 | struct file **bdev_filep) |
1da177e4 LT |
385 | { |
386 | int error = 0; | |
bfecc409 | 387 | blk_mode_t mode; |
1da177e4 | 388 | |
bfecc409 HH |
389 | mode = sb_open_mode(mp->m_super->s_flags); |
390 | *bdev_filep = bdev_file_open_by_path(name, mode, | |
391 | mp->m_super, &fs_holder_ops); | |
1b9e2d90 CB |
392 | if (IS_ERR(*bdev_filep)) { |
393 | error = PTR_ERR(*bdev_filep); | |
394 | *bdev_filep = NULL; | |
77af574e | 395 | xfs_warn(mp, "Invalid device [%s], error=%d", name, error); |
1da177e4 LT |
396 | } |
397 | ||
2451337d | 398 | return error; |
1da177e4 LT |
399 | } |
400 | ||
3180e66d | 401 | STATIC void |
35a93b14 | 402 | xfs_shutdown_devices( |
19f354d4 CH |
403 | struct xfs_mount *mp) |
404 | { | |
1a0a5dad CH |
405 | /* |
406 | * Udev is triggered whenever anyone closes a block device or unmounts | |
407 | * a file systemm on a block device. | |
408 | * The default udev rules invoke blkid to read the fs super and create | |
409 | * symlinks to the bdev under /dev/disk. For this, it uses buffered | |
410 | * reads through the page cache. | |
411 | * | |
412 | * xfs_db also uses buffered reads to examine metadata. There is no | |
413 | * coordination between xfs_db and udev, which means that they can run | |
414 | * concurrently. Note there is no coordination between the kernel and | |
415 | * blkid either. | |
416 | * | |
417 | * On a system with 64k pages, the page cache can cache the superblock | |
418 | * and the root inode (and hence the root directory) with the same 64k | |
419 | * page. If udev spawns blkid after the mkfs and the system is busy | |
420 | * enough that it is still running when xfs_db starts up, they'll both | |
421 | * read from the same page in the pagecache. | |
422 | * | |
423 | * The unmount writes updated inode metadata to disk directly. The XFS | |
424 | * buffer cache does not use the bdev pagecache, so it needs to | |
425 | * invalidate that pagecache on unmount. If the above scenario occurs, | |
426 | * the pagecache no longer reflects what's on disk, xfs_db reads the | |
427 | * stale metadata, and fails to find /a. Most of the time this succeeds | |
428 | * because closing a bdev invalidates the page cache, but when processes | |
429 | * race, everyone loses. | |
430 | */ | |
19f354d4 | 431 | if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) { |
35a93b14 CH |
432 | blkdev_issue_flush(mp->m_logdev_targp->bt_bdev); |
433 | invalidate_bdev(mp->m_logdev_targp->bt_bdev); | |
19f354d4 CH |
434 | } |
435 | if (mp->m_rtdev_targp) { | |
35a93b14 CH |
436 | blkdev_issue_flush(mp->m_rtdev_targp->bt_bdev); |
437 | invalidate_bdev(mp->m_rtdev_targp->bt_bdev); | |
19f354d4 | 438 | } |
35a93b14 CH |
439 | blkdev_issue_flush(mp->m_ddev_targp->bt_bdev); |
440 | invalidate_bdev(mp->m_ddev_targp->bt_bdev); | |
19f354d4 CH |
441 | } |
442 | ||
443 | /* | |
444 | * The file system configurations are: | |
445 | * (1) device (partition) with data and internal log | |
446 | * (2) logical volume with data and log subvolumes. | |
447 | * (3) logical volume with data, log, and realtime subvolumes. | |
448 | * | |
449 | * We only have to handle opening the log and realtime volumes here if | |
450 | * they are present. The data subvolume has already been opened by | |
451 | * get_sb_bdev() and is stored in sb->s_bdev. | |
452 | */ | |
453 | STATIC int | |
454 | xfs_open_devices( | |
9d565ffa | 455 | struct xfs_mount *mp) |
19f354d4 | 456 | { |
8d945b59 CH |
457 | struct super_block *sb = mp->m_super; |
458 | struct block_device *ddev = sb->s_bdev; | |
1b9e2d90 | 459 | struct file *logdev_file = NULL, *rtdev_file = NULL; |
19f354d4 CH |
460 | int error; |
461 | ||
462 | /* | |
463 | * Open real time and log devices - order is important. | |
464 | */ | |
9d565ffa | 465 | if (mp->m_logname) { |
1b9e2d90 | 466 | error = xfs_blkdev_get(mp, mp->m_logname, &logdev_file); |
19f354d4 | 467 | if (error) |
653bee38 | 468 | return error; |
19f354d4 CH |
469 | } |
470 | ||
9d565ffa | 471 | if (mp->m_rtname) { |
1b9e2d90 | 472 | error = xfs_blkdev_get(mp, mp->m_rtname, &rtdev_file); |
19f354d4 CH |
473 | if (error) |
474 | goto out_close_logdev; | |
475 | ||
1b9e2d90 CB |
476 | if (file_bdev(rtdev_file) == ddev || |
477 | (logdev_file && | |
478 | file_bdev(rtdev_file) == file_bdev(logdev_file))) { | |
4f10700a DC |
479 | xfs_warn(mp, |
480 | "Cannot mount filesystem with identical rtdev and ddev/logdev."); | |
2451337d | 481 | error = -EINVAL; |
19f354d4 CH |
482 | goto out_close_rtdev; |
483 | } | |
484 | } | |
485 | ||
486 | /* | |
487 | * Setup xfs_mount buffer target pointers | |
488 | */ | |
1b9e2d90 | 489 | mp->m_ddev_targp = xfs_alloc_buftarg(mp, sb->s_bdev_file); |
84270a1a DW |
490 | if (IS_ERR(mp->m_ddev_targp)) { |
491 | error = PTR_ERR(mp->m_ddev_targp); | |
492 | mp->m_ddev_targp = NULL; | |
19f354d4 | 493 | goto out_close_rtdev; |
84270a1a | 494 | } |
19f354d4 | 495 | |
1b9e2d90 CB |
496 | if (rtdev_file) { |
497 | mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev_file); | |
84270a1a DW |
498 | if (IS_ERR(mp->m_rtdev_targp)) { |
499 | error = PTR_ERR(mp->m_rtdev_targp); | |
500 | mp->m_rtdev_targp = NULL; | |
19f354d4 | 501 | goto out_free_ddev_targ; |
84270a1a | 502 | } |
19f354d4 CH |
503 | } |
504 | ||
1b9e2d90 CB |
505 | if (logdev_file && file_bdev(logdev_file) != ddev) { |
506 | mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev_file); | |
84270a1a DW |
507 | if (IS_ERR(mp->m_logdev_targp)) { |
508 | error = PTR_ERR(mp->m_logdev_targp); | |
509 | mp->m_logdev_targp = NULL; | |
19f354d4 | 510 | goto out_free_rtdev_targ; |
84270a1a | 511 | } |
19f354d4 CH |
512 | } else { |
513 | mp->m_logdev_targp = mp->m_ddev_targp; | |
e340dd63 | 514 | /* Handle won't be used, drop it */ |
1b9e2d90 | 515 | if (logdev_file) |
22650a99 | 516 | bdev_fput(logdev_file); |
19f354d4 CH |
517 | } |
518 | ||
653bee38 | 519 | return 0; |
19f354d4 CH |
520 | |
521 | out_free_rtdev_targ: | |
522 | if (mp->m_rtdev_targp) | |
a1f69417 | 523 | xfs_free_buftarg(mp->m_rtdev_targp); |
19f354d4 | 524 | out_free_ddev_targ: |
a1f69417 | 525 | xfs_free_buftarg(mp->m_ddev_targp); |
19f354d4 | 526 | out_close_rtdev: |
1b9e2d90 | 527 | if (rtdev_file) |
22650a99 | 528 | bdev_fput(rtdev_file); |
19f354d4 | 529 | out_close_logdev: |
1b9e2d90 | 530 | if (logdev_file) |
22650a99 | 531 | bdev_fput(logdev_file); |
653bee38 | 532 | return error; |
19f354d4 CH |
533 | } |
534 | ||
e34b562c CH |
535 | /* |
536 | * Setup xfs_mount buffer target pointers based on superblock | |
537 | */ | |
538 | STATIC int | |
539 | xfs_setup_devices( | |
540 | struct xfs_mount *mp) | |
541 | { | |
542 | int error; | |
19f354d4 | 543 | |
13c7c54b | 544 | error = xfs_configure_buftarg(mp->m_ddev_targp, mp->m_sb.sb_sectsize); |
e34b562c CH |
545 | if (error) |
546 | return error; | |
547 | ||
548 | if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) { | |
549 | unsigned int log_sector_size = BBSIZE; | |
550 | ||
38c26bfd | 551 | if (xfs_has_sector(mp)) |
e34b562c | 552 | log_sector_size = mp->m_sb.sb_logsectsize; |
13c7c54b | 553 | error = xfs_configure_buftarg(mp->m_logdev_targp, |
e34b562c CH |
554 | log_sector_size); |
555 | if (error) | |
556 | return error; | |
557 | } | |
bdc03eb5 CH |
558 | |
559 | if (mp->m_sb.sb_rtstart) { | |
560 | if (mp->m_rtdev_targp) { | |
561 | xfs_warn(mp, | |
562 | "can't use internal and external rtdev at the same time"); | |
563 | return -EINVAL; | |
564 | } | |
565 | mp->m_rtdev_targp = mp->m_ddev_targp; | |
566 | } else if (mp->m_rtname) { | |
13c7c54b | 567 | error = xfs_configure_buftarg(mp->m_rtdev_targp, |
e34b562c CH |
568 | mp->m_sb.sb_sectsize); |
569 | if (error) | |
570 | return error; | |
571 | } | |
572 | ||
573 | return 0; | |
574 | } | |
19f354d4 | 575 | |
aa6bf01d CH |
576 | STATIC int |
577 | xfs_init_mount_workqueues( | |
578 | struct xfs_mount *mp) | |
579 | { | |
78c931b8 | 580 | mp->m_buf_workqueue = alloc_workqueue("xfs-buf/%s", |
05a302a1 DW |
581 | XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM), |
582 | 1, mp->m_super->s_id); | |
78c931b8 BF |
583 | if (!mp->m_buf_workqueue) |
584 | goto out; | |
585 | ||
aa6bf01d | 586 | mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s", |
05a302a1 DW |
587 | XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM), |
588 | 0, mp->m_super->s_id); | |
aa6bf01d | 589 | if (!mp->m_unwritten_workqueue) |
28408243 | 590 | goto out_destroy_buf; |
aa6bf01d | 591 | |
5889608d | 592 | mp->m_reclaim_workqueue = alloc_workqueue("xfs-reclaim/%s", |
05a302a1 DW |
593 | XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM), |
594 | 0, mp->m_super->s_id); | |
5889608d | 595 | if (!mp->m_reclaim_workqueue) |
33c0dd78 | 596 | goto out_destroy_unwritten; |
5889608d | 597 | |
ab23a776 DC |
598 | mp->m_blockgc_wq = alloc_workqueue("xfs-blockgc/%s", |
599 | XFS_WQFLAGS(WQ_UNBOUND | WQ_FREEZABLE | WQ_MEM_RECLAIM), | |
05a302a1 | 600 | 0, mp->m_super->s_id); |
ab23a776 | 601 | if (!mp->m_blockgc_wq) |
1058d0f5 | 602 | goto out_destroy_reclaim; |
579b62fa | 603 | |
ab23a776 DC |
604 | mp->m_inodegc_wq = alloc_workqueue("xfs-inodegc/%s", |
605 | XFS_WQFLAGS(WQ_FREEZABLE | WQ_MEM_RECLAIM), | |
606 | 1, mp->m_super->s_id); | |
607 | if (!mp->m_inodegc_wq) | |
608 | goto out_destroy_blockgc; | |
609 | ||
05a302a1 DW |
610 | mp->m_sync_workqueue = alloc_workqueue("xfs-sync/%s", |
611 | XFS_WQFLAGS(WQ_FREEZABLE), 0, mp->m_super->s_id); | |
696a5620 | 612 | if (!mp->m_sync_workqueue) |
ab23a776 | 613 | goto out_destroy_inodegc; |
696a5620 | 614 | |
aa6bf01d CH |
615 | return 0; |
616 | ||
ab23a776 DC |
617 | out_destroy_inodegc: |
618 | destroy_workqueue(mp->m_inodegc_wq); | |
619 | out_destroy_blockgc: | |
620 | destroy_workqueue(mp->m_blockgc_wq); | |
5889608d DC |
621 | out_destroy_reclaim: |
622 | destroy_workqueue(mp->m_reclaim_workqueue); | |
4c2d542f DC |
623 | out_destroy_unwritten: |
624 | destroy_workqueue(mp->m_unwritten_workqueue); | |
78c931b8 BF |
625 | out_destroy_buf: |
626 | destroy_workqueue(mp->m_buf_workqueue); | |
aa6bf01d CH |
627 | out: |
628 | return -ENOMEM; | |
629 | } | |
630 | ||
631 | STATIC void | |
632 | xfs_destroy_mount_workqueues( | |
633 | struct xfs_mount *mp) | |
634 | { | |
696a5620 | 635 | destroy_workqueue(mp->m_sync_workqueue); |
ab23a776 DC |
636 | destroy_workqueue(mp->m_blockgc_wq); |
637 | destroy_workqueue(mp->m_inodegc_wq); | |
5889608d | 638 | destroy_workqueue(mp->m_reclaim_workqueue); |
aa6bf01d | 639 | destroy_workqueue(mp->m_unwritten_workqueue); |
78c931b8 | 640 | destroy_workqueue(mp->m_buf_workqueue); |
aa6bf01d CH |
641 | } |
642 | ||
f0f7a674 DW |
643 | static void |
644 | xfs_flush_inodes_worker( | |
645 | struct work_struct *work) | |
646 | { | |
647 | struct xfs_mount *mp = container_of(work, struct xfs_mount, | |
648 | m_flush_inodes_work); | |
649 | struct super_block *sb = mp->m_super; | |
650 | ||
651 | if (down_read_trylock(&sb->s_umount)) { | |
652 | sync_inodes_sb(sb); | |
653 | up_read(&sb->s_umount); | |
654 | } | |
655 | } | |
656 | ||
9aa05000 DC |
657 | /* |
658 | * Flush all dirty data to disk. Must not be called while holding an XFS_ILOCK | |
659 | * or a page lock. We use sync_inodes_sb() here to ensure we block while waiting | |
660 | * for IO to complete so that we effectively throttle multiple callers to the | |
661 | * rate at which IO is completing. | |
662 | */ | |
663 | void | |
664 | xfs_flush_inodes( | |
665 | struct xfs_mount *mp) | |
666 | { | |
f0f7a674 DW |
667 | /* |
668 | * If flush_work() returns true then that means we waited for a flush | |
669 | * which was already in progress. Don't bother running another scan. | |
670 | */ | |
671 | if (flush_work(&mp->m_flush_inodes_work)) | |
c6425702 DW |
672 | return; |
673 | ||
f0f7a674 DW |
674 | queue_work(mp->m_sync_workqueue, &mp->m_flush_inodes_work); |
675 | flush_work(&mp->m_flush_inodes_work); | |
9aa05000 DC |
676 | } |
677 | ||
bf904248 | 678 | /* Catch misguided souls that try to use this interface on XFS */ |
1da177e4 | 679 | STATIC struct inode * |
a50cd269 | 680 | xfs_fs_alloc_inode( |
1da177e4 LT |
681 | struct super_block *sb) |
682 | { | |
bf904248 | 683 | BUG(); |
493dca61 | 684 | return NULL; |
1da177e4 LT |
685 | } |
686 | ||
bf904248 | 687 | /* |
99fa8cb3 | 688 | * Now that the generic code is guaranteed not to be accessing |
8179c036 | 689 | * the linux inode, we can inactivate and reclaim the inode. |
bf904248 | 690 | */ |
1da177e4 | 691 | STATIC void |
a50cd269 | 692 | xfs_fs_destroy_inode( |
848ce8f7 | 693 | struct inode *inode) |
1da177e4 | 694 | { |
848ce8f7 CH |
695 | struct xfs_inode *ip = XFS_I(inode); |
696 | ||
cca28fb8 | 697 | trace_xfs_destroy_inode(ip); |
99fa8cb3 | 698 | |
65523218 | 699 | ASSERT(!rwsem_is_locked(&inode->i_rwsem)); |
8179c036 DC |
700 | XFS_STATS_INC(ip->i_mount, vn_rele); |
701 | XFS_STATS_INC(ip->i_mount, vn_remove); | |
c076ae7a | 702 | xfs_inode_mark_reclaimable(ip); |
1da177e4 LT |
703 | } |
704 | ||
c3b1b131 CH |
705 | static void |
706 | xfs_fs_dirty_inode( | |
707 | struct inode *inode, | |
cbfecb92 | 708 | int flags) |
c3b1b131 CH |
709 | { |
710 | struct xfs_inode *ip = XFS_I(inode); | |
711 | struct xfs_mount *mp = ip->i_mount; | |
712 | struct xfs_trans *tp; | |
713 | ||
714 | if (!(inode->i_sb->s_flags & SB_LAZYTIME)) | |
715 | return; | |
cbfecb92 LC |
716 | |
717 | /* | |
718 | * Only do the timestamp update if the inode is dirty (I_DIRTY_SYNC) | |
719 | * and has dirty timestamp (I_DIRTY_TIME). I_DIRTY_TIME can be passed | |
720 | * in flags possibly together with I_DIRTY_SYNC. | |
721 | */ | |
722 | if ((flags & ~I_DIRTY_TIME) != I_DIRTY_SYNC || !(flags & I_DIRTY_TIME)) | |
c3b1b131 CH |
723 | return; |
724 | ||
725 | if (xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp)) | |
726 | return; | |
727 | xfs_ilock(ip, XFS_ILOCK_EXCL); | |
728 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | |
729 | xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP); | |
730 | xfs_trans_commit(tp); | |
731 | } | |
732 | ||
07c8f675 DC |
733 | /* |
734 | * Slab object creation initialisation for the XFS inode. | |
735 | * This covers only the idempotent fields in the XFS inode; | |
736 | * all other fields need to be initialised on allocation | |
b595076a | 737 | * from the slab. This avoids the need to repeatedly initialise |
07c8f675 DC |
738 | * fields in the xfs inode that left in the initialise state |
739 | * when freeing the inode. | |
740 | */ | |
bf904248 DC |
741 | STATIC void |
742 | xfs_fs_inode_init_once( | |
07c8f675 DC |
743 | void *inode) |
744 | { | |
745 | struct xfs_inode *ip = inode; | |
746 | ||
747 | memset(ip, 0, sizeof(struct xfs_inode)); | |
bf904248 DC |
748 | |
749 | /* vfs inode */ | |
750 | inode_init_once(VFS_I(ip)); | |
751 | ||
752 | /* xfs inode */ | |
07c8f675 DC |
753 | atomic_set(&ip->i_pincount, 0); |
754 | spin_lock_init(&ip->i_flags_lock); | |
785dd131 | 755 | init_rwsem(&ip->i_lock); |
07c8f675 DC |
756 | } |
757 | ||
5132ba8f DC |
758 | /* |
759 | * We do an unlocked check for XFS_IDONTCACHE here because we are already | |
760 | * serialised against cache hits here via the inode->i_lock and igrab() in | |
761 | * xfs_iget_cache_hit(). Hence a lookup that might clear this flag will not be | |
762 | * racing with us, and it avoids needing to grab a spinlock here for every inode | |
763 | * we drop the final reference on. | |
764 | */ | |
765 | STATIC int | |
766 | xfs_fs_drop_inode( | |
767 | struct inode *inode) | |
768 | { | |
769 | struct xfs_inode *ip = XFS_I(inode); | |
770 | ||
17c12bcd DW |
771 | /* |
772 | * If this unlinked inode is in the middle of recovery, don't | |
773 | * drop the inode just yet; log recovery will take care of | |
774 | * that. See the comment for this inode flag. | |
775 | */ | |
776 | if (ip->i_flags & XFS_IRECOVERY) { | |
e1d06e5f | 777 | ASSERT(xlog_recovery_needed(ip->i_mount->m_log)); |
17c12bcd DW |
778 | return 0; |
779 | } | |
780 | ||
dae2f8ed | 781 | return generic_drop_inode(inode); |
5132ba8f DC |
782 | } |
783 | ||
0e2f80af AP |
784 | STATIC void |
785 | xfs_fs_evict_inode( | |
786 | struct inode *inode) | |
787 | { | |
788 | if (IS_DAX(inode)) | |
789 | dax_break_layout_final(inode); | |
790 | ||
791 | truncate_inode_pages_final(&inode->i_data); | |
792 | clear_inode(inode); | |
793 | } | |
794 | ||
a943f372 IK |
795 | static void |
796 | xfs_mount_free( | |
a738159d CH |
797 | struct xfs_mount *mp) |
798 | { | |
35a93b14 CH |
799 | if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) |
800 | xfs_free_buftarg(mp->m_logdev_targp); | |
bdc03eb5 | 801 | if (mp->m_rtdev_targp && mp->m_rtdev_targp != mp->m_ddev_targp) |
35a93b14 CH |
802 | xfs_free_buftarg(mp->m_rtdev_targp); |
803 | if (mp->m_ddev_targp) | |
804 | xfs_free_buftarg(mp->m_ddev_targp); | |
805 | ||
a76dba3b | 806 | debugfs_remove(mp->m_debugfs); |
a738159d CH |
807 | kfree(mp->m_rtname); |
808 | kfree(mp->m_logname); | |
d4c75a1b | 809 | kfree(mp); |
a738159d CH |
810 | } |
811 | ||
1da177e4 | 812 | STATIC int |
69961a26 | 813 | xfs_fs_sync_fs( |
1da177e4 LT |
814 | struct super_block *sb, |
815 | int wait) | |
816 | { | |
745f6919 | 817 | struct xfs_mount *mp = XFS_M(sb); |
2d86293c | 818 | int error; |
1da177e4 | 819 | |
ab23a776 DC |
820 | trace_xfs_fs_sync_fs(mp, __return_address); |
821 | ||
e893bffd | 822 | /* |
34625c66 | 823 | * Doing anything during the async pass would be counterproductive. |
e893bffd | 824 | */ |
34625c66 | 825 | if (!wait) |
69961a26 | 826 | return 0; |
69961a26 | 827 | |
2d86293c DW |
828 | error = xfs_log_force(mp, XFS_LOG_SYNC); |
829 | if (error) | |
830 | return error; | |
831 | ||
69961a26 | 832 | if (laptop_mode) { |
1da177e4 LT |
833 | /* |
834 | * The disk must be active because we're syncing. | |
f661f1e0 | 835 | * We schedule log work now (now that the disk is |
1da177e4 LT |
836 | * active) instead of later (when it might not be). |
837 | */ | |
f661f1e0 | 838 | flush_delayed_work(&mp->m_log->l_work); |
1da177e4 LT |
839 | } |
840 | ||
ab23a776 DC |
841 | /* |
842 | * If we are called with page faults frozen out, it means we are about | |
843 | * to freeze the transaction subsystem. Take the opportunity to shut | |
844 | * down inodegc because once SB_FREEZE_FS is set it's too late to | |
845 | * prevent inactivation races with freeze. The fs doesn't get called | |
846 | * again by the freezing process until after SB_FREEZE_FS has been set, | |
6f649091 DW |
847 | * so it's now or never. Same logic applies to speculative allocation |
848 | * garbage collection. | |
ab23a776 DC |
849 | * |
850 | * We don't care if this is a normal syncfs call that does this or | |
851 | * freeze that does this - we can run this multiple times without issue | |
852 | * and we won't race with a restart because a restart can only occur | |
853 | * when the state is either SB_FREEZE_FS or SB_FREEZE_COMPLETE. | |
854 | */ | |
6f649091 | 855 | if (sb->s_writers.frozen == SB_FREEZE_PAGEFAULT) { |
ab23a776 | 856 | xfs_inodegc_stop(mp); |
6f649091 | 857 | xfs_blockgc_stop(mp); |
080d01c4 | 858 | xfs_zone_gc_stop(mp); |
6f649091 | 859 | } |
ab23a776 | 860 | |
69961a26 | 861 | return 0; |
1da177e4 LT |
862 | } |
863 | ||
dd324cb7 CH |
864 | static xfs_extlen_t |
865 | xfs_internal_log_size( | |
866 | struct xfs_mount *mp) | |
1da177e4 | 867 | { |
dd324cb7 CH |
868 | if (!mp->m_sb.sb_logstart) |
869 | return 0; | |
870 | return mp->m_sb.sb_logblocks; | |
871 | } | |
4ca488eb | 872 | |
dd324cb7 CH |
873 | static void |
874 | xfs_statfs_data( | |
875 | struct xfs_mount *mp, | |
876 | struct kstatfs *st) | |
877 | { | |
878 | int64_t fdblocks = | |
712bae96 | 879 | xfs_sum_freecounter(mp, XC_FREE_BLOCKS); |
4ca488eb | 880 | |
dd324cb7 | 881 | /* make sure st->f_bfree does not underflow */ |
712bae96 CH |
882 | st->f_bfree = max(0LL, |
883 | fdblocks - xfs_freecounter_unavailable(mp, XC_FREE_BLOCKS)); | |
884 | ||
72843ca6 CH |
885 | /* |
886 | * sb_dblocks can change during growfs, but nothing cares about reporting | |
887 | * the old or new value during growfs. | |
888 | */ | |
dd324cb7 CH |
889 | st->f_blocks = mp->m_sb.sb_dblocks - xfs_internal_log_size(mp); |
890 | } | |
891 | ||
892 | /* | |
893 | * When stat(v)fs is called on a file with the realtime bit set or a directory | |
894 | * with the rtinherit bit, report freespace information for the RT device | |
895 | * instead of the main data device. | |
896 | */ | |
897 | static void | |
898 | xfs_statfs_rt( | |
899 | struct xfs_mount *mp, | |
900 | struct kstatfs *st) | |
901 | { | |
902 | st->f_bfree = xfs_rtbxlen_to_blen(mp, | |
712bae96 | 903 | xfs_sum_freecounter(mp, XC_FREE_RTEXTENTS)); |
55ef6e7a CH |
904 | st->f_blocks = mp->m_sb.sb_rblocks - xfs_rtbxlen_to_blen(mp, |
905 | mp->m_free[XC_FREE_RTEXTENTS].res_total); | |
dd324cb7 | 906 | } |
0d485ada | 907 | |
dd324cb7 CH |
908 | static void |
909 | xfs_statfs_inodes( | |
910 | struct xfs_mount *mp, | |
911 | struct kstatfs *st) | |
912 | { | |
913 | uint64_t icount = percpu_counter_sum(&mp->m_icount); | |
914 | uint64_t ifree = percpu_counter_sum(&mp->m_ifree); | |
915 | uint64_t fakeinos = XFS_FSB_TO_INO(mp, st->f_bfree); | |
0d485ada | 916 | |
dd324cb7 | 917 | st->f_files = min(icount + fakeinos, (uint64_t)XFS_MAXINUMBER); |
ef325959 | 918 | if (M_IGEO(mp)->maxicount) |
dd324cb7 | 919 | st->f_files = min_t(typeof(st->f_files), st->f_files, |
ef325959 | 920 | M_IGEO(mp)->maxicount); |
2fe33661 | 921 | |
01f9882e | 922 | /* If sb_icount overshot maxicount, report actual allocation */ |
dd324cb7 CH |
923 | st->f_files = max_t(typeof(st->f_files), st->f_files, |
924 | mp->m_sb.sb_icount); | |
01f9882e | 925 | |
dd324cb7 CH |
926 | /* Make sure st->f_ffree does not underflow */ |
927 | st->f_ffree = max_t(int64_t, 0, st->f_files - (icount - ifree)); | |
928 | } | |
2fe33661 | 929 | |
dd324cb7 CH |
930 | STATIC int |
931 | xfs_fs_statfs( | |
932 | struct dentry *dentry, | |
933 | struct kstatfs *st) | |
934 | { | |
935 | struct xfs_mount *mp = XFS_M(dentry->d_sb); | |
936 | struct xfs_inode *ip = XFS_I(d_inode(dentry)); | |
2229276c | 937 | |
dd324cb7 CH |
938 | /* |
939 | * Expedite background inodegc but don't wait. We do not want to block | |
940 | * here waiting hours for a billion extent file to be truncated. | |
941 | */ | |
942 | xfs_inodegc_push(mp); | |
943 | ||
944 | st->f_type = XFS_SUPER_MAGIC; | |
945 | st->f_namelen = MAXNAMELEN - 1; | |
946 | st->f_bsize = mp->m_sb.sb_blocksize; | |
947 | st->f_fsid = u64_to_fsid(huge_encode_dev(mp->m_ddev_targp->bt_dev)); | |
948 | ||
949 | xfs_statfs_data(mp, st); | |
950 | xfs_statfs_inodes(mp, st); | |
951 | ||
952 | if (XFS_IS_REALTIME_MOUNT(mp) && | |
953 | (ip->i_diflags & (XFS_DIFLAG_RTINHERIT | XFS_DIFLAG_REALTIME))) | |
954 | xfs_statfs_rt(mp, st); | |
a0158315 | 955 | |
9a17ebfe DW |
956 | if ((ip->i_diflags & XFS_DIFLAG_PROJINHERIT) && |
957 | ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))) == | |
958 | (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD)) | |
dd324cb7 | 959 | xfs_qm_statvfs(ip, st); |
9a17ebfe | 960 | |
dd324cb7 CH |
961 | /* |
962 | * XFS does not distinguish between blocks available to privileged and | |
963 | * unprivileged users. | |
964 | */ | |
965 | st->f_bavail = st->f_bfree; | |
4ca488eb | 966 | return 0; |
1da177e4 LT |
967 | } |
968 | ||
d5db0f97 | 969 | STATIC void |
c8c4e8bc CH |
970 | xfs_save_resvblks( |
971 | struct xfs_mount *mp) | |
d5db0f97 | 972 | { |
c8c4e8bc CH |
973 | enum xfs_free_counter i; |
974 | ||
975 | for (i = 0; i < XC_FREE_NR; i++) { | |
976 | mp->m_free[i].res_saved = mp->m_free[i].res_total; | |
977 | xfs_reserve_blocks(mp, i, 0); | |
978 | } | |
d5db0f97 ES |
979 | } |
980 | ||
981 | STATIC void | |
c8c4e8bc CH |
982 | xfs_restore_resvblks( |
983 | struct xfs_mount *mp) | |
d5db0f97 | 984 | { |
c8c4e8bc CH |
985 | uint64_t resblks; |
986 | enum xfs_free_counter i; | |
d5db0f97 | 987 | |
c8c4e8bc CH |
988 | for (i = 0; i < XC_FREE_NR; i++) { |
989 | if (mp->m_free[i].res_saved) { | |
990 | resblks = mp->m_free[i].res_saved; | |
991 | mp->m_free[i].res_saved = 0; | |
992 | } else | |
993 | resblks = xfs_default_resblks(mp, i); | |
994 | xfs_reserve_blocks(mp, i, resblks); | |
995 | } | |
d5db0f97 ES |
996 | } |
997 | ||
8757c38f IK |
998 | /* |
999 | * Second stage of a freeze. The data is already frozen so we only | |
1000 | * need to take care of the metadata. Once that's done sync the superblock | |
1001 | * to the log to dirty it in case of a crash while frozen. This ensures that we | |
1002 | * will recover the unlinked inode lists on the next mount. | |
1003 | */ | |
1004 | STATIC int | |
1005 | xfs_fs_freeze( | |
1006 | struct super_block *sb) | |
1007 | { | |
1008 | struct xfs_mount *mp = XFS_M(sb); | |
c3f2375b WL |
1009 | unsigned int flags; |
1010 | int ret; | |
8757c38f | 1011 | |
c3f2375b WL |
1012 | /* |
1013 | * The filesystem is now frozen far enough that memory reclaim | |
1014 | * cannot safely operate on the filesystem. Hence we need to | |
1015 | * set a GFP_NOFS context here to avoid recursion deadlocks. | |
1016 | */ | |
1017 | flags = memalloc_nofs_save(); | |
8757c38f | 1018 | xfs_save_resvblks(mp); |
5b0ad7c2 | 1019 | ret = xfs_log_quiesce(mp); |
c3f2375b | 1020 | memalloc_nofs_restore(flags); |
ab23a776 DC |
1021 | |
1022 | /* | |
1023 | * For read-write filesystems, we need to restart the inodegc on error | |
1024 | * because we stopped it at SB_FREEZE_PAGEFAULT level and a thaw is not | |
1025 | * going to be run to restart it now. We are at SB_FREEZE_FS level | |
1026 | * here, so we can restart safely without racing with a stop in | |
1027 | * xfs_fs_sync_fs(). | |
1028 | */ | |
2e973b2c | 1029 | if (ret && !xfs_is_readonly(mp)) { |
6f649091 | 1030 | xfs_blockgc_start(mp); |
ab23a776 | 1031 | xfs_inodegc_start(mp); |
080d01c4 | 1032 | xfs_zone_gc_start(mp); |
6f649091 | 1033 | } |
ab23a776 | 1034 | |
c3f2375b | 1035 | return ret; |
8757c38f IK |
1036 | } |
1037 | ||
1038 | STATIC int | |
1039 | xfs_fs_unfreeze( | |
1040 | struct super_block *sb) | |
1041 | { | |
1042 | struct xfs_mount *mp = XFS_M(sb); | |
1043 | ||
1044 | xfs_restore_resvblks(mp); | |
1045 | xfs_log_work_queue(mp); | |
ab23a776 DC |
1046 | |
1047 | /* | |
1048 | * Don't reactivate the inodegc worker on a readonly filesystem because | |
6f649091 DW |
1049 | * inodes are sent directly to reclaim. Don't reactivate the blockgc |
1050 | * worker because there are no speculative preallocations on a readonly | |
1051 | * filesystem. | |
ab23a776 | 1052 | */ |
2e973b2c | 1053 | if (!xfs_is_readonly(mp)) { |
080d01c4 | 1054 | xfs_zone_gc_start(mp); |
6f649091 | 1055 | xfs_blockgc_start(mp); |
ab23a776 | 1056 | xfs_inodegc_start(mp); |
6f649091 | 1057 | } |
ab23a776 | 1058 | |
8757c38f IK |
1059 | return 0; |
1060 | } | |
1061 | ||
1062 | /* | |
1063 | * This function fills in xfs_mount_t fields based on mount args. | |
1064 | * Note: the superblock _has_ now been read in. | |
1065 | */ | |
1066 | STATIC int | |
1067 | xfs_finish_flags( | |
1068 | struct xfs_mount *mp) | |
1069 | { | |
8757c38f | 1070 | /* Fail a mount where the logbuf is smaller than the log stripe */ |
38c26bfd | 1071 | if (xfs_has_logv2(mp)) { |
8757c38f IK |
1072 | if (mp->m_logbsize <= 0 && |
1073 | mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE) { | |
1074 | mp->m_logbsize = mp->m_sb.sb_logsunit; | |
1075 | } else if (mp->m_logbsize > 0 && | |
1076 | mp->m_logbsize < mp->m_sb.sb_logsunit) { | |
1077 | xfs_warn(mp, | |
1078 | "logbuf size must be greater than or equal to log stripe size"); | |
1079 | return -EINVAL; | |
1080 | } | |
1081 | } else { | |
1082 | /* Fail a mount if the logbuf is larger than 32K */ | |
1083 | if (mp->m_logbsize > XLOG_BIG_RECORD_BSIZE) { | |
1084 | xfs_warn(mp, | |
1085 | "logbuf size for version 1 logs must be 16K or 32K"); | |
1086 | return -EINVAL; | |
1087 | } | |
1088 | } | |
1089 | ||
1090 | /* | |
1091 | * V5 filesystems always use attr2 format for attributes. | |
1092 | */ | |
0560f31a | 1093 | if (xfs_has_crc(mp) && xfs_has_noattr2(mp)) { |
8757c38f IK |
1094 | xfs_warn(mp, "Cannot mount a V5 filesystem as noattr2. " |
1095 | "attr2 is always enabled for V5 filesystems."); | |
1096 | return -EINVAL; | |
1097 | } | |
1098 | ||
8757c38f IK |
1099 | /* |
1100 | * prohibit r/w mounts of read-only filesystems | |
1101 | */ | |
2e973b2c | 1102 | if ((mp->m_sb.sb_flags & XFS_SBF_READONLY) && !xfs_is_readonly(mp)) { |
8757c38f IK |
1103 | xfs_warn(mp, |
1104 | "cannot mount a read-only filesystem as read-write"); | |
1105 | return -EROFS; | |
1106 | } | |
1107 | ||
149e53af CH |
1108 | if ((mp->m_qflags & XFS_GQUOTA_ACCT) && |
1109 | (mp->m_qflags & XFS_PQUOTA_ACCT) && | |
38c26bfd | 1110 | !xfs_has_pquotino(mp)) { |
8757c38f IK |
1111 | xfs_warn(mp, |
1112 | "Super block does not support project and group quota together"); | |
1113 | return -EINVAL; | |
1114 | } | |
1115 | ||
7452a6da CH |
1116 | if (!xfs_has_zoned(mp)) { |
1117 | if (mp->m_max_open_zones) { | |
1118 | xfs_warn(mp, | |
1119 | "max_open_zones mount option only supported on zoned file systems."); | |
1120 | return -EINVAL; | |
1121 | } | |
64d03611 HH |
1122 | if (mp->m_features & XFS_FEAT_NOLIFETIME) { |
1123 | xfs_warn(mp, | |
1124 | "nolifetime mount option only supported on zoned file systems."); | |
1125 | return -EINVAL; | |
1126 | } | |
7452a6da CH |
1127 | } |
1128 | ||
8757c38f IK |
1129 | return 0; |
1130 | } | |
1131 | ||
1132 | static int | |
1133 | xfs_init_percpu_counters( | |
1134 | struct xfs_mount *mp) | |
1135 | { | |
712bae96 CH |
1136 | int error; |
1137 | int i; | |
8757c38f IK |
1138 | |
1139 | error = percpu_counter_init(&mp->m_icount, 0, GFP_KERNEL); | |
1140 | if (error) | |
1141 | return -ENOMEM; | |
1142 | ||
1143 | error = percpu_counter_init(&mp->m_ifree, 0, GFP_KERNEL); | |
1144 | if (error) | |
1145 | goto free_icount; | |
1146 | ||
8757c38f IK |
1147 | error = percpu_counter_init(&mp->m_delalloc_blks, 0, GFP_KERNEL); |
1148 | if (error) | |
712bae96 | 1149 | goto free_ifree; |
8757c38f | 1150 | |
7099bd0f | 1151 | error = percpu_counter_init(&mp->m_delalloc_rtextents, 0, GFP_KERNEL); |
2229276c DW |
1152 | if (error) |
1153 | goto free_delalloc; | |
1154 | ||
712bae96 CH |
1155 | for (i = 0; i < XC_FREE_NR; i++) { |
1156 | error = percpu_counter_init(&mp->m_free[i].count, 0, | |
1157 | GFP_KERNEL); | |
1158 | if (error) | |
1159 | goto free_freecounters; | |
1160 | } | |
7099bd0f | 1161 | |
8757c38f IK |
1162 | return 0; |
1163 | ||
712bae96 | 1164 | free_freecounters: |
09dab6ce | 1165 | while (--i >= 0) |
712bae96 | 1166 | percpu_counter_destroy(&mp->m_free[i].count); |
7099bd0f | 1167 | percpu_counter_destroy(&mp->m_delalloc_rtextents); |
2229276c DW |
1168 | free_delalloc: |
1169 | percpu_counter_destroy(&mp->m_delalloc_blks); | |
8757c38f IK |
1170 | free_ifree: |
1171 | percpu_counter_destroy(&mp->m_ifree); | |
1172 | free_icount: | |
1173 | percpu_counter_destroy(&mp->m_icount); | |
1174 | return -ENOMEM; | |
1175 | } | |
1176 | ||
1177 | void | |
1178 | xfs_reinit_percpu_counters( | |
1179 | struct xfs_mount *mp) | |
1180 | { | |
1181 | percpu_counter_set(&mp->m_icount, mp->m_sb.sb_icount); | |
1182 | percpu_counter_set(&mp->m_ifree, mp->m_sb.sb_ifree); | |
712bae96 | 1183 | xfs_set_freecounter(mp, XC_FREE_BLOCKS, mp->m_sb.sb_fdblocks); |
1d319ac6 CH |
1184 | if (!xfs_has_zoned(mp)) |
1185 | xfs_set_freecounter(mp, XC_FREE_RTEXTENTS, | |
1186 | mp->m_sb.sb_frextents); | |
8757c38f IK |
1187 | } |
1188 | ||
1189 | static void | |
1190 | xfs_destroy_percpu_counters( | |
1191 | struct xfs_mount *mp) | |
1192 | { | |
712bae96 CH |
1193 | enum xfs_free_counter i; |
1194 | ||
1195 | for (i = 0; i < XC_FREE_NR; i++) | |
1196 | percpu_counter_destroy(&mp->m_free[i].count); | |
8757c38f IK |
1197 | percpu_counter_destroy(&mp->m_icount); |
1198 | percpu_counter_destroy(&mp->m_ifree); | |
75c8c50f | 1199 | ASSERT(xfs_is_shutdown(mp) || |
7099bd0f CH |
1200 | percpu_counter_sum(&mp->m_delalloc_rtextents) == 0); |
1201 | percpu_counter_destroy(&mp->m_delalloc_rtextents); | |
1202 | ASSERT(xfs_is_shutdown(mp) || | |
8757c38f IK |
1203 | percpu_counter_sum(&mp->m_delalloc_blks) == 0); |
1204 | percpu_counter_destroy(&mp->m_delalloc_blks); | |
1205 | } | |
1206 | ||
ab23a776 DC |
1207 | static int |
1208 | xfs_inodegc_init_percpu( | |
1209 | struct xfs_mount *mp) | |
1210 | { | |
1211 | struct xfs_inodegc *gc; | |
1212 | int cpu; | |
1213 | ||
1214 | mp->m_inodegc = alloc_percpu(struct xfs_inodegc); | |
1215 | if (!mp->m_inodegc) | |
1216 | return -ENOMEM; | |
1217 | ||
1218 | for_each_possible_cpu(cpu) { | |
1219 | gc = per_cpu_ptr(mp->m_inodegc, cpu); | |
b37c4c83 | 1220 | gc->cpu = cpu; |
62334fab | 1221 | gc->mp = mp; |
ab23a776 DC |
1222 | init_llist_head(&gc->list); |
1223 | gc->items = 0; | |
d4d12c02 | 1224 | gc->error = 0; |
7cf2b0f9 | 1225 | INIT_DELAYED_WORK(&gc->work, xfs_inodegc_worker); |
ab23a776 DC |
1226 | } |
1227 | return 0; | |
1228 | } | |
1229 | ||
1230 | static void | |
1231 | xfs_inodegc_free_percpu( | |
1232 | struct xfs_mount *mp) | |
1233 | { | |
1234 | if (!mp->m_inodegc) | |
1235 | return; | |
1236 | free_percpu(mp->m_inodegc); | |
1237 | } | |
1238 | ||
8757c38f IK |
1239 | static void |
1240 | xfs_fs_put_super( | |
1241 | struct super_block *sb) | |
1242 | { | |
1243 | struct xfs_mount *mp = XFS_M(sb); | |
1244 | ||
64c80dfd | 1245 | xfs_notice(mp, "Unmounting Filesystem %pU", &mp->m_sb.sb_uuid); |
8757c38f IK |
1246 | xfs_filestream_unmount(mp); |
1247 | xfs_unmountfs(mp); | |
1248 | ||
18618e71 | 1249 | xfs_rtmount_freesb(mp); |
8757c38f | 1250 | xfs_freesb(mp); |
d7a74cad | 1251 | xchk_mount_stats_free(mp); |
8757c38f | 1252 | free_percpu(mp->m_stats.xs_stats); |
ab23a776 | 1253 | xfs_inodegc_free_percpu(mp); |
8757c38f IK |
1254 | xfs_destroy_percpu_counters(mp); |
1255 | xfs_destroy_mount_workqueues(mp); | |
35a93b14 | 1256 | xfs_shutdown_devices(mp); |
8757c38f IK |
1257 | } |
1258 | ||
1259 | static long | |
1260 | xfs_fs_nr_cached_objects( | |
1261 | struct super_block *sb, | |
1262 | struct shrink_control *sc) | |
1263 | { | |
1264 | /* Paranoia: catch incorrect calls during mount setup or teardown */ | |
1265 | if (WARN_ON_ONCE(!sb->s_fs_info)) | |
1266 | return 0; | |
1267 | return xfs_reclaim_inodes_count(XFS_M(sb)); | |
1268 | } | |
1269 | ||
1270 | static long | |
1271 | xfs_fs_free_cached_objects( | |
1272 | struct super_block *sb, | |
1273 | struct shrink_control *sc) | |
c7eea6f7 | 1274 | { |
8757c38f IK |
1275 | return xfs_reclaim_inodes_nr(XFS_M(sb), sc->nr_to_scan); |
1276 | } | |
c7eea6f7 | 1277 | |
e7caa877 CH |
1278 | static void |
1279 | xfs_fs_shutdown( | |
1280 | struct super_block *sb) | |
1281 | { | |
1282 | xfs_force_shutdown(XFS_M(sb), SHUTDOWN_DEVICE_REMOVED); | |
1283 | } | |
1284 | ||
099bf44f CH |
1285 | static int |
1286 | xfs_fs_show_stats( | |
1287 | struct seq_file *m, | |
1288 | struct dentry *root) | |
1289 | { | |
5443041b HH |
1290 | struct xfs_mount *mp = XFS_M(root->d_sb); |
1291 | ||
1292 | if (xfs_has_zoned(mp) && IS_ENABLED(CONFIG_XFS_RT)) | |
1293 | xfs_zoned_show_stats(m, mp); | |
099bf44f CH |
1294 | return 0; |
1295 | } | |
1296 | ||
8757c38f IK |
1297 | static const struct super_operations xfs_super_operations = { |
1298 | .alloc_inode = xfs_fs_alloc_inode, | |
1299 | .destroy_inode = xfs_fs_destroy_inode, | |
1300 | .dirty_inode = xfs_fs_dirty_inode, | |
1301 | .drop_inode = xfs_fs_drop_inode, | |
0e2f80af | 1302 | .evict_inode = xfs_fs_evict_inode, |
8757c38f IK |
1303 | .put_super = xfs_fs_put_super, |
1304 | .sync_fs = xfs_fs_sync_fs, | |
1305 | .freeze_fs = xfs_fs_freeze, | |
1306 | .unfreeze_fs = xfs_fs_unfreeze, | |
1307 | .statfs = xfs_fs_statfs, | |
1308 | .show_options = xfs_fs_show_options, | |
1309 | .nr_cached_objects = xfs_fs_nr_cached_objects, | |
1310 | .free_cached_objects = xfs_fs_free_cached_objects, | |
e7caa877 | 1311 | .shutdown = xfs_fs_shutdown, |
099bf44f | 1312 | .show_stats = xfs_fs_show_stats, |
8757c38f | 1313 | }; |
c7eea6f7 | 1314 | |
8757c38f IK |
1315 | static int |
1316 | suffix_kstrtoint( | |
1317 | const char *s, | |
1318 | unsigned int base, | |
1319 | int *res) | |
1320 | { | |
1321 | int last, shift_left_factor = 0, _res; | |
1322 | char *value; | |
1323 | int ret = 0; | |
1324 | ||
1325 | value = kstrdup(s, GFP_KERNEL); | |
1326 | if (!value) | |
1327 | return -ENOMEM; | |
1328 | ||
1329 | last = strlen(value) - 1; | |
1330 | if (value[last] == 'K' || value[last] == 'k') { | |
1331 | shift_left_factor = 10; | |
1332 | value[last] = '\0'; | |
1333 | } | |
1334 | if (value[last] == 'M' || value[last] == 'm') { | |
1335 | shift_left_factor = 20; | |
1336 | value[last] = '\0'; | |
1337 | } | |
1338 | if (value[last] == 'G' || value[last] == 'g') { | |
1339 | shift_left_factor = 30; | |
1340 | value[last] = '\0'; | |
1341 | } | |
1342 | ||
1343 | if (kstrtoint(value, base, &_res)) | |
1344 | ret = -EINVAL; | |
1345 | kfree(value); | |
1346 | *res = _res << shift_left_factor; | |
1347 | return ret; | |
c7eea6f7 DC |
1348 | } |
1349 | ||
4528b905 DW |
1350 | static int |
1351 | suffix_kstrtoull( | |
1352 | const char *s, | |
1353 | unsigned int base, | |
1354 | unsigned long long *res) | |
1355 | { | |
1356 | int last, shift_left_factor = 0; | |
1357 | unsigned long long _res; | |
1358 | char *value; | |
1359 | int ret = 0; | |
1360 | ||
1361 | value = kstrdup(s, GFP_KERNEL); | |
1362 | if (!value) | |
1363 | return -ENOMEM; | |
1364 | ||
1365 | last = strlen(value) - 1; | |
1366 | if (value[last] == 'K' || value[last] == 'k') { | |
1367 | shift_left_factor = 10; | |
1368 | value[last] = '\0'; | |
1369 | } | |
1370 | if (value[last] == 'M' || value[last] == 'm') { | |
1371 | shift_left_factor = 20; | |
1372 | value[last] = '\0'; | |
1373 | } | |
1374 | if (value[last] == 'G' || value[last] == 'g') { | |
1375 | shift_left_factor = 30; | |
1376 | value[last] = '\0'; | |
1377 | } | |
1378 | ||
1379 | if (kstrtoull(value, base, &_res)) | |
1380 | ret = -EINVAL; | |
1381 | kfree(value); | |
1382 | *res = _res << shift_left_factor; | |
1383 | return ret; | |
1384 | } | |
1385 | ||
92cf7d36 PR |
1386 | static inline void |
1387 | xfs_fs_warn_deprecated( | |
1388 | struct fs_context *fc, | |
1389 | struct fs_parameter *param, | |
1390 | uint64_t flag, | |
1391 | bool value) | |
1392 | { | |
1393 | /* Don't print the warning if reconfiguring and current mount point | |
1394 | * already had the flag set | |
1395 | */ | |
1396 | if ((fc->purpose & FS_CONTEXT_FOR_RECONFIGURE) && | |
0560f31a | 1397 | !!(XFS_M(fc->root->d_sb)->m_features & flag) == value) |
92cf7d36 PR |
1398 | return; |
1399 | xfs_warn(fc->s_fs_info, "%s mount option is deprecated.", param->key); | |
1400 | } | |
1401 | ||
9909c4aa | 1402 | /* |
8757c38f IK |
1403 | * Set mount state from a mount option. |
1404 | * | |
1405 | * NOTE: mp->m_super is NULL here! | |
9909c4aa | 1406 | */ |
8757c38f | 1407 | static int |
1e5c39df | 1408 | xfs_fs_parse_param( |
8757c38f IK |
1409 | struct fs_context *fc, |
1410 | struct fs_parameter *param) | |
1da177e4 | 1411 | { |
0f98b4ec | 1412 | struct xfs_mount *parsing_mp = fc->s_fs_info; |
8757c38f IK |
1413 | struct fs_parse_result result; |
1414 | int size = 0; | |
1415 | int opt; | |
9909c4aa | 1416 | |
d5d9dd5b DW |
1417 | BUILD_BUG_ON(XFS_QFLAGS_MNTOPTS & XFS_MOUNT_QUOTA_ALL); |
1418 | ||
d7167b14 | 1419 | opt = fs_parse(fc, xfs_fs_parameters, param, &result); |
8757c38f IK |
1420 | if (opt < 0) |
1421 | return opt; | |
1da177e4 | 1422 | |
8757c38f IK |
1423 | switch (opt) { |
1424 | case Opt_logbufs: | |
0f98b4ec | 1425 | parsing_mp->m_logbufs = result.uint_32; |
8757c38f IK |
1426 | return 0; |
1427 | case Opt_logbsize: | |
0f98b4ec | 1428 | if (suffix_kstrtoint(param->string, 10, &parsing_mp->m_logbsize)) |
8757c38f IK |
1429 | return -EINVAL; |
1430 | return 0; | |
1431 | case Opt_logdev: | |
0f98b4ec PR |
1432 | kfree(parsing_mp->m_logname); |
1433 | parsing_mp->m_logname = kstrdup(param->string, GFP_KERNEL); | |
1434 | if (!parsing_mp->m_logname) | |
8757c38f IK |
1435 | return -ENOMEM; |
1436 | return 0; | |
1437 | case Opt_rtdev: | |
0f98b4ec PR |
1438 | kfree(parsing_mp->m_rtname); |
1439 | parsing_mp->m_rtname = kstrdup(param->string, GFP_KERNEL); | |
1440 | if (!parsing_mp->m_rtname) | |
8757c38f IK |
1441 | return -ENOMEM; |
1442 | return 0; | |
1443 | case Opt_allocsize: | |
1444 | if (suffix_kstrtoint(param->string, 10, &size)) | |
1445 | return -EINVAL; | |
0f98b4ec | 1446 | parsing_mp->m_allocsize_log = ffs(size) - 1; |
0560f31a | 1447 | parsing_mp->m_features |= XFS_FEAT_ALLOCSIZE; |
8757c38f IK |
1448 | return 0; |
1449 | case Opt_grpid: | |
1450 | case Opt_bsdgroups: | |
0560f31a | 1451 | parsing_mp->m_features |= XFS_FEAT_GRPID; |
8757c38f IK |
1452 | return 0; |
1453 | case Opt_nogrpid: | |
1454 | case Opt_sysvgroups: | |
0560f31a | 1455 | parsing_mp->m_features &= ~XFS_FEAT_GRPID; |
8757c38f IK |
1456 | return 0; |
1457 | case Opt_wsync: | |
0560f31a | 1458 | parsing_mp->m_features |= XFS_FEAT_WSYNC; |
8757c38f IK |
1459 | return 0; |
1460 | case Opt_norecovery: | |
0560f31a | 1461 | parsing_mp->m_features |= XFS_FEAT_NORECOVERY; |
8757c38f IK |
1462 | return 0; |
1463 | case Opt_noalign: | |
0560f31a | 1464 | parsing_mp->m_features |= XFS_FEAT_NOALIGN; |
8757c38f IK |
1465 | return 0; |
1466 | case Opt_swalloc: | |
0560f31a | 1467 | parsing_mp->m_features |= XFS_FEAT_SWALLOC; |
8757c38f IK |
1468 | return 0; |
1469 | case Opt_sunit: | |
0f98b4ec | 1470 | parsing_mp->m_dalign = result.uint_32; |
8757c38f IK |
1471 | return 0; |
1472 | case Opt_swidth: | |
0f98b4ec | 1473 | parsing_mp->m_swidth = result.uint_32; |
8757c38f IK |
1474 | return 0; |
1475 | case Opt_inode32: | |
0560f31a | 1476 | parsing_mp->m_features |= XFS_FEAT_SMALL_INUMS; |
8757c38f IK |
1477 | return 0; |
1478 | case Opt_inode64: | |
0560f31a | 1479 | parsing_mp->m_features &= ~XFS_FEAT_SMALL_INUMS; |
8757c38f IK |
1480 | return 0; |
1481 | case Opt_nouuid: | |
0560f31a | 1482 | parsing_mp->m_features |= XFS_FEAT_NOUUID; |
8757c38f | 1483 | return 0; |
8757c38f | 1484 | case Opt_largeio: |
0560f31a | 1485 | parsing_mp->m_features |= XFS_FEAT_LARGE_IOSIZE; |
8757c38f IK |
1486 | return 0; |
1487 | case Opt_nolargeio: | |
0560f31a | 1488 | parsing_mp->m_features &= ~XFS_FEAT_LARGE_IOSIZE; |
8757c38f | 1489 | return 0; |
8757c38f | 1490 | case Opt_filestreams: |
0560f31a | 1491 | parsing_mp->m_features |= XFS_FEAT_FILESTREAMS; |
8757c38f IK |
1492 | return 0; |
1493 | case Opt_noquota: | |
0f98b4ec PR |
1494 | parsing_mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT; |
1495 | parsing_mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD; | |
d5d9dd5b | 1496 | parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; |
8757c38f IK |
1497 | return 0; |
1498 | case Opt_quota: | |
1499 | case Opt_uquota: | |
1500 | case Opt_usrquota: | |
149e53af | 1501 | parsing_mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ENFD); |
d5d9dd5b | 1502 | parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; |
8757c38f IK |
1503 | return 0; |
1504 | case Opt_qnoenforce: | |
1505 | case Opt_uqnoenforce: | |
149e53af | 1506 | parsing_mp->m_qflags |= XFS_UQUOTA_ACCT; |
0f98b4ec | 1507 | parsing_mp->m_qflags &= ~XFS_UQUOTA_ENFD; |
d5d9dd5b | 1508 | parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; |
8757c38f IK |
1509 | return 0; |
1510 | case Opt_pquota: | |
1511 | case Opt_prjquota: | |
149e53af | 1512 | parsing_mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ENFD); |
d5d9dd5b | 1513 | parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; |
8757c38f IK |
1514 | return 0; |
1515 | case Opt_pqnoenforce: | |
149e53af | 1516 | parsing_mp->m_qflags |= XFS_PQUOTA_ACCT; |
0f98b4ec | 1517 | parsing_mp->m_qflags &= ~XFS_PQUOTA_ENFD; |
d5d9dd5b | 1518 | parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; |
8757c38f IK |
1519 | return 0; |
1520 | case Opt_gquota: | |
1521 | case Opt_grpquota: | |
149e53af | 1522 | parsing_mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ENFD); |
d5d9dd5b | 1523 | parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; |
8757c38f IK |
1524 | return 0; |
1525 | case Opt_gqnoenforce: | |
149e53af | 1526 | parsing_mp->m_qflags |= XFS_GQUOTA_ACCT; |
0f98b4ec | 1527 | parsing_mp->m_qflags &= ~XFS_GQUOTA_ENFD; |
d5d9dd5b | 1528 | parsing_mp->m_qflags |= XFS_QFLAGS_MNTOPTS; |
8757c38f IK |
1529 | return 0; |
1530 | case Opt_discard: | |
0560f31a | 1531 | parsing_mp->m_features |= XFS_FEAT_DISCARD; |
8757c38f IK |
1532 | return 0; |
1533 | case Opt_nodiscard: | |
0560f31a | 1534 | parsing_mp->m_features &= ~XFS_FEAT_DISCARD; |
8757c38f IK |
1535 | return 0; |
1536 | #ifdef CONFIG_FS_DAX | |
1537 | case Opt_dax: | |
0f98b4ec | 1538 | xfs_mount_set_dax_mode(parsing_mp, XFS_DAX_ALWAYS); |
8d6c3446 IW |
1539 | return 0; |
1540 | case Opt_dax_enum: | |
0f98b4ec | 1541 | xfs_mount_set_dax_mode(parsing_mp, result.uint_32); |
8757c38f IK |
1542 | return 0; |
1543 | #endif | |
c23c393e PR |
1544 | /* Following mount options will be removed in September 2025 */ |
1545 | case Opt_ikeep: | |
0560f31a DC |
1546 | xfs_fs_warn_deprecated(fc, param, XFS_FEAT_IKEEP, true); |
1547 | parsing_mp->m_features |= XFS_FEAT_IKEEP; | |
c23c393e PR |
1548 | return 0; |
1549 | case Opt_noikeep: | |
0560f31a DC |
1550 | xfs_fs_warn_deprecated(fc, param, XFS_FEAT_IKEEP, false); |
1551 | parsing_mp->m_features &= ~XFS_FEAT_IKEEP; | |
c23c393e PR |
1552 | return 0; |
1553 | case Opt_attr2: | |
0560f31a DC |
1554 | xfs_fs_warn_deprecated(fc, param, XFS_FEAT_ATTR2, true); |
1555 | parsing_mp->m_features |= XFS_FEAT_ATTR2; | |
c23c393e PR |
1556 | return 0; |
1557 | case Opt_noattr2: | |
0560f31a DC |
1558 | xfs_fs_warn_deprecated(fc, param, XFS_FEAT_NOATTR2, true); |
1559 | parsing_mp->m_features |= XFS_FEAT_NOATTR2; | |
c23c393e | 1560 | return 0; |
7452a6da CH |
1561 | case Opt_max_open_zones: |
1562 | parsing_mp->m_max_open_zones = result.uint_32; | |
1563 | return 0; | |
64d03611 HH |
1564 | case Opt_lifetime: |
1565 | parsing_mp->m_features &= ~XFS_FEAT_NOLIFETIME; | |
1566 | return 0; | |
1567 | case Opt_nolifetime: | |
1568 | parsing_mp->m_features |= XFS_FEAT_NOLIFETIME; | |
1569 | return 0; | |
4528b905 DW |
1570 | case Opt_max_atomic_write: |
1571 | if (suffix_kstrtoull(param->string, 10, | |
1572 | &parsing_mp->m_awu_max_bytes)) { | |
1573 | xfs_warn(parsing_mp, | |
1574 | "max atomic write size must be positive integer"); | |
1575 | return -EINVAL; | |
1576 | } | |
1577 | return 0; | |
8757c38f | 1578 | default: |
0f98b4ec | 1579 | xfs_warn(parsing_mp, "unknown mount option [%s].", param->key); |
8757c38f IK |
1580 | return -EINVAL; |
1581 | } | |
d5db0f97 | 1582 | |
d5db0f97 ES |
1583 | return 0; |
1584 | } | |
1585 | ||
8757c38f | 1586 | static int |
1e5c39df | 1587 | xfs_fs_validate_params( |
f8f15e42 CH |
1588 | struct xfs_mount *mp) |
1589 | { | |
0560f31a | 1590 | /* No recovery flag requires a read-only mount */ |
2e973b2c | 1591 | if (xfs_has_norecovery(mp) && !xfs_is_readonly(mp)) { |
8757c38f | 1592 | xfs_warn(mp, "no-recovery mounts must be read-only."); |
2451337d | 1593 | return -EINVAL; |
d3eaace8 DC |
1594 | } |
1595 | ||
d3eaace8 | 1596 | /* |
0560f31a DC |
1597 | * We have not read the superblock at this point, so only the attr2 |
1598 | * mount option can set the attr2 feature by this stage. | |
d3eaace8 | 1599 | */ |
0560f31a | 1600 | if (xfs_has_attr2(mp) && xfs_has_noattr2(mp)) { |
e23b55d5 | 1601 | xfs_warn(mp, "attr2 and noattr2 cannot both be specified."); |
2451337d | 1602 | return -EINVAL; |
d3eaace8 DC |
1603 | } |
1604 | ||
e23b55d5 | 1605 | |
0560f31a | 1606 | if (xfs_has_noalign(mp) && (mp->m_dalign || mp->m_swidth)) { |
4f10700a | 1607 | xfs_warn(mp, |
8757c38f IK |
1608 | "sunit and swidth options incompatible with the noalign option"); |
1609 | return -EINVAL; | |
f8f15e42 CH |
1610 | } |
1611 | ||
d5d9dd5b DW |
1612 | if (!IS_ENABLED(CONFIG_XFS_QUOTA) && |
1613 | (mp->m_qflags & ~XFS_QFLAGS_MNTOPTS)) { | |
8757c38f | 1614 | xfs_warn(mp, "quota support not available in this kernel."); |
2451337d | 1615 | return -EINVAL; |
d892d586 CS |
1616 | } |
1617 | ||
8757c38f IK |
1618 | if ((mp->m_dalign && !mp->m_swidth) || |
1619 | (!mp->m_dalign && mp->m_swidth)) { | |
1620 | xfs_warn(mp, "sunit and swidth must be specified together"); | |
1621 | return -EINVAL; | |
1622 | } | |
5681ca40 | 1623 | |
8757c38f IK |
1624 | if (mp->m_dalign && (mp->m_swidth % mp->m_dalign != 0)) { |
1625 | xfs_warn(mp, | |
1626 | "stripe width (%d) must be a multiple of the stripe unit (%d)", | |
1627 | mp->m_swidth, mp->m_dalign); | |
1628 | return -EINVAL; | |
1629 | } | |
5681ca40 | 1630 | |
8757c38f IK |
1631 | if (mp->m_logbufs != -1 && |
1632 | mp->m_logbufs != 0 && | |
1633 | (mp->m_logbufs < XLOG_MIN_ICLOGS || | |
1634 | mp->m_logbufs > XLOG_MAX_ICLOGS)) { | |
1635 | xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]", | |
1636 | mp->m_logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS); | |
1637 | return -EINVAL; | |
1638 | } | |
5681ca40 | 1639 | |
8757c38f IK |
1640 | if (mp->m_logbsize != -1 && |
1641 | mp->m_logbsize != 0 && | |
1642 | (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE || | |
1643 | mp->m_logbsize > XLOG_MAX_RECORD_BSIZE || | |
1644 | !is_power_of_2(mp->m_logbsize))) { | |
1645 | xfs_warn(mp, | |
1646 | "invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]", | |
1647 | mp->m_logbsize); | |
1648 | return -EINVAL; | |
1649 | } | |
5681ca40 | 1650 | |
0560f31a | 1651 | if (xfs_has_allocsize(mp) && |
8757c38f IK |
1652 | (mp->m_allocsize_log > XFS_MAX_IO_LOG || |
1653 | mp->m_allocsize_log < XFS_MIN_IO_LOG)) { | |
1654 | xfs_warn(mp, "invalid log iosize: %d [not %d-%d]", | |
1655 | mp->m_allocsize_log, XFS_MIN_IO_LOG, XFS_MAX_IO_LOG); | |
1656 | return -EINVAL; | |
1657 | } | |
9fe82b8c | 1658 | |
5681ca40 | 1659 | return 0; |
72c44e35 | 1660 | } |
74394496 | 1661 | |
a76dba3b DW |
1662 | struct dentry * |
1663 | xfs_debugfs_mkdir( | |
1664 | const char *name, | |
1665 | struct dentry *parent) | |
1666 | { | |
1667 | struct dentry *child; | |
1668 | ||
1669 | /* Apparently we're expected to ignore error returns?? */ | |
1670 | child = debugfs_create_dir(name, parent); | |
1671 | if (IS_ERR(child)) | |
1672 | return NULL; | |
1673 | ||
1674 | return child; | |
1675 | } | |
1676 | ||
73e5fff9 | 1677 | static int |
1e5c39df | 1678 | xfs_fs_fill_super( |
72c44e35 | 1679 | struct super_block *sb, |
73e5fff9 | 1680 | struct fs_context *fc) |
72c44e35 | 1681 | { |
73e5fff9 | 1682 | struct xfs_mount *mp = sb->s_fs_info; |
72c44e35 | 1683 | struct inode *root; |
0279c71f | 1684 | int flags = 0, error; |
72c44e35 | 1685 | |
7c89fcb2 | 1686 | mp->m_super = sb; |
1da177e4 | 1687 | |
d8d222e0 DC |
1688 | /* |
1689 | * Copy VFS mount flags from the context now that all parameter parsing | |
1690 | * is guaranteed to have been completed by either the old mount API or | |
1691 | * the newer fsopen/fsconfig API. | |
1692 | */ | |
1693 | if (fc->sb_flags & SB_RDONLY) | |
ca57120d | 1694 | xfs_set_readonly(mp); |
d8d222e0 DC |
1695 | if (fc->sb_flags & SB_DIRSYNC) |
1696 | mp->m_features |= XFS_FEAT_DIRSYNC; | |
1697 | if (fc->sb_flags & SB_SYNCHRONOUS) | |
1698 | mp->m_features |= XFS_FEAT_WSYNC; | |
1699 | ||
1e5c39df | 1700 | error = xfs_fs_validate_params(mp); |
745f6919 | 1701 | if (error) |
2a9311ad | 1702 | return error; |
1da177e4 LT |
1703 | |
1704 | sb_min_blocksize(sb, BBSIZE); | |
0ec58516 | 1705 | sb->s_xattr = xfs_xattr_handlers; |
a50cd269 | 1706 | sb->s_export_op = &xfs_export_operations; |
fcafb71b | 1707 | #ifdef CONFIG_XFS_QUOTA |
a50cd269 | 1708 | sb->s_qcop = &xfs_quotactl_operations; |
17ef4fdd | 1709 | sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ; |
fcafb71b | 1710 | #endif |
a50cd269 | 1711 | sb->s_op = &xfs_super_operations; |
1da177e4 | 1712 | |
dae5cd81 DC |
1713 | /* |
1714 | * Delay mount work if the debug hook is set. This is debug | |
1715 | * instrumention to coordinate simulation of xfs mount failures with | |
1716 | * VFS superblock operations | |
1717 | */ | |
1718 | if (xfs_globals.mount_delay) { | |
1719 | xfs_notice(mp, "Delaying mount for %d seconds.", | |
1720 | xfs_globals.mount_delay); | |
1721 | msleep(xfs_globals.mount_delay * 1000); | |
1722 | } | |
1723 | ||
73e5fff9 | 1724 | if (fc->sb_flags & SB_SILENT) |
f8f15e42 CH |
1725 | flags |= XFS_MFSI_QUIET; |
1726 | ||
9d565ffa | 1727 | error = xfs_open_devices(mp); |
19f354d4 | 1728 | if (error) |
2a9311ad | 1729 | return error; |
f8f15e42 | 1730 | |
a76dba3b DW |
1731 | if (xfs_debugfs) { |
1732 | mp->m_debugfs = xfs_debugfs_mkdir(mp->m_super->s_id, | |
1733 | xfs_debugfs); | |
1734 | } else { | |
1735 | mp->m_debugfs = NULL; | |
1736 | } | |
1737 | ||
2451337d | 1738 | error = xfs_init_mount_workqueues(mp); |
61ba35de | 1739 | if (error) |
35a93b14 | 1740 | goto out_shutdown_devices; |
c962fb79 | 1741 | |
5681ca40 | 1742 | error = xfs_init_percpu_counters(mp); |
aa6bf01d CH |
1743 | if (error) |
1744 | goto out_destroy_workqueues; | |
1745 | ||
ab23a776 DC |
1746 | error = xfs_inodegc_init_percpu(mp); |
1747 | if (error) | |
1748 | goto out_destroy_counters; | |
1749 | ||
225e4635 BD |
1750 | /* Allocate stats memory before we do operations that might use it */ |
1751 | mp->m_stats.xs_stats = alloc_percpu(struct xfsstats); | |
1752 | if (!mp->m_stats.xs_stats) { | |
f9d460b3 | 1753 | error = -ENOMEM; |
ab23a776 | 1754 | goto out_destroy_inodegc; |
225e4635 BD |
1755 | } |
1756 | ||
d7a74cad | 1757 | error = xchk_mount_stats_alloc(mp); |
f8f15e42 | 1758 | if (error) |
225e4635 | 1759 | goto out_free_stats; |
9d565ffa | 1760 | |
d7a74cad DW |
1761 | error = xfs_readsb(mp, flags); |
1762 | if (error) | |
1763 | goto out_free_scrub_stats; | |
1764 | ||
9d565ffa | 1765 | error = xfs_finish_flags(mp); |
f8f15e42 | 1766 | if (error) |
effa2eda | 1767 | goto out_free_sb; |
f8f15e42 | 1768 | |
e34b562c | 1769 | error = xfs_setup_devices(mp); |
19f354d4 | 1770 | if (error) |
effa2eda | 1771 | goto out_free_sb; |
f8f15e42 | 1772 | |
4887e531 CH |
1773 | /* |
1774 | * V4 support is undergoing deprecation. | |
1775 | * | |
1776 | * Note: this has to use an open coded m_features check as xfs_has_crc | |
1777 | * always returns false for !CONFIG_XFS_SUPPORT_V4. | |
1778 | */ | |
1779 | if (!(mp->m_features & XFS_FEAT_CRC)) { | |
1780 | if (!IS_ENABLED(CONFIG_XFS_SUPPORT_V4)) { | |
1781 | xfs_warn(mp, | |
1782 | "Deprecated V4 format (crc=0) not supported by kernel."); | |
1783 | error = -EINVAL; | |
1784 | goto out_free_sb; | |
1785 | } | |
b96cb835 DW |
1786 | xfs_warn_once(mp, |
1787 | "Deprecated V4 format (crc=0) will not be supported after September 2030."); | |
b96cb835 DW |
1788 | } |
1789 | ||
7ba83850 DW |
1790 | /* ASCII case insensitivity is undergoing deprecation. */ |
1791 | if (xfs_has_asciici(mp)) { | |
1792 | #ifdef CONFIG_XFS_SUPPORT_ASCII_CI | |
1793 | xfs_warn_once(mp, | |
1794 | "Deprecated ASCII case-insensitivity feature (ascii-ci=1) will not be supported after September 2030."); | |
1795 | #else | |
1796 | xfs_warn(mp, | |
1797 | "Deprecated ASCII case-insensitivity feature (ascii-ci=1) not supported by kernel."); | |
1798 | error = -EINVAL; | |
1799 | goto out_free_sb; | |
1800 | #endif | |
1801 | } | |
1802 | ||
9e00163c LH |
1803 | /* |
1804 | * Filesystem claims it needs repair, so refuse the mount unless | |
1805 | * norecovery is also specified, in which case the filesystem can | |
1806 | * be mounted with no risk of further damage. | |
1807 | */ | |
1808 | if (xfs_has_needsrepair(mp) && !xfs_has_norecovery(mp)) { | |
80c720b8 DW |
1809 | xfs_warn(mp, "Filesystem needs repair. Please run xfs_repair."); |
1810 | error = -EFSCORRUPTED; | |
1811 | goto out_free_sb; | |
1812 | } | |
1813 | ||
3945ae03 DW |
1814 | /* |
1815 | * Don't touch the filesystem if a user tool thinks it owns the primary | |
1816 | * superblock. mkfs doesn't clear the flag from secondary supers, so | |
1817 | * we don't check them at all. | |
1818 | */ | |
1819 | if (mp->m_sb.sb_inprogress) { | |
1820 | xfs_warn(mp, "Offline file system operation in progress!"); | |
1821 | error = -EFSCORRUPTED; | |
1822 | goto out_free_sb; | |
1823 | } | |
1824 | ||
3945ae03 | 1825 | if (mp->m_sb.sb_blocksize > PAGE_SIZE) { |
7df7c204 PR |
1826 | size_t max_folio_size = mapping_max_folio_size_supported(); |
1827 | ||
1828 | if (!xfs_has_crc(mp)) { | |
1829 | xfs_warn(mp, | |
1830 | "V4 Filesystem with blocksize %d bytes. Only pagesize (%ld) or less is supported.", | |
3945ae03 | 1831 | mp->m_sb.sb_blocksize, PAGE_SIZE); |
7df7c204 PR |
1832 | error = -ENOSYS; |
1833 | goto out_free_sb; | |
1834 | } | |
1835 | ||
1836 | if (mp->m_sb.sb_blocksize > max_folio_size) { | |
1837 | xfs_warn(mp, | |
1838 | "block size (%u bytes) not supported; Only block size (%zu) or less is supported", | |
1839 | mp->m_sb.sb_blocksize, max_folio_size); | |
1840 | error = -ENOSYS; | |
1841 | goto out_free_sb; | |
1842 | } | |
1843 | ||
ecc8065d | 1844 | xfs_warn_experimental(mp, XFS_EXPERIMENTAL_LBS); |
3945ae03 DW |
1845 | } |
1846 | ||
1847 | /* Ensure this filesystem fits in the page cache limits */ | |
1848 | if (xfs_sb_validate_fsb_count(&mp->m_sb, mp->m_sb.sb_dblocks) || | |
1849 | xfs_sb_validate_fsb_count(&mp->m_sb, mp->m_sb.sb_rblocks)) { | |
1850 | xfs_warn(mp, | |
1851 | "file system too large to be mounted on this system."); | |
1852 | error = -EFBIG; | |
1853 | goto out_free_sb; | |
1854 | } | |
1855 | ||
932befe3 DW |
1856 | /* |
1857 | * XFS block mappings use 54 bits to store the logical block offset. | |
1858 | * This should suffice to handle the maximum file size that the VFS | |
1859 | * supports (currently 2^63 bytes on 64-bit and ULONG_MAX << PAGE_SHIFT | |
1860 | * bytes on 32-bit), but as XFS and VFS have gotten the s_maxbytes | |
1861 | * calculation wrong on 32-bit kernels in the past, we'll add a WARN_ON | |
1862 | * to check this assertion. | |
1863 | * | |
1864 | * Avoid integer overflow by comparing the maximum bmbt offset to the | |
1865 | * maximum pagecache offset in units of fs blocks. | |
1866 | */ | |
33005fd0 | 1867 | if (!xfs_verify_fileoff(mp, XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE))) { |
932befe3 DW |
1868 | xfs_warn(mp, |
1869 | "MAX_LFS_FILESIZE block offset (%llu) exceeds extent map maximum (%llu)!", | |
1870 | XFS_B_TO_FSBT(mp, MAX_LFS_FILESIZE), | |
1871 | XFS_MAX_FILEOFF); | |
1872 | error = -EINVAL; | |
1873 | goto out_free_sb; | |
1874 | } | |
1875 | ||
18618e71 | 1876 | error = xfs_rtmount_readsb(mp); |
f8f15e42 | 1877 | if (error) |
effa2eda | 1878 | goto out_free_sb; |
f8f15e42 | 1879 | |
18618e71 DW |
1880 | error = xfs_filestream_mount(mp); |
1881 | if (error) | |
1882 | goto out_free_rtsb; | |
1883 | ||
704b2907 DC |
1884 | /* |
1885 | * we must configure the block size in the superblock before we run the | |
1886 | * full mount process as the mount process can lookup and cache inodes. | |
704b2907 | 1887 | */ |
dddde68b | 1888 | sb->s_magic = XFS_SUPER_MAGIC; |
4ca488eb CH |
1889 | sb->s_blocksize = mp->m_sb.sb_blocksize; |
1890 | sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; | |
932befe3 | 1891 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
8de52778 | 1892 | sb->s_max_links = XFS_MAXLINK; |
1da177e4 | 1893 | sb->s_time_gran = 1; |
38c26bfd | 1894 | if (xfs_has_bigtime(mp)) { |
f93e5436 DW |
1895 | sb->s_time_min = xfs_bigtime_to_unix(XFS_BIGTIME_TIME_MIN); |
1896 | sb->s_time_max = xfs_bigtime_to_unix(XFS_BIGTIME_TIME_MAX); | |
1897 | } else { | |
1898 | sb->s_time_min = XFS_LEGACY_TIME_MIN; | |
1899 | sb->s_time_max = XFS_LEGACY_TIME_MAX; | |
1900 | } | |
06dbf82b | 1901 | trace_xfs_inode_timestamp_range(mp, sb->s_time_min, sb->s_time_max); |
5121711e | 1902 | sb->s_iflags |= SB_I_CGROUPWB | SB_I_ALLOW_HSM; |
adfb5fb4 | 1903 | |
1da177e4 LT |
1904 | set_posix_acl_flag(sb); |
1905 | ||
dc037ad7 | 1906 | /* version 5 superblocks support inode version counters. */ |
d6837c1a | 1907 | if (xfs_has_crc(mp)) |
357fdad0 | 1908 | sb->s_flags |= SB_I_VERSION; |
dc037ad7 | 1909 | |
0560f31a | 1910 | if (xfs_has_dax_always(mp)) { |
679a9949 CH |
1911 | error = xfs_setup_dax_always(mp); |
1912 | if (error) | |
b6e03c10 | 1913 | goto out_filestream_unmount; |
cbe4dab1 DC |
1914 | } |
1915 | ||
70200574 CH |
1916 | if (xfs_has_discard(mp) && !bdev_max_discard_sectors(sb->s_bdev)) { |
1917 | xfs_warn(mp, | |
1918 | "mounting with \"discard\" option, but the device does not support discard"); | |
1919 | mp->m_features &= ~XFS_FEAT_DISCARD; | |
1e6fa688 KN |
1920 | } |
1921 | ||
2167eaab CH |
1922 | if (xfs_has_zoned(mp)) { |
1923 | if (!xfs_has_metadir(mp)) { | |
1924 | xfs_alert(mp, | |
1925 | "metadir feature required for zoned realtime devices."); | |
1926 | error = -EINVAL; | |
1927 | goto out_filestream_unmount; | |
1928 | } | |
1929 | xfs_warn_experimental(mp, XFS_EXPERIMENTAL_ZONED); | |
1930 | } else if (xfs_has_metadir(mp)) { | |
4f3d4dd1 | 1931 | xfs_warn_experimental(mp, XFS_EXPERIMENTAL_METADIR); |
2167eaab | 1932 | } |
4f3d4dd1 | 1933 | |
38c26bfd | 1934 | if (xfs_has_reflink(mp)) { |
155debbe DW |
1935 | if (xfs_has_realtime(mp) && |
1936 | !xfs_reflink_supports_rextsize(mp, mp->m_sb.sb_rextsize)) { | |
66ae56a5 | 1937 | xfs_alert(mp, |
155debbe DW |
1938 | "reflink not compatible with realtime extent size %u!", |
1939 | mp->m_sb.sb_rextsize); | |
66ae56a5 CH |
1940 | error = -EINVAL; |
1941 | goto out_filestream_unmount; | |
1942 | } | |
1943 | ||
af4f8833 CH |
1944 | if (xfs_has_zoned(mp)) { |
1945 | xfs_alert(mp, | |
1946 | "reflink not compatible with zoned RT device!"); | |
1947 | error = -EINVAL; | |
1948 | goto out_filestream_unmount; | |
1949 | } | |
1950 | ||
66ae56a5 CH |
1951 | if (xfs_globals.always_cow) { |
1952 | xfs_info(mp, "using DEBUG-only always_cow mode."); | |
1953 | mp->m_always_cow = true; | |
1954 | } | |
c14632dd DW |
1955 | } |
1956 | ||
d5d9dd5b DW |
1957 | /* |
1958 | * If no quota mount options were provided, maybe we'll try to pick | |
1959 | * up the quota accounting and enforcement flags from the ondisk sb. | |
1960 | */ | |
1961 | if (!(mp->m_qflags & XFS_QFLAGS_MNTOPTS)) | |
1962 | xfs_set_resuming_quotaon(mp); | |
1963 | mp->m_qflags &= ~XFS_QFLAGS_MNTOPTS; | |
1518646e | 1964 | |
8a00ebe4 | 1965 | error = xfs_mountfs(mp); |
2bcf6e97 | 1966 | if (error) |
7e18530b | 1967 | goto out_filestream_unmount; |
704b2907 | 1968 | |
01651646 | 1969 | root = igrab(VFS_I(mp->m_rootip)); |
f3dcc13f | 1970 | if (!root) { |
2451337d | 1971 | error = -ENOENT; |
8a00ebe4 | 1972 | goto out_unmount; |
cbc89dcf | 1973 | } |
48fde701 | 1974 | sb->s_root = d_make_root(root); |
f3dcc13f | 1975 | if (!sb->s_root) { |
2451337d | 1976 | error = -ENOMEM; |
8a00ebe4 | 1977 | goto out_unmount; |
1da177e4 | 1978 | } |
74394496 | 1979 | |
1da177e4 | 1980 | return 0; |
33c7a2bc | 1981 | |
7e18530b | 1982 | out_filestream_unmount: |
120226c1 | 1983 | xfs_filestream_unmount(mp); |
18618e71 DW |
1984 | out_free_rtsb: |
1985 | xfs_rtmount_freesb(mp); | |
effa2eda CH |
1986 | out_free_sb: |
1987 | xfs_freesb(mp); | |
d7a74cad DW |
1988 | out_free_scrub_stats: |
1989 | xchk_mount_stats_free(mp); | |
225e4635 BD |
1990 | out_free_stats: |
1991 | free_percpu(mp->m_stats.xs_stats); | |
ab23a776 | 1992 | out_destroy_inodegc: |
ab23a776 | 1993 | xfs_inodegc_free_percpu(mp); |
9d565ffa | 1994 | out_destroy_counters: |
5681ca40 | 1995 | xfs_destroy_percpu_counters(mp); |
225e4635 | 1996 | out_destroy_workqueues: |
aa6bf01d | 1997 | xfs_destroy_mount_workqueues(mp); |
35a93b14 CH |
1998 | out_shutdown_devices: |
1999 | xfs_shutdown_devices(mp); | |
2451337d | 2000 | return error; |
f8f15e42 | 2001 | |
2bcf6e97 | 2002 | out_unmount: |
e48ad316 | 2003 | xfs_filestream_unmount(mp); |
19f354d4 | 2004 | xfs_unmountfs(mp); |
18618e71 | 2005 | goto out_free_rtsb; |
1da177e4 LT |
2006 | } |
2007 | ||
73e5fff9 | 2008 | static int |
1e5c39df | 2009 | xfs_fs_get_tree( |
73e5fff9 IK |
2010 | struct fs_context *fc) |
2011 | { | |
1e5c39df | 2012 | return get_tree_bdev(fc, xfs_fs_fill_super); |
73e5fff9 IK |
2013 | } |
2014 | ||
63cd1e9b IK |
2015 | static int |
2016 | xfs_remount_rw( | |
2017 | struct xfs_mount *mp) | |
2018 | { | |
2019 | struct xfs_sb *sbp = &mp->m_sb; | |
2020 | int error; | |
2021 | ||
bfecc409 | 2022 | if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp && |
df3b7e2b | 2023 | xfs_readonly_buftarg(mp->m_logdev_targp)) { |
bfecc409 HH |
2024 | xfs_warn(mp, |
2025 | "ro->rw transition prohibited by read-only logdev"); | |
2026 | return -EACCES; | |
2027 | } | |
2028 | ||
df3b7e2b | 2029 | if (mp->m_rtdev_targp && xfs_readonly_buftarg(mp->m_rtdev_targp)) { |
bfecc409 HH |
2030 | xfs_warn(mp, |
2031 | "ro->rw transition prohibited by read-only rtdev"); | |
2032 | return -EACCES; | |
2033 | } | |
2034 | ||
0560f31a | 2035 | if (xfs_has_norecovery(mp)) { |
63cd1e9b IK |
2036 | xfs_warn(mp, |
2037 | "ro->rw transition prohibited on norecovery mount"); | |
2038 | return -EINVAL; | |
2039 | } | |
2040 | ||
d6837c1a | 2041 | if (xfs_sb_is_v5(sbp) && |
63cd1e9b IK |
2042 | xfs_sb_has_ro_compat_feature(sbp, XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) { |
2043 | xfs_warn(mp, | |
2044 | "ro->rw transition prohibited on unknown (0x%x) ro-compat filesystem", | |
2045 | (sbp->sb_features_ro_compat & | |
2046 | XFS_SB_FEAT_RO_COMPAT_UNKNOWN)); | |
2047 | return -EINVAL; | |
2048 | } | |
2049 | ||
ca57120d | 2050 | xfs_clear_readonly(mp); |
63cd1e9b IK |
2051 | |
2052 | /* | |
2053 | * If this is the first remount to writeable state we might have some | |
2054 | * superblock changes to update. | |
2055 | */ | |
2056 | if (mp->m_update_sb) { | |
2057 | error = xfs_sync_sb(mp, false); | |
2058 | if (error) { | |
2059 | xfs_warn(mp, "failed to write sb changes"); | |
2060 | return error; | |
2061 | } | |
2062 | mp->m_update_sb = false; | |
2063 | } | |
2064 | ||
2065 | /* | |
2066 | * Fill out the reserve pool if it is empty. Use the stashed value if | |
2067 | * it is non-zero, otherwise go with the default. | |
2068 | */ | |
2069 | xfs_restore_resvblks(mp); | |
2070 | xfs_log_work_queue(mp); | |
c9a6526f | 2071 | xfs_blockgc_start(mp); |
63cd1e9b IK |
2072 | |
2073 | /* Create the per-AG metadata reservation pool .*/ | |
2074 | error = xfs_fs_reserve_ag_blocks(mp); | |
2075 | if (error && error != -ENOSPC) | |
2076 | return error; | |
2077 | ||
ab23a776 DC |
2078 | /* Re-enable the background inode inactivation worker. */ |
2079 | xfs_inodegc_start(mp); | |
2080 | ||
080d01c4 CH |
2081 | /* Restart zone reclaim */ |
2082 | xfs_zone_gc_start(mp); | |
2083 | ||
63cd1e9b IK |
2084 | return 0; |
2085 | } | |
2086 | ||
2087 | static int | |
2088 | xfs_remount_ro( | |
2089 | struct xfs_mount *mp) | |
2090 | { | |
089558bc DW |
2091 | struct xfs_icwalk icw = { |
2092 | .icw_flags = XFS_ICWALK_FLAG_SYNC, | |
2093 | }; | |
2094 | int error; | |
63cd1e9b | 2095 | |
b97cca3b DW |
2096 | /* Flush all the dirty data to disk. */ |
2097 | error = sync_filesystem(mp->m_super); | |
2098 | if (error) | |
2099 | return error; | |
2100 | ||
63cd1e9b IK |
2101 | /* |
2102 | * Cancel background eofb scanning so it cannot race with the final | |
2103 | * log force+buftarg wait and deadlock the remount. | |
2104 | */ | |
c9a6526f | 2105 | xfs_blockgc_stop(mp); |
63cd1e9b | 2106 | |
089558bc DW |
2107 | /* |
2108 | * Clear out all remaining COW staging extents and speculative post-EOF | |
2109 | * preallocations so that we don't leave inodes requiring inactivation | |
2110 | * cleanups during reclaim on a read-only mount. We must process every | |
2111 | * cached inode, so this requires a synchronous cache scan. | |
2112 | */ | |
2113 | error = xfs_blockgc_free_space(mp, &icw); | |
63cd1e9b IK |
2114 | if (error) { |
2115 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); | |
2116 | return error; | |
2117 | } | |
2118 | ||
ab23a776 DC |
2119 | /* |
2120 | * Stop the inodegc background worker. xfs_fs_reconfigure already | |
2121 | * flushed all pending inodegc work when it sync'd the filesystem. | |
2122 | * The VFS holds s_umount, so we know that inodes cannot enter | |
2123 | * xfs_fs_destroy_inode during a remount operation. In readonly mode | |
2124 | * we send inodes straight to reclaim, so no inodes will be queued. | |
2125 | */ | |
2126 | xfs_inodegc_stop(mp); | |
2127 | ||
080d01c4 CH |
2128 | /* Stop zone reclaim */ |
2129 | xfs_zone_gc_stop(mp); | |
2130 | ||
63cd1e9b | 2131 | /* Free the per-AG metadata reservation pool. */ |
f30f656e | 2132 | xfs_fs_unreserve_ag_blocks(mp); |
63cd1e9b IK |
2133 | |
2134 | /* | |
2135 | * Before we sync the metadata, we need to free up the reserve block | |
2136 | * pool so that the used block count in the superblock on disk is | |
2137 | * correct at the end of the remount. Stash the current* reserve pool | |
2138 | * size so that if we get remounted rw, we can return it to the same | |
2139 | * size. | |
2140 | */ | |
2141 | xfs_save_resvblks(mp); | |
2142 | ||
ea2064da | 2143 | xfs_log_clean(mp); |
ca57120d | 2144 | xfs_set_readonly(mp); |
63cd1e9b IK |
2145 | |
2146 | return 0; | |
2147 | } | |
2148 | ||
2149 | /* | |
2150 | * Logically we would return an error here to prevent users from believing | |
2151 | * they might have changed mount options using remount which can't be changed. | |
2152 | * | |
2153 | * But unfortunately mount(8) adds all options from mtab and fstab to the mount | |
2154 | * arguments in some cases so we can't blindly reject options, but have to | |
2155 | * check for each specified option if it actually differs from the currently | |
2156 | * set option and only reject it if that's the case. | |
2157 | * | |
2158 | * Until that is implemented we return success for every remount request, and | |
2159 | * silently ignore all options that we can't actually change. | |
2160 | */ | |
2161 | static int | |
1e5c39df | 2162 | xfs_fs_reconfigure( |
63cd1e9b IK |
2163 | struct fs_context *fc) |
2164 | { | |
2165 | struct xfs_mount *mp = XFS_M(fc->root->d_sb); | |
2166 | struct xfs_mount *new_mp = fc->s_fs_info; | |
63cd1e9b IK |
2167 | int flags = fc->sb_flags; |
2168 | int error; | |
2169 | ||
d5d9dd5b DW |
2170 | new_mp->m_qflags &= ~XFS_QFLAGS_MNTOPTS; |
2171 | ||
4750a171 | 2172 | /* version 5 superblocks always support version counters. */ |
d6837c1a | 2173 | if (xfs_has_crc(mp)) |
4750a171 ES |
2174 | fc->sb_flags |= SB_I_VERSION; |
2175 | ||
1e5c39df | 2176 | error = xfs_fs_validate_params(new_mp); |
63cd1e9b IK |
2177 | if (error) |
2178 | return error; | |
2179 | ||
95b61333 NRI |
2180 | /* attr2 -> noattr2 */ |
2181 | if (xfs_has_noattr2(new_mp)) { | |
2182 | if (xfs_has_crc(mp)) { | |
2183 | xfs_warn(mp, | |
2184 | "attr2 is always enabled for a V5 filesystem - can't be changed."); | |
2185 | return -EINVAL; | |
2186 | } | |
2187 | mp->m_features &= ~XFS_FEAT_ATTR2; | |
2188 | mp->m_features |= XFS_FEAT_NOATTR2; | |
2189 | } else if (xfs_has_attr2(new_mp)) { | |
2190 | /* noattr2 -> attr2 */ | |
2191 | mp->m_features &= ~XFS_FEAT_NOATTR2; | |
2192 | mp->m_features |= XFS_FEAT_ATTR2; | |
2193 | } | |
2194 | ||
4528b905 DW |
2195 | /* Validate new max_atomic_write option before making other changes */ |
2196 | if (mp->m_awu_max_bytes != new_mp->m_awu_max_bytes) { | |
2197 | error = xfs_set_max_atomic_write_opt(mp, | |
2198 | new_mp->m_awu_max_bytes); | |
2199 | if (error) | |
2200 | return error; | |
2201 | } | |
2202 | ||
63cd1e9b | 2203 | /* inode32 -> inode64 */ |
0560f31a DC |
2204 | if (xfs_has_small_inums(mp) && !xfs_has_small_inums(new_mp)) { |
2205 | mp->m_features &= ~XFS_FEAT_SMALL_INUMS; | |
d6837c1a | 2206 | mp->m_maxagi = xfs_set_inode_alloc(mp, mp->m_sb.sb_agcount); |
63cd1e9b IK |
2207 | } |
2208 | ||
2209 | /* inode64 -> inode32 */ | |
0560f31a DC |
2210 | if (!xfs_has_small_inums(mp) && xfs_has_small_inums(new_mp)) { |
2211 | mp->m_features |= XFS_FEAT_SMALL_INUMS; | |
d6837c1a | 2212 | mp->m_maxagi = xfs_set_inode_alloc(mp, mp->m_sb.sb_agcount); |
63cd1e9b IK |
2213 | } |
2214 | ||
95b61333 NRI |
2215 | /* |
2216 | * Now that mp has been modified according to the remount options, we | |
2217 | * do a final option validation with xfs_finish_flags() just like it is | |
2218 | * just like it is done during mount. We cannot use | |
2219 | * done during mount. We cannot use xfs_finish_flags() on new_mp as it | |
2220 | * contains only the user given options. | |
2221 | */ | |
2222 | error = xfs_finish_flags(mp); | |
2223 | if (error) | |
2224 | return error; | |
2225 | ||
63cd1e9b | 2226 | /* ro -> rw */ |
2e973b2c | 2227 | if (xfs_is_readonly(mp) && !(flags & SB_RDONLY)) { |
63cd1e9b IK |
2228 | error = xfs_remount_rw(mp); |
2229 | if (error) | |
2230 | return error; | |
2231 | } | |
2232 | ||
2233 | /* rw -> ro */ | |
2e973b2c | 2234 | if (!xfs_is_readonly(mp) && (flags & SB_RDONLY)) { |
63cd1e9b IK |
2235 | error = xfs_remount_ro(mp); |
2236 | if (error) | |
2237 | return error; | |
2238 | } | |
2239 | ||
2240 | return 0; | |
2241 | } | |
2242 | ||
dbbff489 CH |
2243 | static void |
2244 | xfs_fs_free( | |
73e5fff9 IK |
2245 | struct fs_context *fc) |
2246 | { | |
2247 | struct xfs_mount *mp = fc->s_fs_info; | |
2248 | ||
2249 | /* | |
2250 | * mp is stored in the fs_context when it is initialized. | |
2251 | * mp is transferred to the superblock on a successful mount, | |
2252 | * but if an error occurs before the transfer we have to free | |
2253 | * it here. | |
2254 | */ | |
2255 | if (mp) | |
2256 | xfs_mount_free(mp); | |
2257 | } | |
2258 | ||
2259 | static const struct fs_context_operations xfs_context_ops = { | |
1e5c39df DW |
2260 | .parse_param = xfs_fs_parse_param, |
2261 | .get_tree = xfs_fs_get_tree, | |
2262 | .reconfigure = xfs_fs_reconfigure, | |
2263 | .free = xfs_fs_free, | |
73e5fff9 IK |
2264 | }; |
2265 | ||
d8d222e0 DC |
2266 | /* |
2267 | * WARNING: do not initialise any parameters in this function that depend on | |
2268 | * mount option parsing having already been performed as this can be called from | |
2269 | * fsopen() before any parameters have been set. | |
2270 | */ | |
e9c4d8bf CH |
2271 | static int |
2272 | xfs_init_fs_context( | |
73e5fff9 IK |
2273 | struct fs_context *fc) |
2274 | { | |
2275 | struct xfs_mount *mp; | |
e9c4d8bf | 2276 | int i; |
73e5fff9 | 2277 | |
f078d4ea | 2278 | mp = kzalloc(sizeof(struct xfs_mount), GFP_KERNEL | __GFP_NOFAIL); |
73e5fff9 IK |
2279 | if (!mp) |
2280 | return -ENOMEM; | |
2281 | ||
50f83009 | 2282 | spin_lock_init(&mp->m_sb_lock); |
e9c4d8bf CH |
2283 | for (i = 0; i < XG_TYPE_MAX; i++) |
2284 | xa_init(&mp->m_groups[i].xa); | |
50f83009 | 2285 | mutex_init(&mp->m_growlock); |
1df8d750 | 2286 | mutex_init(&mp->m_metafile_resv_lock); |
f0f7a674 | 2287 | INIT_WORK(&mp->m_flush_inodes_work, xfs_flush_inodes_worker); |
50f83009 | 2288 | INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker); |
50f83009 IK |
2289 | mp->m_kobj.kobject.kset = xfs_kset; |
2290 | /* | |
2291 | * We don't create the finobt per-ag space reservation until after log | |
2292 | * recovery, so we must set this to true so that an ifree transaction | |
2293 | * started during log recovery will not depend on space reservations | |
2294 | * for finobt expansion. | |
2295 | */ | |
2296 | mp->m_finobt_nores = true; | |
2297 | ||
73e5fff9 IK |
2298 | /* |
2299 | * These can be overridden by the mount option parsing. | |
2300 | */ | |
2301 | mp->m_logbufs = -1; | |
2302 | mp->m_logbsize = -1; | |
2303 | mp->m_allocsize_log = 16; /* 64k */ | |
2304 | ||
86a1746e DW |
2305 | xfs_hooks_init(&mp->m_dir_update_hooks); |
2306 | ||
73e5fff9 IK |
2307 | fc->s_fs_info = mp; |
2308 | fc->ops = &xfs_context_ops; | |
2309 | ||
2310 | return 0; | |
2311 | } | |
2312 | ||
2a9311ad CH |
2313 | static void |
2314 | xfs_kill_sb( | |
2315 | struct super_block *sb) | |
2316 | { | |
2317 | kill_block_super(sb); | |
2318 | xfs_mount_free(XFS_M(sb)); | |
2319 | } | |
2320 | ||
5085b607 | 2321 | static struct file_system_type xfs_fs_type = { |
1da177e4 LT |
2322 | .owner = THIS_MODULE, |
2323 | .name = "xfs", | |
73e5fff9 | 2324 | .init_fs_context = xfs_init_fs_context, |
d7167b14 | 2325 | .parameters = xfs_fs_parameters, |
2a9311ad | 2326 | .kill_sb = xfs_kill_sb, |
a64e5a59 LC |
2327 | .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP | FS_MGTIME | |
2328 | FS_LBS, | |
1da177e4 | 2329 | }; |
7f78e035 | 2330 | MODULE_ALIAS_FS("xfs"); |
1da177e4 | 2331 | |
9f8868ff | 2332 | STATIC int __init |
182696fb | 2333 | xfs_init_caches(void) |
9f8868ff | 2334 | { |
9fa47bdc DW |
2335 | int error; |
2336 | ||
231f91ab DC |
2337 | xfs_buf_cache = kmem_cache_create("xfs_buf", sizeof(struct xfs_buf), 0, |
2338 | SLAB_HWCACHE_ALIGN | | |
f88c3fb8 | 2339 | SLAB_RECLAIM_ACCOUNT, |
231f91ab DC |
2340 | NULL); |
2341 | if (!xfs_buf_cache) | |
2342 | goto out; | |
2343 | ||
182696fb | 2344 | xfs_log_ticket_cache = kmem_cache_create("xfs_log_ticket", |
b1231760 CM |
2345 | sizeof(struct xlog_ticket), |
2346 | 0, 0, NULL); | |
182696fb | 2347 | if (!xfs_log_ticket_cache) |
231f91ab | 2348 | goto out_destroy_buf_cache; |
9f8868ff | 2349 | |
9fa47bdc DW |
2350 | error = xfs_btree_init_cur_caches(); |
2351 | if (error) | |
c201d9ca | 2352 | goto out_destroy_log_ticket_cache; |
9f8868ff | 2353 | |
7fbaab57 | 2354 | error = rcbagbt_init_cur_cache(); |
f3c799c2 DW |
2355 | if (error) |
2356 | goto out_destroy_btree_cur_cache; | |
2357 | ||
7fbaab57 DW |
2358 | error = xfs_defer_init_item_caches(); |
2359 | if (error) | |
2360 | goto out_destroy_rcbagbt_cur_cache; | |
2361 | ||
182696fb | 2362 | xfs_da_state_cache = kmem_cache_create("xfs_da_state", |
b1231760 CM |
2363 | sizeof(struct xfs_da_state), |
2364 | 0, 0, NULL); | |
182696fb | 2365 | if (!xfs_da_state_cache) |
f3c799c2 | 2366 | goto out_destroy_defer_item_cache; |
9f8868ff | 2367 | |
182696fb | 2368 | xfs_ifork_cache = kmem_cache_create("xfs_ifork", |
b1231760 CM |
2369 | sizeof(struct xfs_ifork), |
2370 | 0, 0, NULL); | |
182696fb DW |
2371 | if (!xfs_ifork_cache) |
2372 | goto out_destroy_da_state_cache; | |
9f8868ff | 2373 | |
182696fb | 2374 | xfs_trans_cache = kmem_cache_create("xfs_trans", |
b1231760 CM |
2375 | sizeof(struct xfs_trans), |
2376 | 0, 0, NULL); | |
182696fb DW |
2377 | if (!xfs_trans_cache) |
2378 | goto out_destroy_ifork_cache; | |
9f8868ff | 2379 | |
e98c414f | 2380 | |
9f8868ff | 2381 | /* |
182696fb | 2382 | * The size of the cache-allocated buf log item is the maximum |
9f8868ff CH |
2383 | * size possible under XFS. This wastes a little bit of memory, |
2384 | * but it is much faster. | |
2385 | */ | |
182696fb | 2386 | xfs_buf_item_cache = kmem_cache_create("xfs_buf_item", |
b1231760 CM |
2387 | sizeof(struct xfs_buf_log_item), |
2388 | 0, 0, NULL); | |
182696fb DW |
2389 | if (!xfs_buf_item_cache) |
2390 | goto out_destroy_trans_cache; | |
9f8868ff | 2391 | |
182696fb | 2392 | xfs_efd_cache = kmem_cache_create("xfs_efd_item", |
3c5aaace DW |
2393 | xfs_efd_log_item_sizeof(XFS_EFD_MAX_FAST_EXTENTS), |
2394 | 0, 0, NULL); | |
182696fb DW |
2395 | if (!xfs_efd_cache) |
2396 | goto out_destroy_buf_item_cache; | |
9f8868ff | 2397 | |
182696fb | 2398 | xfs_efi_cache = kmem_cache_create("xfs_efi_item", |
3c5aaace DW |
2399 | xfs_efi_log_item_sizeof(XFS_EFI_MAX_FAST_EXTENTS), |
2400 | 0, 0, NULL); | |
182696fb DW |
2401 | if (!xfs_efi_cache) |
2402 | goto out_destroy_efd_cache; | |
9f8868ff | 2403 | |
182696fb | 2404 | xfs_inode_cache = kmem_cache_create("xfs_inode", |
b1231760 CM |
2405 | sizeof(struct xfs_inode), 0, |
2406 | (SLAB_HWCACHE_ALIGN | | |
2407 | SLAB_RECLAIM_ACCOUNT | | |
f88c3fb8 | 2408 | SLAB_ACCOUNT), |
b1231760 | 2409 | xfs_fs_inode_init_once); |
182696fb DW |
2410 | if (!xfs_inode_cache) |
2411 | goto out_destroy_efi_cache; | |
9f8868ff | 2412 | |
182696fb | 2413 | xfs_ili_cache = kmem_cache_create("xfs_ili", |
b1231760 | 2414 | sizeof(struct xfs_inode_log_item), 0, |
f88c3fb8 | 2415 | SLAB_RECLAIM_ACCOUNT, |
d59eadae | 2416 | NULL); |
182696fb DW |
2417 | if (!xfs_ili_cache) |
2418 | goto out_destroy_inode_cache; | |
b1231760 | 2419 | |
182696fb | 2420 | xfs_icreate_cache = kmem_cache_create("xfs_icr", |
b1231760 CM |
2421 | sizeof(struct xfs_icreate_item), |
2422 | 0, 0, NULL); | |
182696fb DW |
2423 | if (!xfs_icreate_cache) |
2424 | goto out_destroy_ili_cache; | |
9f8868ff | 2425 | |
182696fb | 2426 | xfs_rud_cache = kmem_cache_create("xfs_rud_item", |
b1231760 CM |
2427 | sizeof(struct xfs_rud_log_item), |
2428 | 0, 0, NULL); | |
182696fb DW |
2429 | if (!xfs_rud_cache) |
2430 | goto out_destroy_icreate_cache; | |
5880f2d7 | 2431 | |
182696fb | 2432 | xfs_rui_cache = kmem_cache_create("xfs_rui_item", |
cd00158c | 2433 | xfs_rui_log_item_sizeof(XFS_RUI_MAX_FAST_EXTENTS), |
b1231760 | 2434 | 0, 0, NULL); |
182696fb DW |
2435 | if (!xfs_rui_cache) |
2436 | goto out_destroy_rud_cache; | |
5880f2d7 | 2437 | |
182696fb | 2438 | xfs_cud_cache = kmem_cache_create("xfs_cud_item", |
b1231760 CM |
2439 | sizeof(struct xfs_cud_log_item), |
2440 | 0, 0, NULL); | |
182696fb DW |
2441 | if (!xfs_cud_cache) |
2442 | goto out_destroy_rui_cache; | |
baf4bcac | 2443 | |
182696fb | 2444 | xfs_cui_cache = kmem_cache_create("xfs_cui_item", |
baf4bcac | 2445 | xfs_cui_log_item_sizeof(XFS_CUI_MAX_FAST_EXTENTS), |
b1231760 | 2446 | 0, 0, NULL); |
182696fb DW |
2447 | if (!xfs_cui_cache) |
2448 | goto out_destroy_cud_cache; | |
baf4bcac | 2449 | |
182696fb | 2450 | xfs_bud_cache = kmem_cache_create("xfs_bud_item", |
b1231760 CM |
2451 | sizeof(struct xfs_bud_log_item), |
2452 | 0, 0, NULL); | |
182696fb DW |
2453 | if (!xfs_bud_cache) |
2454 | goto out_destroy_cui_cache; | |
6413a014 | 2455 | |
182696fb | 2456 | xfs_bui_cache = kmem_cache_create("xfs_bui_item", |
6413a014 | 2457 | xfs_bui_log_item_sizeof(XFS_BUI_MAX_FAST_EXTENTS), |
b1231760 | 2458 | 0, 0, NULL); |
182696fb DW |
2459 | if (!xfs_bui_cache) |
2460 | goto out_destroy_bud_cache; | |
6413a014 | 2461 | |
4136e38a DW |
2462 | xfs_attrd_cache = kmem_cache_create("xfs_attrd_item", |
2463 | sizeof(struct xfs_attrd_log_item), | |
2464 | 0, 0, NULL); | |
2465 | if (!xfs_attrd_cache) | |
2466 | goto out_destroy_bui_cache; | |
2467 | ||
2468 | xfs_attri_cache = kmem_cache_create("xfs_attri_item", | |
2469 | sizeof(struct xfs_attri_log_item), | |
2470 | 0, 0, NULL); | |
2471 | if (!xfs_attri_cache) | |
2472 | goto out_destroy_attrd_cache; | |
2473 | ||
784eb7d8 DC |
2474 | xfs_iunlink_cache = kmem_cache_create("xfs_iul_item", |
2475 | sizeof(struct xfs_iunlink_item), | |
2476 | 0, 0, NULL); | |
2477 | if (!xfs_iunlink_cache) | |
2478 | goto out_destroy_attri_cache; | |
2479 | ||
6c08f434 DW |
2480 | xfs_xmd_cache = kmem_cache_create("xfs_xmd_item", |
2481 | sizeof(struct xfs_xmd_log_item), | |
2482 | 0, 0, NULL); | |
2483 | if (!xfs_xmd_cache) | |
2484 | goto out_destroy_iul_cache; | |
2485 | ||
2486 | xfs_xmi_cache = kmem_cache_create("xfs_xmi_item", | |
2487 | sizeof(struct xfs_xmi_log_item), | |
2488 | 0, 0, NULL); | |
2489 | if (!xfs_xmi_cache) | |
2490 | goto out_destroy_xmd_cache; | |
2491 | ||
b7c62d90 AH |
2492 | xfs_parent_args_cache = kmem_cache_create("xfs_parent_args", |
2493 | sizeof(struct xfs_parent_args), | |
2494 | 0, 0, NULL); | |
2495 | if (!xfs_parent_args_cache) | |
2496 | goto out_destroy_xmi_cache; | |
2497 | ||
9f8868ff CH |
2498 | return 0; |
2499 | ||
b7c62d90 AH |
2500 | out_destroy_xmi_cache: |
2501 | kmem_cache_destroy(xfs_xmi_cache); | |
6c08f434 DW |
2502 | out_destroy_xmd_cache: |
2503 | kmem_cache_destroy(xfs_xmd_cache); | |
2504 | out_destroy_iul_cache: | |
2505 | kmem_cache_destroy(xfs_iunlink_cache); | |
784eb7d8 DC |
2506 | out_destroy_attri_cache: |
2507 | kmem_cache_destroy(xfs_attri_cache); | |
4136e38a DW |
2508 | out_destroy_attrd_cache: |
2509 | kmem_cache_destroy(xfs_attrd_cache); | |
2510 | out_destroy_bui_cache: | |
2511 | kmem_cache_destroy(xfs_bui_cache); | |
182696fb DW |
2512 | out_destroy_bud_cache: |
2513 | kmem_cache_destroy(xfs_bud_cache); | |
2514 | out_destroy_cui_cache: | |
2515 | kmem_cache_destroy(xfs_cui_cache); | |
2516 | out_destroy_cud_cache: | |
2517 | kmem_cache_destroy(xfs_cud_cache); | |
2518 | out_destroy_rui_cache: | |
2519 | kmem_cache_destroy(xfs_rui_cache); | |
2520 | out_destroy_rud_cache: | |
2521 | kmem_cache_destroy(xfs_rud_cache); | |
2522 | out_destroy_icreate_cache: | |
2523 | kmem_cache_destroy(xfs_icreate_cache); | |
2524 | out_destroy_ili_cache: | |
2525 | kmem_cache_destroy(xfs_ili_cache); | |
2526 | out_destroy_inode_cache: | |
2527 | kmem_cache_destroy(xfs_inode_cache); | |
2528 | out_destroy_efi_cache: | |
2529 | kmem_cache_destroy(xfs_efi_cache); | |
2530 | out_destroy_efd_cache: | |
2531 | kmem_cache_destroy(xfs_efd_cache); | |
2532 | out_destroy_buf_item_cache: | |
2533 | kmem_cache_destroy(xfs_buf_item_cache); | |
2534 | out_destroy_trans_cache: | |
2535 | kmem_cache_destroy(xfs_trans_cache); | |
2536 | out_destroy_ifork_cache: | |
2537 | kmem_cache_destroy(xfs_ifork_cache); | |
2538 | out_destroy_da_state_cache: | |
2539 | kmem_cache_destroy(xfs_da_state_cache); | |
f3c799c2 DW |
2540 | out_destroy_defer_item_cache: |
2541 | xfs_defer_destroy_item_caches(); | |
7fbaab57 DW |
2542 | out_destroy_rcbagbt_cur_cache: |
2543 | rcbagbt_destroy_cur_cache(); | |
182696fb | 2544 | out_destroy_btree_cur_cache: |
9fa47bdc | 2545 | xfs_btree_destroy_cur_caches(); |
182696fb DW |
2546 | out_destroy_log_ticket_cache: |
2547 | kmem_cache_destroy(xfs_log_ticket_cache); | |
231f91ab DC |
2548 | out_destroy_buf_cache: |
2549 | kmem_cache_destroy(xfs_buf_cache); | |
9f8868ff CH |
2550 | out: |
2551 | return -ENOMEM; | |
2552 | } | |
2553 | ||
2554 | STATIC void | |
182696fb | 2555 | xfs_destroy_caches(void) |
9f8868ff | 2556 | { |
8c0a8537 KS |
2557 | /* |
2558 | * Make sure all delayed rcu free are flushed before we | |
2559 | * destroy caches. | |
2560 | */ | |
2561 | rcu_barrier(); | |
b7c62d90 | 2562 | kmem_cache_destroy(xfs_parent_args_cache); |
6c08f434 DW |
2563 | kmem_cache_destroy(xfs_xmd_cache); |
2564 | kmem_cache_destroy(xfs_xmi_cache); | |
784eb7d8 | 2565 | kmem_cache_destroy(xfs_iunlink_cache); |
4136e38a DW |
2566 | kmem_cache_destroy(xfs_attri_cache); |
2567 | kmem_cache_destroy(xfs_attrd_cache); | |
182696fb DW |
2568 | kmem_cache_destroy(xfs_bui_cache); |
2569 | kmem_cache_destroy(xfs_bud_cache); | |
2570 | kmem_cache_destroy(xfs_cui_cache); | |
2571 | kmem_cache_destroy(xfs_cud_cache); | |
2572 | kmem_cache_destroy(xfs_rui_cache); | |
2573 | kmem_cache_destroy(xfs_rud_cache); | |
2574 | kmem_cache_destroy(xfs_icreate_cache); | |
2575 | kmem_cache_destroy(xfs_ili_cache); | |
2576 | kmem_cache_destroy(xfs_inode_cache); | |
2577 | kmem_cache_destroy(xfs_efi_cache); | |
2578 | kmem_cache_destroy(xfs_efd_cache); | |
2579 | kmem_cache_destroy(xfs_buf_item_cache); | |
2580 | kmem_cache_destroy(xfs_trans_cache); | |
2581 | kmem_cache_destroy(xfs_ifork_cache); | |
2582 | kmem_cache_destroy(xfs_da_state_cache); | |
f3c799c2 | 2583 | xfs_defer_destroy_item_caches(); |
7fbaab57 | 2584 | rcbagbt_destroy_cur_cache(); |
9fa47bdc | 2585 | xfs_btree_destroy_cur_caches(); |
182696fb | 2586 | kmem_cache_destroy(xfs_log_ticket_cache); |
231f91ab | 2587 | kmem_cache_destroy(xfs_buf_cache); |
9f8868ff | 2588 | } |
1da177e4 | 2589 | |
0bf6a5bd DC |
2590 | STATIC int __init |
2591 | xfs_init_workqueues(void) | |
2592 | { | |
c999a223 DC |
2593 | /* |
2594 | * The allocation workqueue can be used in memory reclaim situations | |
2595 | * (writepage path), and parallelism is only limited by the number of | |
2596 | * AGs in all the filesystems mounted. Hence use the default large | |
2597 | * max_active value for this workqueue. | |
2598 | */ | |
8018ec08 | 2599 | xfs_alloc_wq = alloc_workqueue("xfsalloc", |
05a302a1 | 2600 | XFS_WQFLAGS(WQ_MEM_RECLAIM | WQ_FREEZABLE), 0); |
c999a223 | 2601 | if (!xfs_alloc_wq) |
5889608d | 2602 | return -ENOMEM; |
c999a223 | 2603 | |
05a302a1 DW |
2604 | xfs_discard_wq = alloc_workqueue("xfsdiscard", XFS_WQFLAGS(WQ_UNBOUND), |
2605 | 0); | |
4560e78f CH |
2606 | if (!xfs_discard_wq) |
2607 | goto out_free_alloc_wq; | |
2608 | ||
0bf6a5bd | 2609 | return 0; |
4560e78f CH |
2610 | out_free_alloc_wq: |
2611 | destroy_workqueue(xfs_alloc_wq); | |
2612 | return -ENOMEM; | |
0bf6a5bd DC |
2613 | } |
2614 | ||
39411f81 | 2615 | STATIC void |
0bf6a5bd DC |
2616 | xfs_destroy_workqueues(void) |
2617 | { | |
4560e78f | 2618 | destroy_workqueue(xfs_discard_wq); |
c999a223 | 2619 | destroy_workqueue(xfs_alloc_wq); |
0bf6a5bd DC |
2620 | } |
2621 | ||
1da177e4 | 2622 | STATIC int __init |
9f8868ff | 2623 | init_xfs_fs(void) |
1da177e4 LT |
2624 | { |
2625 | int error; | |
1da177e4 | 2626 | |
30cbc591 DW |
2627 | xfs_check_ondisk_structs(); |
2628 | ||
3cfb9290 DW |
2629 | error = xfs_dahash_test(); |
2630 | if (error) | |
2631 | return error; | |
2632 | ||
65795910 CH |
2633 | printk(KERN_INFO XFS_VERSION_STRING " with " |
2634 | XFS_BUILD_OPTIONS " enabled\n"); | |
1da177e4 | 2635 | |
9f8868ff | 2636 | xfs_dir_startup(); |
1da177e4 | 2637 | |
182696fb | 2638 | error = xfs_init_caches(); |
f1653c2e | 2639 | if (error) |
ef7d9593 | 2640 | goto out; |
f1653c2e | 2641 | |
0bf6a5bd | 2642 | error = xfs_init_workqueues(); |
9f8868ff | 2643 | if (error) |
182696fb | 2644 | goto out_destroy_caches; |
9f8868ff | 2645 | |
0bf6a5bd DC |
2646 | error = xfs_mru_cache_init(); |
2647 | if (error) | |
2648 | goto out_destroy_wq; | |
2649 | ||
9f8868ff CH |
2650 | error = xfs_init_procfs(); |
2651 | if (error) | |
231f91ab | 2652 | goto out_mru_cache_uninit; |
9f8868ff CH |
2653 | |
2654 | error = xfs_sysctl_register(); | |
2655 | if (error) | |
2656 | goto out_cleanup_procfs; | |
1da177e4 | 2657 | |
a76dba3b DW |
2658 | xfs_debugfs = xfs_debugfs_mkdir("xfs", NULL); |
2659 | ||
3d871226 BF |
2660 | xfs_kset = kset_create_and_add("xfs", NULL, fs_kobj); |
2661 | if (!xfs_kset) { | |
2662 | error = -ENOMEM; | |
a76dba3b | 2663 | goto out_debugfs_unregister; |
3d871226 BF |
2664 | } |
2665 | ||
80529c45 BD |
2666 | xfsstats.xs_kobj.kobject.kset = xfs_kset; |
2667 | ||
2668 | xfsstats.xs_stats = alloc_percpu(struct xfsstats); | |
2669 | if (!xfsstats.xs_stats) { | |
2670 | error = -ENOMEM; | |
2671 | goto out_kset_unregister; | |
2672 | } | |
2673 | ||
2674 | error = xfs_sysfs_init(&xfsstats.xs_kobj, &xfs_stats_ktype, NULL, | |
bb230c12 BD |
2675 | "stats"); |
2676 | if (error) | |
80529c45 | 2677 | goto out_free_stats; |
bb230c12 | 2678 | |
d7a74cad DW |
2679 | error = xchk_global_stats_setup(xfs_debugfs); |
2680 | if (error) | |
2681 | goto out_remove_stats_kobj; | |
2682 | ||
65b65735 BF |
2683 | #ifdef DEBUG |
2684 | xfs_dbg_kobj.kobject.kset = xfs_kset; | |
2685 | error = xfs_sysfs_init(&xfs_dbg_kobj, &xfs_dbg_ktype, NULL, "debug"); | |
a05931ce | 2686 | if (error) |
d7a74cad | 2687 | goto out_remove_scrub_stats; |
65b65735 BF |
2688 | #endif |
2689 | ||
2690 | error = xfs_qm_init(); | |
2691 | if (error) | |
bb230c12 | 2692 | goto out_remove_dbg_kobj; |
1da177e4 LT |
2693 | |
2694 | error = register_filesystem(&xfs_fs_type); | |
2695 | if (error) | |
a05931ce | 2696 | goto out_qm_exit; |
1da177e4 LT |
2697 | return 0; |
2698 | ||
a05931ce CH |
2699 | out_qm_exit: |
2700 | xfs_qm_exit(); | |
bb230c12 | 2701 | out_remove_dbg_kobj: |
65b65735 BF |
2702 | #ifdef DEBUG |
2703 | xfs_sysfs_del(&xfs_dbg_kobj); | |
d7a74cad | 2704 | out_remove_scrub_stats: |
65b65735 | 2705 | #endif |
d7a74cad DW |
2706 | xchk_global_stats_teardown(); |
2707 | out_remove_stats_kobj: | |
80529c45 BD |
2708 | xfs_sysfs_del(&xfsstats.xs_kobj); |
2709 | out_free_stats: | |
2710 | free_percpu(xfsstats.xs_stats); | |
bb230c12 | 2711 | out_kset_unregister: |
3d871226 | 2712 | kset_unregister(xfs_kset); |
a76dba3b DW |
2713 | out_debugfs_unregister: |
2714 | debugfs_remove(xfs_debugfs); | |
9f8868ff CH |
2715 | xfs_sysctl_unregister(); |
2716 | out_cleanup_procfs: | |
2717 | xfs_cleanup_procfs(); | |
9f8868ff CH |
2718 | out_mru_cache_uninit: |
2719 | xfs_mru_cache_uninit(); | |
0bf6a5bd DC |
2720 | out_destroy_wq: |
2721 | xfs_destroy_workqueues(); | |
182696fb DW |
2722 | out_destroy_caches: |
2723 | xfs_destroy_caches(); | |
9f8868ff | 2724 | out: |
1da177e4 LT |
2725 | return error; |
2726 | } | |
2727 | ||
2728 | STATIC void __exit | |
9f8868ff | 2729 | exit_xfs_fs(void) |
1da177e4 | 2730 | { |
a05931ce | 2731 | xfs_qm_exit(); |
1da177e4 | 2732 | unregister_filesystem(&xfs_fs_type); |
65b65735 BF |
2733 | #ifdef DEBUG |
2734 | xfs_sysfs_del(&xfs_dbg_kobj); | |
2735 | #endif | |
d7a74cad | 2736 | xchk_global_stats_teardown(); |
80529c45 BD |
2737 | xfs_sysfs_del(&xfsstats.xs_kobj); |
2738 | free_percpu(xfsstats.xs_stats); | |
3d871226 | 2739 | kset_unregister(xfs_kset); |
a76dba3b | 2740 | debugfs_remove(xfs_debugfs); |
9f8868ff CH |
2741 | xfs_sysctl_unregister(); |
2742 | xfs_cleanup_procfs(); | |
9f8868ff | 2743 | xfs_mru_cache_uninit(); |
0bf6a5bd | 2744 | xfs_destroy_workqueues(); |
182696fb | 2745 | xfs_destroy_caches(); |
af3b6382 | 2746 | xfs_uuid_table_free(); |
1da177e4 LT |
2747 | } |
2748 | ||
2749 | module_init(init_xfs_fs); | |
2750 | module_exit(exit_xfs_fs); | |
2751 | ||
2752 | MODULE_AUTHOR("Silicon Graphics, Inc."); | |
2753 | MODULE_DESCRIPTION(XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled"); | |
2754 | MODULE_LICENSE("GPL"); |