1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include "xfs.h"
19#include "xfs_fs.h"
20#include "xfs_types.h"
21#include "xfs_bit.h"
22#include "xfs_log.h"
23#include "xfs_inum.h"
24#include "xfs_trans.h"
25#include "xfs_sb.h"
26#include "xfs_ag.h"
27#include "xfs_dir2.h"
28#include "xfs_dmapi.h"
29#include "xfs_mount.h"
30#include "xfs_bmap_btree.h"
31#include "xfs_alloc_btree.h"
32#include "xfs_ialloc_btree.h"
33#include "xfs_dir2_sf.h"
34#include "xfs_attr_sf.h"
35#include "xfs_dinode.h"
36#include "xfs_inode.h"
37#include "xfs_btree.h"
38#include "xfs_ialloc.h"
39#include "xfs_alloc.h"
40#include "xfs_rtalloc.h"
41#include "xfs_bmap.h"
42#include "xfs_error.h"
43#include "xfs_rw.h"
44#include "xfs_quota.h"
45#include "xfs_fsops.h"
46#include "xfs_utils.h"
47
48STATIC void xfs_unmountfs_wait(xfs_mount_t *);
49
50
51#ifdef HAVE_PERCPU_SB
52STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t,
53 int);
54STATIC void xfs_icsb_balance_counter_locked(xfs_mount_t *, xfs_sb_field_t,
55 int);
56STATIC int xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t,
57 int64_t, int);
58STATIC void xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t);
59
60#else
61
62#define xfs_icsb_balance_counter(mp, a, b) do { } while (0)
63#define xfs_icsb_balance_counter_locked(mp, a, b) do { } while (0)
64#define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0)
65
66#endif
67
68static const struct {
69 short offset;
70 short type;
71
72
73} xfs_sb_info[] = {
74 { offsetof(xfs_sb_t, sb_magicnum), 0 },
75 { offsetof(xfs_sb_t, sb_blocksize), 0 },
76 { offsetof(xfs_sb_t, sb_dblocks), 0 },
77 { offsetof(xfs_sb_t, sb_rblocks), 0 },
78 { offsetof(xfs_sb_t, sb_rextents), 0 },
79 { offsetof(xfs_sb_t, sb_uuid), 1 },
80 { offsetof(xfs_sb_t, sb_logstart), 0 },
81 { offsetof(xfs_sb_t, sb_rootino), 0 },
82 { offsetof(xfs_sb_t, sb_rbmino), 0 },
83 { offsetof(xfs_sb_t, sb_rsumino), 0 },
84 { offsetof(xfs_sb_t, sb_rextsize), 0 },
85 { offsetof(xfs_sb_t, sb_agblocks), 0 },
86 { offsetof(xfs_sb_t, sb_agcount), 0 },
87 { offsetof(xfs_sb_t, sb_rbmblocks), 0 },
88 { offsetof(xfs_sb_t, sb_logblocks), 0 },
89 { offsetof(xfs_sb_t, sb_versionnum), 0 },
90 { offsetof(xfs_sb_t, sb_sectsize), 0 },
91 { offsetof(xfs_sb_t, sb_inodesize), 0 },
92 { offsetof(xfs_sb_t, sb_inopblock), 0 },
93 { offsetof(xfs_sb_t, sb_fname[0]), 1 },
94 { offsetof(xfs_sb_t, sb_blocklog), 0 },
95 { offsetof(xfs_sb_t, sb_sectlog), 0 },
96 { offsetof(xfs_sb_t, sb_inodelog), 0 },
97 { offsetof(xfs_sb_t, sb_inopblog), 0 },
98 { offsetof(xfs_sb_t, sb_agblklog), 0 },
99 { offsetof(xfs_sb_t, sb_rextslog), 0 },
100 { offsetof(xfs_sb_t, sb_inprogress), 0 },
101 { offsetof(xfs_sb_t, sb_imax_pct), 0 },
102 { offsetof(xfs_sb_t, sb_icount), 0 },
103 { offsetof(xfs_sb_t, sb_ifree), 0 },
104 { offsetof(xfs_sb_t, sb_fdblocks), 0 },
105 { offsetof(xfs_sb_t, sb_frextents), 0 },
106 { offsetof(xfs_sb_t, sb_uquotino), 0 },
107 { offsetof(xfs_sb_t, sb_gquotino), 0 },
108 { offsetof(xfs_sb_t, sb_qflags), 0 },
109 { offsetof(xfs_sb_t, sb_flags), 0 },
110 { offsetof(xfs_sb_t, sb_shared_vn), 0 },
111 { offsetof(xfs_sb_t, sb_inoalignmt), 0 },
112 { offsetof(xfs_sb_t, sb_unit), 0 },
113 { offsetof(xfs_sb_t, sb_width), 0 },
114 { offsetof(xfs_sb_t, sb_dirblklog), 0 },
115 { offsetof(xfs_sb_t, sb_logsectlog), 0 },
116 { offsetof(xfs_sb_t, sb_logsectsize),0 },
117 { offsetof(xfs_sb_t, sb_logsunit), 0 },
118 { offsetof(xfs_sb_t, sb_features2), 0 },
119 { offsetof(xfs_sb_t, sb_bad_features2), 0 },
120 { sizeof(xfs_sb_t), 0 }
121};
122
123static DEFINE_MUTEX(xfs_uuid_table_mutex);
124static int xfs_uuid_table_size;
125static uuid_t *xfs_uuid_table;
126
127
128
129
130
131STATIC int
132xfs_uuid_mount(
133 struct xfs_mount *mp)
134{
135 uuid_t *uuid = &mp->m_sb.sb_uuid;
136 int hole, i;
137
138 if (mp->m_flags & XFS_MOUNT_NOUUID)
139 return 0;
140
141 if (uuid_is_nil(uuid)) {
142 cmn_err(CE_WARN,
143 "XFS: Filesystem %s has nil UUID - can't mount",
144 mp->m_fsname);
145 return XFS_ERROR(EINVAL);
146 }
147
148 mutex_lock(&xfs_uuid_table_mutex);
149 for (i = 0, hole = -1; i < xfs_uuid_table_size; i++) {
150 if (uuid_is_nil(&xfs_uuid_table[i])) {
151 hole = i;
152 continue;
153 }
154 if (uuid_equal(uuid, &xfs_uuid_table[i]))
155 goto out_duplicate;
156 }
157
158 if (hole < 0) {
159 xfs_uuid_table = kmem_realloc(xfs_uuid_table,
160 (xfs_uuid_table_size + 1) * sizeof(*xfs_uuid_table),
161 xfs_uuid_table_size * sizeof(*xfs_uuid_table),
162 KM_SLEEP);
163 hole = xfs_uuid_table_size++;
164 }
165 xfs_uuid_table[hole] = *uuid;
166 mutex_unlock(&xfs_uuid_table_mutex);
167
168 return 0;
169
170 out_duplicate:
171 mutex_unlock(&xfs_uuid_table_mutex);
172 cmn_err(CE_WARN, "XFS: Filesystem %s has duplicate UUID - can't mount",
173 mp->m_fsname);
174 return XFS_ERROR(EINVAL);
175}
176
177STATIC void
178xfs_uuid_unmount(
179 struct xfs_mount *mp)
180{
181 uuid_t *uuid = &mp->m_sb.sb_uuid;
182 int i;
183
184 if (mp->m_flags & XFS_MOUNT_NOUUID)
185 return;
186
187 mutex_lock(&xfs_uuid_table_mutex);
188 for (i = 0; i < xfs_uuid_table_size; i++) {
189 if (uuid_is_nil(&xfs_uuid_table[i]))
190 continue;
191 if (!uuid_equal(uuid, &xfs_uuid_table[i]))
192 continue;
193 memset(&xfs_uuid_table[i], 0, sizeof(uuid_t));
194 break;
195 }
196 ASSERT(i < xfs_uuid_table_size);
197 mutex_unlock(&xfs_uuid_table_mutex);
198}
199
200
201
202
203
204
205
206STATIC void
207xfs_free_perag(
208 xfs_mount_t *mp)
209{
210 if (mp->m_perag) {
211 int agno;
212
213 for (agno = 0; agno < mp->m_maxagi; agno++)
214 if (mp->m_perag[agno].pagb_list)
215 kmem_free(mp->m_perag[agno].pagb_list);
216 kmem_free(mp->m_perag);
217 }
218}
219
220
221
222
223
224int
225xfs_sb_validate_fsb_count(
226 xfs_sb_t *sbp,
227 __uint64_t nblocks)
228{
229 ASSERT(PAGE_SHIFT >= sbp->sb_blocklog);
230 ASSERT(sbp->sb_blocklog >= BBSHIFT);
231
232#if XFS_BIG_BLKNOS
233 if (nblocks >> (PAGE_CACHE_SHIFT - sbp->sb_blocklog) > ULONG_MAX)
234 return E2BIG;
235#else
236 if (nblocks << (sbp->sb_blocklog - BBSHIFT) > UINT_MAX)
237 return E2BIG;
238#endif
239 return 0;
240}
241
242
243
244
245STATIC int
246xfs_mount_validate_sb(
247 xfs_mount_t *mp,
248 xfs_sb_t *sbp,
249 int flags)
250{
251
252
253
254
255
256
257
258 if (sbp->sb_magicnum != XFS_SB_MAGIC) {
259 xfs_fs_mount_cmn_err(flags, "bad magic number");
260 return XFS_ERROR(EWRONGFS);
261 }
262
263 if (!xfs_sb_good_version(sbp)) {
264 xfs_fs_mount_cmn_err(flags, "bad version");
265 return XFS_ERROR(EWRONGFS);
266 }
267
268 if (unlikely(
269 sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) {
270 xfs_fs_mount_cmn_err(flags,
271 "filesystem is marked as having an external log; "
272 "specify logdev on the\nmount command line.");
273 return XFS_ERROR(EINVAL);
274 }
275
276 if (unlikely(
277 sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) {
278 xfs_fs_mount_cmn_err(flags,
279 "filesystem is marked as having an internal log; "
280 "do not specify logdev on\nthe mount command line.");
281 return XFS_ERROR(EINVAL);
282 }
283
284
285
286
287
288 if (unlikely(
289 sbp->sb_agcount <= 0 ||
290 sbp->sb_sectsize < XFS_MIN_SECTORSIZE ||
291 sbp->sb_sectsize > XFS_MAX_SECTORSIZE ||
292 sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG ||
293 sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG ||
294 sbp->sb_sectsize != (1 << sbp->sb_sectlog) ||
295 sbp->sb_blocksize < XFS_MIN_BLOCKSIZE ||
296 sbp->sb_blocksize > XFS_MAX_BLOCKSIZE ||
297 sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG ||
298 sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG ||
299 sbp->sb_blocksize != (1 << sbp->sb_blocklog) ||
300 sbp->sb_inodesize < XFS_DINODE_MIN_SIZE ||
301 sbp->sb_inodesize > XFS_DINODE_MAX_SIZE ||
302 sbp->sb_inodelog < XFS_DINODE_MIN_LOG ||
303 sbp->sb_inodelog > XFS_DINODE_MAX_LOG ||
304 sbp->sb_inodesize != (1 << sbp->sb_inodelog) ||
305 (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) ||
306 (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) ||
307 (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) ||
308 (sbp->sb_imax_pct > 100 ))) {
309 xfs_fs_mount_cmn_err(flags, "SB sanity check 1 failed");
310 return XFS_ERROR(EFSCORRUPTED);
311 }
312
313
314
315
316 if (unlikely(
317 sbp->sb_dblocks == 0 ||
318 sbp->sb_dblocks >
319 (xfs_drfsbno_t)sbp->sb_agcount * sbp->sb_agblocks ||
320 sbp->sb_dblocks < (xfs_drfsbno_t)(sbp->sb_agcount - 1) *
321 sbp->sb_agblocks + XFS_MIN_AG_BLOCKS)) {
322 xfs_fs_mount_cmn_err(flags, "SB sanity check 2 failed");
323 return XFS_ERROR(EFSCORRUPTED);
324 }
325
326
327
328
329 if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) {
330 xfs_fs_mount_cmn_err(flags,
331 "file system with blocksize %d bytes",
332 sbp->sb_blocksize);
333 xfs_fs_mount_cmn_err(flags,
334 "only pagesize (%ld) or less will currently work.",
335 PAGE_SIZE);
336 return XFS_ERROR(ENOSYS);
337 }
338
339
340
341
342 switch (sbp->sb_inodesize) {
343 case 256:
344 case 512:
345 case 1024:
346 case 2048:
347 break;
348 default:
349 xfs_fs_mount_cmn_err(flags,
350 "inode size of %d bytes not supported",
351 sbp->sb_inodesize);
352 return XFS_ERROR(ENOSYS);
353 }
354
355 if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) ||
356 xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
357 xfs_fs_mount_cmn_err(flags,
358 "file system too large to be mounted on this system.");
359 return XFS_ERROR(E2BIG);
360 }
361
362 if (unlikely(sbp->sb_inprogress)) {
363 xfs_fs_mount_cmn_err(flags, "file system busy");
364 return XFS_ERROR(EFSCORRUPTED);
365 }
366
367
368
369
370 if (unlikely(!xfs_sb_version_hasdirv2(sbp))) {
371 xfs_fs_mount_cmn_err(flags,
372 "file system using version 1 directory format");
373 return XFS_ERROR(ENOSYS);
374 }
375
376 return 0;
377}
378
379STATIC void
380xfs_initialize_perag_icache(
381 xfs_perag_t *pag)
382{
383 if (!pag->pag_ici_init) {
384 rwlock_init(&pag->pag_ici_lock);
385 INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
386 pag->pag_ici_init = 1;
387 }
388}
389
390xfs_agnumber_t
391xfs_initialize_perag(
392 xfs_mount_t *mp,
393 xfs_agnumber_t agcount)
394{
395 xfs_agnumber_t index, max_metadata;
396 xfs_perag_t *pag;
397 xfs_agino_t agino;
398 xfs_ino_t ino;
399 xfs_sb_t *sbp = &mp->m_sb;
400 xfs_ino_t max_inum = XFS_MAXINUMBER_32;
401
402
403 agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0);
404 ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino);
405
406
407
408
409 if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > max_inum) {
410 mp->m_flags |= XFS_MOUNT_32BITINODES;
411 } else {
412 mp->m_flags &= ~XFS_MOUNT_32BITINODES;
413 }
414
415
416 if (mp->m_flags & XFS_MOUNT_32BITINODES) {
417
418
419
420 if (mp->m_maxicount) {
421 __uint64_t icount;
422
423 icount = sbp->sb_dblocks * sbp->sb_imax_pct;
424 do_div(icount, 100);
425 icount += sbp->sb_agblocks - 1;
426 do_div(icount, sbp->sb_agblocks);
427 max_metadata = icount;
428 } else {
429 max_metadata = agcount;
430 }
431 for (index = 0; index < agcount; index++) {
432 ino = XFS_AGINO_TO_INO(mp, index, agino);
433 if (ino > max_inum) {
434 index++;
435 break;
436 }
437
438
439 pag = &mp->m_perag[index];
440 pag->pagi_inodeok = 1;
441 if (index < max_metadata)
442 pag->pagf_metadata = 1;
443 xfs_initialize_perag_icache(pag);
444 }
445 } else {
446
447 for (index = 0; index < agcount; index++) {
448 pag = &mp->m_perag[index];
449 pag->pagi_inodeok = 1;
450 xfs_initialize_perag_icache(pag);
451 }
452 }
453 return index;
454}
455
456void
457xfs_sb_from_disk(
458 xfs_sb_t *to,
459 xfs_dsb_t *from)
460{
461 to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
462 to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
463 to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
464 to->sb_rblocks = be64_to_cpu(from->sb_rblocks);
465 to->sb_rextents = be64_to_cpu(from->sb_rextents);
466 memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid));
467 to->sb_logstart = be64_to_cpu(from->sb_logstart);
468 to->sb_rootino = be64_to_cpu(from->sb_rootino);
469 to->sb_rbmino = be64_to_cpu(from->sb_rbmino);
470 to->sb_rsumino = be64_to_cpu(from->sb_rsumino);
471 to->sb_rextsize = be32_to_cpu(from->sb_rextsize);
472 to->sb_agblocks = be32_to_cpu(from->sb_agblocks);
473 to->sb_agcount = be32_to_cpu(from->sb_agcount);
474 to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks);
475 to->sb_logblocks = be32_to_cpu(from->sb_logblocks);
476 to->sb_versionnum = be16_to_cpu(from->sb_versionnum);
477 to->sb_sectsize = be16_to_cpu(from->sb_sectsize);
478 to->sb_inodesize = be16_to_cpu(from->sb_inodesize);
479 to->sb_inopblock = be16_to_cpu(from->sb_inopblock);
480 memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname));
481 to->sb_blocklog = from->sb_blocklog;
482 to->sb_sectlog = from->sb_sectlog;
483 to->sb_inodelog = from->sb_inodelog;
484 to->sb_inopblog = from->sb_inopblog;
485 to->sb_agblklog = from->sb_agblklog;
486 to->sb_rextslog = from->sb_rextslog;
487 to->sb_inprogress = from->sb_inprogress;
488 to->sb_imax_pct = from->sb_imax_pct;
489 to->sb_icount = be64_to_cpu(from->sb_icount);
490 to->sb_ifree = be64_to_cpu(from->sb_ifree);
491 to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks);
492 to->sb_frextents = be64_to_cpu(from->sb_frextents);
493 to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
494 to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
495 to->sb_qflags = be16_to_cpu(from->sb_qflags);
496 to->sb_flags = from->sb_flags;
497 to->sb_shared_vn = from->sb_shared_vn;
498 to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
499 to->sb_unit = be32_to_cpu(from->sb_unit);
500 to->sb_width = be32_to_cpu(from->sb_width);
501 to->sb_dirblklog = from->sb_dirblklog;
502 to->sb_logsectlog = from->sb_logsectlog;
503 to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize);
504 to->sb_logsunit = be32_to_cpu(from->sb_logsunit);
505 to->sb_features2 = be32_to_cpu(from->sb_features2);
506 to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2);
507}
508
509
510
511
512
513
514void
515xfs_sb_to_disk(
516 xfs_dsb_t *to,
517 xfs_sb_t *from,
518 __int64_t fields)
519{
520 xfs_caddr_t to_ptr = (xfs_caddr_t)to;
521 xfs_caddr_t from_ptr = (xfs_caddr_t)from;
522 xfs_sb_field_t f;
523 int first;
524 int size;
525
526 ASSERT(fields);
527 if (!fields)
528 return;
529
530 while (fields) {
531 f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
532 first = xfs_sb_info[f].offset;
533 size = xfs_sb_info[f + 1].offset - first;
534
535 ASSERT(xfs_sb_info[f].type == 0 || xfs_sb_info[f].type == 1);
536
537 if (size == 1 || xfs_sb_info[f].type == 1) {
538 memcpy(to_ptr + first, from_ptr + first, size);
539 } else {
540 switch (size) {
541 case 2:
542 *(__be16 *)(to_ptr + first) =
543 cpu_to_be16(*(__u16 *)(from_ptr + first));
544 break;
545 case 4:
546 *(__be32 *)(to_ptr + first) =
547 cpu_to_be32(*(__u32 *)(from_ptr + first));
548 break;
549 case 8:
550 *(__be64 *)(to_ptr + first) =
551 cpu_to_be64(*(__u64 *)(from_ptr + first));
552 break;
553 default:
554 ASSERT(0);
555 }
556 }
557
558 fields &= ~(1LL << f);
559 }
560}
561
562
563
564
565
566
567int
568xfs_readsb(xfs_mount_t *mp, int flags)
569{
570 unsigned int sector_size;
571 unsigned int extra_flags;
572 xfs_buf_t *bp;
573 int error;
574
575 ASSERT(mp->m_sb_bp == NULL);
576 ASSERT(mp->m_ddev_targp != NULL);
577
578
579
580
581
582
583 sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
584 extra_flags = XFS_BUF_LOCK | XFS_BUF_MANAGE | XFS_BUF_MAPPED;
585
586 bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR,
587 BTOBB(sector_size), extra_flags);
588 if (!bp || XFS_BUF_ISERROR(bp)) {
589 xfs_fs_mount_cmn_err(flags, "SB read failed");
590 error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM;
591 goto fail;
592 }
593 ASSERT(XFS_BUF_ISBUSY(bp));
594 ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
595
596
597
598
599
600 xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
601
602 error = xfs_mount_validate_sb(mp, &(mp->m_sb), flags);
603 if (error) {
604 xfs_fs_mount_cmn_err(flags, "SB validate failed");
605 goto fail;
606 }
607
608
609
610
611 if (sector_size > mp->m_sb.sb_sectsize) {
612 xfs_fs_mount_cmn_err(flags,
613 "device supports only %u byte sectors (not %u)",
614 sector_size, mp->m_sb.sb_sectsize);
615 error = ENOSYS;
616 goto fail;
617 }
618
619
620
621
622
623 if (sector_size < mp->m_sb.sb_sectsize) {
624 XFS_BUF_UNMANAGE(bp);
625 xfs_buf_relse(bp);
626 sector_size = mp->m_sb.sb_sectsize;
627 bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR,
628 BTOBB(sector_size), extra_flags);
629 if (!bp || XFS_BUF_ISERROR(bp)) {
630 xfs_fs_mount_cmn_err(flags, "SB re-read failed");
631 error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM;
632 goto fail;
633 }
634 ASSERT(XFS_BUF_ISBUSY(bp));
635 ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
636 }
637
638
639 xfs_icsb_reinit_counters(mp);
640
641 mp->m_sb_bp = bp;
642 xfs_buf_relse(bp);
643 ASSERT(XFS_BUF_VALUSEMA(bp) > 0);
644 return 0;
645
646 fail:
647 if (bp) {
648 XFS_BUF_UNMANAGE(bp);
649 xfs_buf_relse(bp);
650 }
651 return error;
652}
653
654
655
656
657
658
659
660
661
662STATIC void
663xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp)
664{
665 mp->m_agfrotor = mp->m_agirotor = 0;
666 spin_lock_init(&mp->m_agirotor_lock);
667 mp->m_maxagi = mp->m_sb.sb_agcount;
668 mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG;
669 mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
670 mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
671 mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1;
672 mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog;
673 mp->m_blockmask = sbp->sb_blocksize - 1;
674 mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
675 mp->m_blockwmask = mp->m_blockwsize - 1;
676
677 mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1);
678 mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);
679 mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2;
680 mp->m_alloc_mnr[1] = mp->m_alloc_mxr[1] / 2;
681
682 mp->m_inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1);
683 mp->m_inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0);
684 mp->m_inobt_mnr[0] = mp->m_inobt_mxr[0] / 2;
685 mp->m_inobt_mnr[1] = mp->m_inobt_mxr[1] / 2;
686
687 mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 1);
688 mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 0);
689 mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2;
690 mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2;
691
692 mp->m_bsize = XFS_FSB_TO_BB(mp, 1);
693 mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK,
694 sbp->sb_inopblock);
695 mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog;
696}
697
698
699
700
701
702
703
704
705
706STATIC int
707xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount)
708{
709 xfs_agnumber_t index;
710 xfs_perag_t *pag;
711 xfs_sb_t *sbp = &mp->m_sb;
712 uint64_t ifree = 0;
713 uint64_t ialloc = 0;
714 uint64_t bfree = 0;
715 uint64_t bfreelst = 0;
716 uint64_t btree = 0;
717 int error;
718
719 for (index = 0; index < agcount; index++) {
720
721
722
723
724
725 error = xfs_alloc_pagf_init(mp, NULL, index, 0);
726 if (error)
727 return error;
728
729 error = xfs_ialloc_pagi_init(mp, NULL, index);
730 if (error)
731 return error;
732 pag = &mp->m_perag[index];
733 ifree += pag->pagi_freecount;
734 ialloc += pag->pagi_count;
735 bfree += pag->pagf_freeblks;
736 bfreelst += pag->pagf_flcount;
737 btree += pag->pagf_btreeblks;
738 }
739
740
741
742 spin_lock(&mp->m_sb_lock);
743 sbp->sb_ifree = ifree;
744 sbp->sb_icount = ialloc;
745 sbp->sb_fdblocks = bfree + bfreelst + btree;
746 spin_unlock(&mp->m_sb_lock);
747
748
749 xfs_icsb_reinit_counters(mp);
750
751 return 0;
752}
753
754
755
756
757STATIC int
758xfs_update_alignment(xfs_mount_t *mp)
759{
760 xfs_sb_t *sbp = &(mp->m_sb);
761
762 if (mp->m_dalign) {
763
764
765
766
767 if ((BBTOB(mp->m_dalign) & mp->m_blockmask) ||
768 (BBTOB(mp->m_swidth) & mp->m_blockmask)) {
769 if (mp->m_flags & XFS_MOUNT_RETERR) {
770 cmn_err(CE_WARN,
771 "XFS: alignment check 1 failed");
772 return XFS_ERROR(EINVAL);
773 }
774 mp->m_dalign = mp->m_swidth = 0;
775 } else {
776
777
778
779 mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign);
780 if (mp->m_dalign && (sbp->sb_agblocks % mp->m_dalign)) {
781 if (mp->m_flags & XFS_MOUNT_RETERR) {
782 return XFS_ERROR(EINVAL);
783 }
784 xfs_fs_cmn_err(CE_WARN, mp,
785"stripe alignment turned off: sunit(%d)/swidth(%d) incompatible with agsize(%d)",
786 mp->m_dalign, mp->m_swidth,
787 sbp->sb_agblocks);
788
789 mp->m_dalign = 0;
790 mp->m_swidth = 0;
791 } else if (mp->m_dalign) {
792 mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth);
793 } else {
794 if (mp->m_flags & XFS_MOUNT_RETERR) {
795 xfs_fs_cmn_err(CE_WARN, mp,
796"stripe alignment turned off: sunit(%d) less than bsize(%d)",
797 mp->m_dalign,
798 mp->m_blockmask +1);
799 return XFS_ERROR(EINVAL);
800 }
801 mp->m_swidth = 0;
802 }
803 }
804
805
806
807
808
809 if (xfs_sb_version_hasdalign(sbp)) {
810 if (sbp->sb_unit != mp->m_dalign) {
811 sbp->sb_unit = mp->m_dalign;
812 mp->m_update_flags |= XFS_SB_UNIT;
813 }
814 if (sbp->sb_width != mp->m_swidth) {
815 sbp->sb_width = mp->m_swidth;
816 mp->m_update_flags |= XFS_SB_WIDTH;
817 }
818 }
819 } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN &&
820 xfs_sb_version_hasdalign(&mp->m_sb)) {
821 mp->m_dalign = sbp->sb_unit;
822 mp->m_swidth = sbp->sb_width;
823 }
824
825 return 0;
826}
827
828
829
830
831STATIC void
832xfs_set_maxicount(xfs_mount_t *mp)
833{
834 xfs_sb_t *sbp = &(mp->m_sb);
835 __uint64_t icount;
836
837 if (sbp->sb_imax_pct) {
838
839
840
841
842 icount = sbp->sb_dblocks * sbp->sb_imax_pct;
843 do_div(icount, 100);
844 do_div(icount, mp->m_ialloc_blks);
845 mp->m_maxicount = (icount * mp->m_ialloc_blks) <<
846 sbp->sb_inopblog;
847 } else {
848 mp->m_maxicount = 0;
849 }
850}
851
852
853
854
855
856
857
858STATIC void
859xfs_set_rw_sizes(xfs_mount_t *mp)
860{
861 xfs_sb_t *sbp = &(mp->m_sb);
862 int readio_log, writeio_log;
863
864 if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) {
865 if (mp->m_flags & XFS_MOUNT_WSYNC) {
866 readio_log = XFS_WSYNC_READIO_LOG;
867 writeio_log = XFS_WSYNC_WRITEIO_LOG;
868 } else {
869 readio_log = XFS_READIO_LOG_LARGE;
870 writeio_log = XFS_WRITEIO_LOG_LARGE;
871 }
872 } else {
873 readio_log = mp->m_readio_log;
874 writeio_log = mp->m_writeio_log;
875 }
876
877 if (sbp->sb_blocklog > readio_log) {
878 mp->m_readio_log = sbp->sb_blocklog;
879 } else {
880 mp->m_readio_log = readio_log;
881 }
882 mp->m_readio_blocks = 1 << (mp->m_readio_log - sbp->sb_blocklog);
883 if (sbp->sb_blocklog > writeio_log) {
884 mp->m_writeio_log = sbp->sb_blocklog;
885 } else {
886 mp->m_writeio_log = writeio_log;
887 }
888 mp->m_writeio_blocks = 1 << (mp->m_writeio_log - sbp->sb_blocklog);
889}
890
891
892
893
894STATIC void
895xfs_set_inoalignment(xfs_mount_t *mp)
896{
897 if (xfs_sb_version_hasalign(&mp->m_sb) &&
898 mp->m_sb.sb_inoalignmt >=
899 XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size))
900 mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1;
901 else
902 mp->m_inoalign_mask = 0;
903
904
905
906
907 if (mp->m_dalign && mp->m_inoalign_mask &&
908 !(mp->m_dalign & mp->m_inoalign_mask))
909 mp->m_sinoalign = mp->m_dalign;
910 else
911 mp->m_sinoalign = 0;
912}
913
914
915
916
917STATIC int
918xfs_check_sizes(xfs_mount_t *mp)
919{
920 xfs_buf_t *bp;
921 xfs_daddr_t d;
922 int error;
923
924 d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
925 if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) {
926 cmn_err(CE_WARN, "XFS: size check 1 failed");
927 return XFS_ERROR(E2BIG);
928 }
929 error = xfs_read_buf(mp, mp->m_ddev_targp,
930 d - XFS_FSS_TO_BB(mp, 1),
931 XFS_FSS_TO_BB(mp, 1), 0, &bp);
932 if (!error) {
933 xfs_buf_relse(bp);
934 } else {
935 cmn_err(CE_WARN, "XFS: size check 2 failed");
936 if (error == ENOSPC)
937 error = XFS_ERROR(E2BIG);
938 return error;
939 }
940
941 if (mp->m_logdev_targp != mp->m_ddev_targp) {
942 d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
943 if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) {
944 cmn_err(CE_WARN, "XFS: size check 3 failed");
945 return XFS_ERROR(E2BIG);
946 }
947 error = xfs_read_buf(mp, mp->m_logdev_targp,
948 d - XFS_FSB_TO_BB(mp, 1),
949 XFS_FSB_TO_BB(mp, 1), 0, &bp);
950 if (!error) {
951 xfs_buf_relse(bp);
952 } else {
953 cmn_err(CE_WARN, "XFS: size check 3 failed");
954 if (error == ENOSPC)
955 error = XFS_ERROR(E2BIG);
956 return error;
957 }
958 }
959 return 0;
960}
961
962
963
964
965int
966xfs_mount_reset_sbqflags(
967 struct xfs_mount *mp)
968{
969 int error;
970 struct xfs_trans *tp;
971
972 mp->m_qflags = 0;
973
974
975
976
977
978 if (mp->m_sb.sb_qflags == 0)
979 return 0;
980 spin_lock(&mp->m_sb_lock);
981 mp->m_sb.sb_qflags = 0;
982 spin_unlock(&mp->m_sb_lock);
983
984
985
986
987
988 if (mp->m_flags & XFS_MOUNT_RDONLY)
989 return 0;
990
991#ifdef QUOTADEBUG
992 xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes");
993#endif
994
995 tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
996 error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
997 XFS_DEFAULT_LOG_COUNT);
998 if (error) {
999 xfs_trans_cancel(tp, 0);
1000 xfs_fs_cmn_err(CE_ALERT, mp,
1001 "xfs_mount_reset_sbqflags: Superblock update failed!");
1002 return error;
1003 }
1004
1005 xfs_mod_sb(tp, XFS_SB_QFLAGS);
1006 return xfs_trans_commit(tp, 0);
1007}
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019int
1020xfs_mountfs(
1021 xfs_mount_t *mp)
1022{
1023 xfs_sb_t *sbp = &(mp->m_sb);
1024 xfs_inode_t *rip;
1025 __uint64_t resblks;
1026 uint quotamount = 0;
1027 uint quotaflags = 0;
1028 int error = 0;
1029
1030 xfs_mount_common(mp, sbp);
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048 if (xfs_sb_has_mismatched_features2(sbp)) {
1049 cmn_err(CE_WARN,
1050 "XFS: correcting sb_features alignment problem");
1051 sbp->sb_features2 |= sbp->sb_bad_features2;
1052 sbp->sb_bad_features2 = sbp->sb_features2;
1053 mp->m_update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2;
1054
1055
1056
1057
1058
1059 if (xfs_sb_version_hasattr2(&mp->m_sb) &&
1060 !(mp->m_flags & XFS_MOUNT_NOATTR2))
1061 mp->m_flags |= XFS_MOUNT_ATTR2;
1062 }
1063
1064 if (xfs_sb_version_hasattr2(&mp->m_sb) &&
1065 (mp->m_flags & XFS_MOUNT_NOATTR2)) {
1066 xfs_sb_version_removeattr2(&mp->m_sb);
1067 mp->m_update_flags |= XFS_SB_FEATURES2;
1068
1069
1070 if (!sbp->sb_features2)
1071 mp->m_update_flags |= XFS_SB_VERSIONNUM;
1072 }
1073
1074
1075
1076
1077
1078
1079
1080 error = xfs_update_alignment(mp);
1081 if (error)
1082 goto out;
1083
1084 xfs_alloc_compute_maxlevels(mp);
1085 xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK);
1086 xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK);
1087 xfs_ialloc_compute_maxlevels(mp);
1088
1089 xfs_set_maxicount(mp);
1090
1091 mp->m_maxioffset = xfs_max_file_offset(sbp->sb_blocklog);
1092
1093 error = xfs_uuid_mount(mp);
1094 if (error)
1095 goto out;
1096
1097
1098
1099
1100 xfs_set_rw_sizes(mp);
1101
1102
1103
1104
1105
1106
1107 mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE;
1108
1109
1110
1111
1112 xfs_set_inoalignment(mp);
1113
1114
1115
1116
1117 error = xfs_check_sizes(mp);
1118 if (error)
1119 goto out_remove_uuid;
1120
1121
1122
1123
1124 error = xfs_rtmount_init(mp);
1125 if (error) {
1126 cmn_err(CE_WARN, "XFS: RT mount failed");
1127 goto out_remove_uuid;
1128 }
1129
1130
1131
1132
1133
1134 uuid_getnodeuniq(&sbp->sb_uuid, mp->m_fixedfsid);
1135
1136 mp->m_dmevmask = 0;
1137
1138 xfs_dir_mount(mp);
1139
1140
1141
1142
1143 mp->m_attr_magicpct = (mp->m_sb.sb_blocksize * 37) / 100;
1144
1145
1146
1147
1148 xfs_trans_init(mp);
1149
1150
1151
1152
1153 init_rwsem(&mp->m_peraglock);
1154 mp->m_perag = kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t),
1155 KM_MAYFAIL);
1156 if (!mp->m_perag)
1157 goto out_remove_uuid;
1158
1159 mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount);
1160
1161 if (!sbp->sb_logblocks) {
1162 cmn_err(CE_WARN, "XFS: no log defined");
1163 XFS_ERROR_REPORT("xfs_mountfs", XFS_ERRLEVEL_LOW, mp);
1164 error = XFS_ERROR(EFSCORRUPTED);
1165 goto out_free_perag;
1166 }
1167
1168
1169
1170
1171 error = xfs_log_mount(mp, mp->m_logdev_targp,
1172 XFS_FSB_TO_DADDR(mp, sbp->sb_logstart),
1173 XFS_FSB_TO_BB(mp, sbp->sb_logblocks));
1174 if (error) {
1175 cmn_err(CE_WARN, "XFS: log mount failed");
1176 goto out_free_perag;
1177 }
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198 if (xfs_sb_version_haslazysbcount(&mp->m_sb) &&
1199 !XFS_LAST_UNMOUNT_WAS_CLEAN(mp) &&
1200 !mp->m_sb.sb_inprogress) {
1201 error = xfs_initialize_perag_data(mp, sbp->sb_agcount);
1202 if (error)
1203 goto out_free_perag;
1204 }
1205
1206
1207
1208
1209
1210 error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip, 0);
1211 if (error) {
1212 cmn_err(CE_WARN, "XFS: failed to read root inode");
1213 goto out_log_dealloc;
1214 }
1215
1216 ASSERT(rip != NULL);
1217
1218 if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) {
1219 cmn_err(CE_WARN, "XFS: corrupted root inode");
1220 cmn_err(CE_WARN, "Device %s - root %llu is not a directory",
1221 XFS_BUFTARG_NAME(mp->m_ddev_targp),
1222 (unsigned long long)rip->i_ino);
1223 xfs_iunlock(rip, XFS_ILOCK_EXCL);
1224 XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW,
1225 mp);
1226 error = XFS_ERROR(EFSCORRUPTED);
1227 goto out_rele_rip;
1228 }
1229 mp->m_rootip = rip;
1230
1231 xfs_iunlock(rip, XFS_ILOCK_EXCL);
1232
1233
1234
1235
1236 error = xfs_rtmount_inodes(mp);
1237 if (error) {
1238
1239
1240
1241 cmn_err(CE_WARN, "XFS: failed to read RT inodes");
1242 goto out_rele_rip;
1243 }
1244
1245
1246
1247
1248
1249
1250 if (mp->m_update_flags && !(mp->m_flags & XFS_MOUNT_RDONLY)) {
1251 error = xfs_mount_log_sb(mp, mp->m_update_flags);
1252 if (error) {
1253 cmn_err(CE_WARN, "XFS: failed to write sb changes");
1254 goto out_rtunmount;
1255 }
1256 }
1257
1258
1259
1260
1261 if (XFS_IS_QUOTA_RUNNING(mp)) {
1262 error = xfs_qm_newmount(mp, "amount, "aflags);
1263 if (error)
1264 goto out_rtunmount;
1265 } else {
1266 ASSERT(!XFS_IS_QUOTA_ON(mp));
1267
1268
1269
1270
1271
1272
1273 if (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT) {
1274 cmn_err(CE_NOTE,
1275 "XFS: resetting qflags for filesystem %s",
1276 mp->m_fsname);
1277
1278 error = xfs_mount_reset_sbqflags(mp);
1279 if (error)
1280 return error;
1281 }
1282 }
1283
1284
1285
1286
1287
1288
1289 error = xfs_log_mount_finish(mp);
1290 if (error) {
1291 cmn_err(CE_WARN, "XFS: log mount finish failed");
1292 goto out_rtunmount;
1293 }
1294
1295
1296
1297
1298 if (quotamount) {
1299 ASSERT(mp->m_qflags == 0);
1300 mp->m_qflags = quotaflags;
1301
1302 xfs_qm_mount_quotas(mp);
1303 }
1304
1305#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
1306 if (XFS_IS_QUOTA_ON(mp))
1307 xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on");
1308 else
1309 xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on");
1310#endif
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324 resblks = mp->m_sb.sb_dblocks;
1325 do_div(resblks, 20);
1326 resblks = min_t(__uint64_t, resblks, 1024);
1327 error = xfs_reserve_blocks(mp, &resblks, NULL);
1328 if (error)
1329 cmn_err(CE_WARN, "XFS: Unable to allocate reserve blocks. "
1330 "Continuing without a reserve pool.");
1331
1332 return 0;
1333
1334 out_rtunmount:
1335 xfs_rtunmount_inodes(mp);
1336 out_rele_rip:
1337 IRELE(rip);
1338 out_log_dealloc:
1339 xfs_log_unmount(mp);
1340 out_free_perag:
1341 xfs_free_perag(mp);
1342 out_remove_uuid:
1343 xfs_uuid_unmount(mp);
1344 out:
1345 return error;
1346}
1347
1348
1349
1350
1351
1352void
1353xfs_unmountfs(
1354 struct xfs_mount *mp)
1355{
1356 __uint64_t resblks;
1357 int error;
1358
1359 xfs_qm_unmount_quotas(mp);
1360 xfs_rtunmount_inodes(mp);
1361 IRELE(mp->m_rootip);
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373 xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
1374 xfs_reclaim_inodes(mp, XFS_IFLUSH_ASYNC);
1375
1376 xfs_qm_unmount(mp);
1377
1378
1379
1380
1381
1382
1383 xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
1384
1385 xfs_binval(mp->m_ddev_targp);
1386 if (mp->m_rtdev_targp) {
1387 xfs_binval(mp->m_rtdev_targp);
1388 }
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404 resblks = 0;
1405 error = xfs_reserve_blocks(mp, &resblks, NULL);
1406 if (error)
1407 cmn_err(CE_WARN, "XFS: Unable to free reserved block pool. "
1408 "Freespace may not be correct on next mount.");
1409
1410 error = xfs_log_sbcount(mp, 1);
1411 if (error)
1412 cmn_err(CE_WARN, "XFS: Unable to update superblock counters. "
1413 "Freespace may not be correct on next mount.");
1414 xfs_unmountfs_writesb(mp);
1415 xfs_unmountfs_wait(mp);
1416 xfs_log_unmount_write(mp);
1417 xfs_log_unmount(mp);
1418 xfs_uuid_unmount(mp);
1419
1420#if defined(DEBUG)
1421 xfs_errortag_clearall(mp, 0);
1422#endif
1423 xfs_free_perag(mp);
1424}
1425
1426STATIC void
1427xfs_unmountfs_wait(xfs_mount_t *mp)
1428{
1429 if (mp->m_logdev_targp != mp->m_ddev_targp)
1430 xfs_wait_buftarg(mp->m_logdev_targp);
1431 if (mp->m_rtdev_targp)
1432 xfs_wait_buftarg(mp->m_rtdev_targp);
1433 xfs_wait_buftarg(mp->m_ddev_targp);
1434}
1435
1436int
1437xfs_fs_writable(xfs_mount_t *mp)
1438{
1439 return !(xfs_test_for_freeze(mp) || XFS_FORCED_SHUTDOWN(mp) ||
1440 (mp->m_flags & XFS_MOUNT_RDONLY));
1441}
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454int
1455xfs_log_sbcount(
1456 xfs_mount_t *mp,
1457 uint sync)
1458{
1459 xfs_trans_t *tp;
1460 int error;
1461
1462 if (!xfs_fs_writable(mp))
1463 return 0;
1464
1465 xfs_icsb_sync_counters(mp, 0);
1466
1467
1468
1469
1470
1471 if (!xfs_sb_version_haslazysbcount(&mp->m_sb))
1472 return 0;
1473
1474 tp = _xfs_trans_alloc(mp, XFS_TRANS_SB_COUNT);
1475 error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
1476 XFS_DEFAULT_LOG_COUNT);
1477 if (error) {
1478 xfs_trans_cancel(tp, 0);
1479 return error;
1480 }
1481
1482 xfs_mod_sb(tp, XFS_SB_IFREE | XFS_SB_ICOUNT | XFS_SB_FDBLOCKS);
1483 if (sync)
1484 xfs_trans_set_sync(tp);
1485 error = xfs_trans_commit(tp, 0);
1486 return error;
1487}
1488
1489int
1490xfs_unmountfs_writesb(xfs_mount_t *mp)
1491{
1492 xfs_buf_t *sbp;
1493 int error = 0;
1494
1495
1496
1497
1498
1499 if (!((mp->m_flags & XFS_MOUNT_RDONLY) ||
1500 XFS_FORCED_SHUTDOWN(mp))) {
1501
1502 sbp = xfs_getsb(mp, 0);
1503
1504 XFS_BUF_UNDONE(sbp);
1505 XFS_BUF_UNREAD(sbp);
1506 XFS_BUF_UNDELAYWRITE(sbp);
1507 XFS_BUF_WRITE(sbp);
1508 XFS_BUF_UNASYNC(sbp);
1509 ASSERT(XFS_BUF_TARGET(sbp) == mp->m_ddev_targp);
1510 xfsbdstrat(mp, sbp);
1511 error = xfs_iowait(sbp);
1512 if (error)
1513 xfs_ioerror_alert("xfs_unmountfs_writesb",
1514 mp, sbp, XFS_BUF_ADDR(sbp));
1515 xfs_buf_relse(sbp);
1516 }
1517 return error;
1518}
1519
1520
1521
1522
1523
1524
1525
1526
1527void
1528xfs_mod_sb(xfs_trans_t *tp, __int64_t fields)
1529{
1530 xfs_buf_t *bp;
1531 int first;
1532 int last;
1533 xfs_mount_t *mp;
1534 xfs_sb_field_t f;
1535
1536 ASSERT(fields);
1537 if (!fields)
1538 return;
1539 mp = tp->t_mountp;
1540 bp = xfs_trans_getsb(tp, mp, 0);
1541 first = sizeof(xfs_sb_t);
1542 last = 0;
1543
1544
1545
1546 xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, fields);
1547
1548
1549
1550 f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
1551 ASSERT((1LL << f) & XFS_SB_MOD_BITS);
1552 first = xfs_sb_info[f].offset;
1553
1554 f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields);
1555 ASSERT((1LL << f) & XFS_SB_MOD_BITS);
1556 last = xfs_sb_info[f + 1].offset - 1;
1557
1558 xfs_trans_log_buf(tp, bp, first, last);
1559}
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571STATIC int
1572xfs_mod_incore_sb_unlocked(
1573 xfs_mount_t *mp,
1574 xfs_sb_field_t field,
1575 int64_t delta,
1576 int rsvd)
1577{
1578 int scounter;
1579 long long lcounter;
1580 long long res_used, rem;
1581
1582
1583
1584
1585
1586
1587
1588 switch (field) {
1589 case XFS_SBS_ICOUNT:
1590 lcounter = (long long)mp->m_sb.sb_icount;
1591 lcounter += delta;
1592 if (lcounter < 0) {
1593 ASSERT(0);
1594 return XFS_ERROR(EINVAL);
1595 }
1596 mp->m_sb.sb_icount = lcounter;
1597 return 0;
1598 case XFS_SBS_IFREE:
1599 lcounter = (long long)mp->m_sb.sb_ifree;
1600 lcounter += delta;
1601 if (lcounter < 0) {
1602 ASSERT(0);
1603 return XFS_ERROR(EINVAL);
1604 }
1605 mp->m_sb.sb_ifree = lcounter;
1606 return 0;
1607 case XFS_SBS_FDBLOCKS:
1608 lcounter = (long long)
1609 mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
1610 res_used = (long long)(mp->m_resblks - mp->m_resblks_avail);
1611
1612 if (delta > 0) {
1613 if (res_used > delta) {
1614 mp->m_resblks_avail += delta;
1615 } else {
1616 rem = delta - res_used;
1617 mp->m_resblks_avail = mp->m_resblks;
1618 lcounter += rem;
1619 }
1620 } else {
1621
1622 lcounter += delta;
1623
1624
1625
1626
1627
1628
1629 if (lcounter < 0) {
1630 if (rsvd) {
1631 lcounter = (long long)mp->m_resblks_avail + delta;
1632 if (lcounter < 0) {
1633 return XFS_ERROR(ENOSPC);
1634 }
1635 mp->m_resblks_avail = lcounter;
1636 return 0;
1637 } else {
1638 return XFS_ERROR(ENOSPC);
1639 }
1640 }
1641 }
1642
1643 mp->m_sb.sb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp);
1644 return 0;
1645 case XFS_SBS_FREXTENTS:
1646 lcounter = (long long)mp->m_sb.sb_frextents;
1647 lcounter += delta;
1648 if (lcounter < 0) {
1649 return XFS_ERROR(ENOSPC);
1650 }
1651 mp->m_sb.sb_frextents = lcounter;
1652 return 0;
1653 case XFS_SBS_DBLOCKS:
1654 lcounter = (long long)mp->m_sb.sb_dblocks;
1655 lcounter += delta;
1656 if (lcounter < 0) {
1657 ASSERT(0);
1658 return XFS_ERROR(EINVAL);
1659 }
1660 mp->m_sb.sb_dblocks = lcounter;
1661 return 0;
1662 case XFS_SBS_AGCOUNT:
1663 scounter = mp->m_sb.sb_agcount;
1664 scounter += delta;
1665 if (scounter < 0) {
1666 ASSERT(0);
1667 return XFS_ERROR(EINVAL);
1668 }
1669 mp->m_sb.sb_agcount = scounter;
1670 return 0;
1671 case XFS_SBS_IMAX_PCT:
1672 scounter = mp->m_sb.sb_imax_pct;
1673 scounter += delta;
1674 if (scounter < 0) {
1675 ASSERT(0);
1676 return XFS_ERROR(EINVAL);
1677 }
1678 mp->m_sb.sb_imax_pct = scounter;
1679 return 0;
1680 case XFS_SBS_REXTSIZE:
1681 scounter = mp->m_sb.sb_rextsize;
1682 scounter += delta;
1683 if (scounter < 0) {
1684 ASSERT(0);
1685 return XFS_ERROR(EINVAL);
1686 }
1687 mp->m_sb.sb_rextsize = scounter;
1688 return 0;
1689 case XFS_SBS_RBMBLOCKS:
1690 scounter = mp->m_sb.sb_rbmblocks;
1691 scounter += delta;
1692 if (scounter < 0) {
1693 ASSERT(0);
1694 return XFS_ERROR(EINVAL);
1695 }
1696 mp->m_sb.sb_rbmblocks = scounter;
1697 return 0;
1698 case XFS_SBS_RBLOCKS:
1699 lcounter = (long long)mp->m_sb.sb_rblocks;
1700 lcounter += delta;
1701 if (lcounter < 0) {
1702 ASSERT(0);
1703 return XFS_ERROR(EINVAL);
1704 }
1705 mp->m_sb.sb_rblocks = lcounter;
1706 return 0;
1707 case XFS_SBS_REXTENTS:
1708 lcounter = (long long)mp->m_sb.sb_rextents;
1709 lcounter += delta;
1710 if (lcounter < 0) {
1711 ASSERT(0);
1712 return XFS_ERROR(EINVAL);
1713 }
1714 mp->m_sb.sb_rextents = lcounter;
1715 return 0;
1716 case XFS_SBS_REXTSLOG:
1717 scounter = mp->m_sb.sb_rextslog;
1718 scounter += delta;
1719 if (scounter < 0) {
1720 ASSERT(0);
1721 return XFS_ERROR(EINVAL);
1722 }
1723 mp->m_sb.sb_rextslog = scounter;
1724 return 0;
1725 default:
1726 ASSERT(0);
1727 return XFS_ERROR(EINVAL);
1728 }
1729}
1730
1731
1732
1733
1734
1735
1736
1737int
1738xfs_mod_incore_sb(
1739 xfs_mount_t *mp,
1740 xfs_sb_field_t field,
1741 int64_t delta,
1742 int rsvd)
1743{
1744 int status;
1745
1746
1747 switch (field) {
1748#ifdef HAVE_PERCPU_SB
1749 case XFS_SBS_ICOUNT:
1750 case XFS_SBS_IFREE:
1751 case XFS_SBS_FDBLOCKS:
1752 if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
1753 status = xfs_icsb_modify_counters(mp, field,
1754 delta, rsvd);
1755 break;
1756 }
1757
1758#endif
1759 default:
1760 spin_lock(&mp->m_sb_lock);
1761 status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);
1762 spin_unlock(&mp->m_sb_lock);
1763 break;
1764 }
1765
1766 return status;
1767}
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780int
1781xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd)
1782{
1783 int status=0;
1784 xfs_mod_sb_t *msbp;
1785
1786
1787
1788
1789
1790
1791
1792
1793 spin_lock(&mp->m_sb_lock);
1794 msbp = &msb[0];
1795 for (msbp = &msbp[0]; msbp < (msb + nmsb); msbp++) {
1796
1797
1798
1799
1800
1801 switch (msbp->msb_field) {
1802#ifdef HAVE_PERCPU_SB
1803 case XFS_SBS_ICOUNT:
1804 case XFS_SBS_IFREE:
1805 case XFS_SBS_FDBLOCKS:
1806 if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
1807 spin_unlock(&mp->m_sb_lock);
1808 status = xfs_icsb_modify_counters(mp,
1809 msbp->msb_field,
1810 msbp->msb_delta, rsvd);
1811 spin_lock(&mp->m_sb_lock);
1812 break;
1813 }
1814
1815#endif
1816 default:
1817 status = xfs_mod_incore_sb_unlocked(mp,
1818 msbp->msb_field,
1819 msbp->msb_delta, rsvd);
1820 break;
1821 }
1822
1823 if (status != 0) {
1824 break;
1825 }
1826 }
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836 if (status != 0) {
1837 msbp--;
1838 while (msbp >= msb) {
1839 switch (msbp->msb_field) {
1840#ifdef HAVE_PERCPU_SB
1841 case XFS_SBS_ICOUNT:
1842 case XFS_SBS_IFREE:
1843 case XFS_SBS_FDBLOCKS:
1844 if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) {
1845 spin_unlock(&mp->m_sb_lock);
1846 status = xfs_icsb_modify_counters(mp,
1847 msbp->msb_field,
1848 -(msbp->msb_delta),
1849 rsvd);
1850 spin_lock(&mp->m_sb_lock);
1851 break;
1852 }
1853
1854#endif
1855 default:
1856 status = xfs_mod_incore_sb_unlocked(mp,
1857 msbp->msb_field,
1858 -(msbp->msb_delta),
1859 rsvd);
1860 break;
1861 }
1862 ASSERT(status == 0);
1863 msbp--;
1864 }
1865 }
1866 spin_unlock(&mp->m_sb_lock);
1867 return status;
1868}
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879xfs_buf_t *
1880xfs_getsb(
1881 xfs_mount_t *mp,
1882 int flags)
1883{
1884 xfs_buf_t *bp;
1885
1886 ASSERT(mp->m_sb_bp != NULL);
1887 bp = mp->m_sb_bp;
1888 if (flags & XFS_BUF_TRYLOCK) {
1889 if (!XFS_BUF_CPSEMA(bp)) {
1890 return NULL;
1891 }
1892 } else {
1893 XFS_BUF_PSEMA(bp, PRIBIO);
1894 }
1895 XFS_BUF_HOLD(bp);
1896 ASSERT(XFS_BUF_ISDONE(bp));
1897 return bp;
1898}
1899
1900
1901
1902
1903void
1904xfs_freesb(
1905 xfs_mount_t *mp)
1906{
1907 xfs_buf_t *bp;
1908
1909
1910
1911
1912
1913 bp = xfs_getsb(mp, 0);
1914 XFS_BUF_UNMANAGE(bp);
1915 xfs_buf_relse(bp);
1916 mp->m_sb_bp = NULL;
1917}
1918
1919
1920
1921
1922
1923
1924int
1925xfs_mount_log_sb(
1926 xfs_mount_t *mp,
1927 __int64_t fields)
1928{
1929 xfs_trans_t *tp;
1930 int error;
1931
1932 ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID |
1933 XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2 |
1934 XFS_SB_VERSIONNUM));
1935
1936 tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT);
1937 error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
1938 XFS_DEFAULT_LOG_COUNT);
1939 if (error) {
1940 xfs_trans_cancel(tp, 0);
1941 return error;
1942 }
1943 xfs_mod_sb(tp, fields);
1944 error = xfs_trans_commit(tp, 0);
1945 return error;
1946}
1947
1948
1949#ifdef HAVE_PERCPU_SB
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002#ifdef CONFIG_HOTPLUG_CPU
2003
2004
2005
2006
2007
2008
2009
2010
2011STATIC int
2012xfs_icsb_cpu_notify(
2013 struct notifier_block *nfb,
2014 unsigned long action,
2015 void *hcpu)
2016{
2017 xfs_icsb_cnts_t *cntp;
2018 xfs_mount_t *mp;
2019
2020 mp = (xfs_mount_t *)container_of(nfb, xfs_mount_t, m_icsb_notifier);
2021 cntp = (xfs_icsb_cnts_t *)
2022 per_cpu_ptr(mp->m_sb_cnts, (unsigned long)hcpu);
2023 switch (action) {
2024 case CPU_UP_PREPARE:
2025 case CPU_UP_PREPARE_FROZEN:
2026
2027
2028 memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
2029 break;
2030 case CPU_ONLINE:
2031 case CPU_ONLINE_FROZEN:
2032 xfs_icsb_lock(mp);
2033 xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);
2034 xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
2035 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
2036 xfs_icsb_unlock(mp);
2037 break;
2038 case CPU_DEAD:
2039 case CPU_DEAD_FROZEN:
2040
2041
2042
2043 xfs_icsb_lock(mp);
2044 spin_lock(&mp->m_sb_lock);
2045 xfs_icsb_disable_counter(mp, XFS_SBS_ICOUNT);
2046 xfs_icsb_disable_counter(mp, XFS_SBS_IFREE);
2047 xfs_icsb_disable_counter(mp, XFS_SBS_FDBLOCKS);
2048
2049 mp->m_sb.sb_icount += cntp->icsb_icount;
2050 mp->m_sb.sb_ifree += cntp->icsb_ifree;
2051 mp->m_sb.sb_fdblocks += cntp->icsb_fdblocks;
2052
2053 memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
2054
2055 xfs_icsb_balance_counter_locked(mp, XFS_SBS_ICOUNT, 0);
2056 xfs_icsb_balance_counter_locked(mp, XFS_SBS_IFREE, 0);
2057 xfs_icsb_balance_counter_locked(mp, XFS_SBS_FDBLOCKS, 0);
2058 spin_unlock(&mp->m_sb_lock);
2059 xfs_icsb_unlock(mp);
2060 break;
2061 }
2062
2063 return NOTIFY_OK;
2064}
2065#endif
2066
2067int
2068xfs_icsb_init_counters(
2069 xfs_mount_t *mp)
2070{
2071 xfs_icsb_cnts_t *cntp;
2072 int i;
2073
2074 mp->m_sb_cnts = alloc_percpu(xfs_icsb_cnts_t);
2075 if (mp->m_sb_cnts == NULL)
2076 return -ENOMEM;
2077
2078#ifdef CONFIG_HOTPLUG_CPU
2079 mp->m_icsb_notifier.notifier_call = xfs_icsb_cpu_notify;
2080 mp->m_icsb_notifier.priority = 0;
2081 register_hotcpu_notifier(&mp->m_icsb_notifier);
2082#endif
2083
2084 for_each_online_cpu(i) {
2085 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
2086 memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
2087 }
2088
2089 mutex_init(&mp->m_icsb_mutex);
2090
2091
2092
2093
2094
2095 mp->m_icsb_counters = -1;
2096 return 0;
2097}
2098
2099void
2100xfs_icsb_reinit_counters(
2101 xfs_mount_t *mp)
2102{
2103 xfs_icsb_lock(mp);
2104
2105
2106
2107
2108 mp->m_icsb_counters = -1;
2109 xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);
2110 xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
2111 xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
2112 xfs_icsb_unlock(mp);
2113}
2114
2115void
2116xfs_icsb_destroy_counters(
2117 xfs_mount_t *mp)
2118{
2119 if (mp->m_sb_cnts) {
2120 unregister_hotcpu_notifier(&mp->m_icsb_notifier);
2121 free_percpu(mp->m_sb_cnts);
2122 }
2123 mutex_destroy(&mp->m_icsb_mutex);
2124}
2125
2126STATIC_INLINE void
2127xfs_icsb_lock_cntr(
2128 xfs_icsb_cnts_t *icsbp)
2129{
2130 while (test_and_set_bit(XFS_ICSB_FLAG_LOCK, &icsbp->icsb_flags)) {
2131 ndelay(1000);
2132 }
2133}
2134
2135STATIC_INLINE void
2136xfs_icsb_unlock_cntr(
2137 xfs_icsb_cnts_t *icsbp)
2138{
2139 clear_bit(XFS_ICSB_FLAG_LOCK, &icsbp->icsb_flags);
2140}
2141
2142
2143STATIC_INLINE void
2144xfs_icsb_lock_all_counters(
2145 xfs_mount_t *mp)
2146{
2147 xfs_icsb_cnts_t *cntp;
2148 int i;
2149
2150 for_each_online_cpu(i) {
2151 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
2152 xfs_icsb_lock_cntr(cntp);
2153 }
2154}
2155
2156STATIC_INLINE void
2157xfs_icsb_unlock_all_counters(
2158 xfs_mount_t *mp)
2159{
2160 xfs_icsb_cnts_t *cntp;
2161 int i;
2162
2163 for_each_online_cpu(i) {
2164 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
2165 xfs_icsb_unlock_cntr(cntp);
2166 }
2167}
2168
2169STATIC void
2170xfs_icsb_count(
2171 xfs_mount_t *mp,
2172 xfs_icsb_cnts_t *cnt,
2173 int flags)
2174{
2175 xfs_icsb_cnts_t *cntp;
2176 int i;
2177
2178 memset(cnt, 0, sizeof(xfs_icsb_cnts_t));
2179
2180 if (!(flags & XFS_ICSB_LAZY_COUNT))
2181 xfs_icsb_lock_all_counters(mp);
2182
2183 for_each_online_cpu(i) {
2184 cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
2185 cnt->icsb_icount += cntp->icsb_icount;
2186 cnt->icsb_ifree += cntp->icsb_ifree;
2187 cnt->icsb_fdblocks += cntp->icsb_fdblocks;
2188 }
2189
2190 if (!(flags & XFS_ICSB_LAZY_COUNT))
2191 xfs_icsb_unlock_all_counters(mp);
2192}
2193
2194STATIC int
2195xfs_icsb_counter_disabled(
2196 xfs_mount_t *mp,
2197 xfs_sb_field_t field)
2198{
2199 ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS));
2200 return test_bit(field, &mp->m_icsb_counters);
2201}
2202
2203STATIC void
2204xfs_icsb_disable_counter(
2205 xfs_mount_t *mp,
2206 xfs_sb_field_t field)
2207{
2208 xfs_icsb_cnts_t cnt;
2209
2210 ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS));
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220 if (xfs_icsb_counter_disabled(mp, field))
2221 return;
2222
2223 xfs_icsb_lock_all_counters(mp);
2224 if (!test_and_set_bit(field, &mp->m_icsb_counters)) {
2225
2226
2227 xfs_icsb_count(mp, &cnt, XFS_ICSB_LAZY_COUNT);
2228 switch(field) {
2229 case XFS_SBS_ICOUNT:
2230 mp->m_sb.sb_icount = cnt.icsb_icount;
2231 break;
2232 case XFS_SBS_IFREE:
2233 mp->m_sb.sb_ifree = cnt.icsb_ifree;
2234 break;
2235 case XFS_SBS_FDBLOCKS:
2236 mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
2237 break;
2238 default:
2239 BUG();
2240 }
2241 }
2242
2243 xfs_icsb_unlock_all_counters(mp);
2244}
2245
2246STATIC void
2247xfs_icsb_enable_counter(
2248 xfs_mount_t *mp,
2249 xfs_sb_field_t field,
2250 uint64_t count,
2251 uint64_t resid)
2252{
2253 xfs_icsb_cnts_t *cntp;
2254 int i;
2255
2256 ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS));
2257
2258 xfs_icsb_lock_all_counters(mp);
2259 for_each_online_cpu(i) {
2260 cntp = per_cpu_ptr(mp->m_sb_cnts, i);
2261 switch (field) {
2262 case XFS_SBS_ICOUNT:
2263 cntp->icsb_icount = count + resid;
2264 break;
2265 case XFS_SBS_IFREE:
2266 cntp->icsb_ifree = count + resid;
2267 break;
2268 case XFS_SBS_FDBLOCKS:
2269 cntp->icsb_fdblocks = count + resid;
2270 break;
2271 default:
2272 BUG();
2273 break;
2274 }
2275 resid = 0;
2276 }
2277 clear_bit(field, &mp->m_icsb_counters);
2278 xfs_icsb_unlock_all_counters(mp);
2279}
2280
2281void
2282xfs_icsb_sync_counters_locked(
2283 xfs_mount_t *mp,
2284 int flags)
2285{
2286 xfs_icsb_cnts_t cnt;
2287
2288 xfs_icsb_count(mp, &cnt, flags);
2289
2290 if (!xfs_icsb_counter_disabled(mp, XFS_SBS_ICOUNT))
2291 mp->m_sb.sb_icount = cnt.icsb_icount;
2292 if (!xfs_icsb_counter_disabled(mp, XFS_SBS_IFREE))
2293 mp->m_sb.sb_ifree = cnt.icsb_ifree;
2294 if (!xfs_icsb_counter_disabled(mp, XFS_SBS_FDBLOCKS))
2295 mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
2296}
2297
2298
2299
2300
2301void
2302xfs_icsb_sync_counters(
2303 xfs_mount_t *mp,
2304 int flags)
2305{
2306 spin_lock(&mp->m_sb_lock);
2307 xfs_icsb_sync_counters_locked(mp, flags);
2308 spin_unlock(&mp->m_sb_lock);
2309}
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327#define XFS_ICSB_INO_CNTR_REENABLE (uint64_t)64
2328#define XFS_ICSB_FDBLK_CNTR_REENABLE(mp) \
2329 (uint64_t)(512 + XFS_ALLOC_SET_ASIDE(mp))
2330STATIC void
2331xfs_icsb_balance_counter_locked(
2332 xfs_mount_t *mp,
2333 xfs_sb_field_t field,
2334 int min_per_cpu)
2335{
2336 uint64_t count, resid;
2337 int weight = num_online_cpus();
2338 uint64_t min = (uint64_t)min_per_cpu;
2339
2340
2341 xfs_icsb_disable_counter(mp, field);
2342
2343
2344 switch (field) {
2345 case XFS_SBS_ICOUNT:
2346 count = mp->m_sb.sb_icount;
2347 resid = do_div(count, weight);
2348 if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE))
2349 return;
2350 break;
2351 case XFS_SBS_IFREE:
2352 count = mp->m_sb.sb_ifree;
2353 resid = do_div(count, weight);
2354 if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE))
2355 return;
2356 break;
2357 case XFS_SBS_FDBLOCKS:
2358 count = mp->m_sb.sb_fdblocks;
2359 resid = do_div(count, weight);
2360 if (count < max(min, XFS_ICSB_FDBLK_CNTR_REENABLE(mp)))
2361 return;
2362 break;
2363 default:
2364 BUG();
2365 count = resid = 0;
2366 break;
2367 }
2368
2369 xfs_icsb_enable_counter(mp, field, count, resid);
2370}
2371
2372STATIC void
2373xfs_icsb_balance_counter(
2374 xfs_mount_t *mp,
2375 xfs_sb_field_t fields,
2376 int min_per_cpu)
2377{
2378 spin_lock(&mp->m_sb_lock);
2379 xfs_icsb_balance_counter_locked(mp, fields, min_per_cpu);
2380 spin_unlock(&mp->m_sb_lock);
2381}
2382
2383STATIC int
2384xfs_icsb_modify_counters(
2385 xfs_mount_t *mp,
2386 xfs_sb_field_t field,
2387 int64_t delta,
2388 int rsvd)
2389{
2390 xfs_icsb_cnts_t *icsbp;
2391 long long lcounter;
2392 int cpu, ret = 0;
2393
2394 might_sleep();
2395again:
2396 cpu = get_cpu();
2397 icsbp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, cpu);
2398
2399
2400
2401
2402 if (unlikely(xfs_icsb_counter_disabled(mp, field)))
2403 goto slow_path;
2404 xfs_icsb_lock_cntr(icsbp);
2405 if (unlikely(xfs_icsb_counter_disabled(mp, field))) {
2406 xfs_icsb_unlock_cntr(icsbp);
2407 goto slow_path;
2408 }
2409
2410 switch (field) {
2411 case XFS_SBS_ICOUNT:
2412 lcounter = icsbp->icsb_icount;
2413 lcounter += delta;
2414 if (unlikely(lcounter < 0))
2415 goto balance_counter;
2416 icsbp->icsb_icount = lcounter;
2417 break;
2418
2419 case XFS_SBS_IFREE:
2420 lcounter = icsbp->icsb_ifree;
2421 lcounter += delta;
2422 if (unlikely(lcounter < 0))
2423 goto balance_counter;
2424 icsbp->icsb_ifree = lcounter;
2425 break;
2426
2427 case XFS_SBS_FDBLOCKS:
2428 BUG_ON((mp->m_resblks - mp->m_resblks_avail) != 0);
2429
2430 lcounter = icsbp->icsb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
2431 lcounter += delta;
2432 if (unlikely(lcounter < 0))
2433 goto balance_counter;
2434 icsbp->icsb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp);
2435 break;
2436 default:
2437 BUG();
2438 break;
2439 }
2440 xfs_icsb_unlock_cntr(icsbp);
2441 put_cpu();
2442 return 0;
2443
2444slow_path:
2445 put_cpu();
2446
2447
2448
2449
2450
2451
2452 xfs_icsb_lock(mp);
2453
2454
2455
2456
2457
2458
2459
2460 if (!(xfs_icsb_counter_disabled(mp, field))) {
2461 xfs_icsb_unlock(mp);
2462 goto again;
2463 }
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476 spin_lock(&mp->m_sb_lock);
2477 ret = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd);
2478 spin_unlock(&mp->m_sb_lock);
2479
2480
2481
2482
2483
2484
2485
2486 if (ret != ENOSPC)
2487 xfs_icsb_balance_counter(mp, field, 0);
2488 xfs_icsb_unlock(mp);
2489 return ret;
2490
2491balance_counter:
2492 xfs_icsb_unlock_cntr(icsbp);
2493 put_cpu();
2494
2495
2496
2497
2498
2499
2500
2501 xfs_icsb_lock(mp);
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511 xfs_icsb_balance_counter(mp, field, delta);
2512 xfs_icsb_unlock(mp);
2513 goto again;
2514}
2515
2516#endif
2517