aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMingming Cao <cmm@us.ibm.com>2006-06-23 05:05:41 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-23 10:43:06 -0400
commit0216bfcffe424a5473daa4da47440881b36c1f41 (patch)
tree80eaa49bfc644b070e57c251285048992ac6fafc
parent3cbc564024d8f174202f023e8a2991782f6a9431 (diff)
[PATCH] percpu counter data type changes to suppport more than 2**31 ext3 free blocks counter
The percpu counter data type are changed in this set of patches to support more users like ext3 who need more than 32 bit to store the free blocks total in the filesystem. - Generic perpcu counters data type changes. The size of the global counter and local counter were explictly specified using s64 and s32. The global counter is changed from long to s64, while the local counter is changed from long to s32, so we could avoid doing 64 bit update in most cases. - Users of the percpu counters are updated to make use of the new percpu_counter_init() routine now taking an additional parameter to allow users to pass the initial value of the global counter. Signed-off-by: Mingming Cao <cmm@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/ext2/super.c25
-rw-r--r--fs/ext3/super.c36
-rw-r--r--fs/file_table.c2
-rw-r--r--include/linux/percpu_counter.h38
-rw-r--r--lib/percpu_counter.c10
5 files changed, 58 insertions, 53 deletions
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index a6c4d6e02324..ee4ba759581e 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -834,9 +834,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
834 printk ("EXT2-fs: not enough memory\n"); 834 printk ("EXT2-fs: not enough memory\n");
835 goto failed_mount; 835 goto failed_mount;
836 } 836 }
837 percpu_counter_init(&sbi->s_freeblocks_counter);
838 percpu_counter_init(&sbi->s_freeinodes_counter);
839 percpu_counter_init(&sbi->s_dirs_counter);
840 bgl_lock_init(&sbi->s_blockgroup_lock); 837 bgl_lock_init(&sbi->s_blockgroup_lock);
841 sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(*sbi->s_debts), 838 sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(*sbi->s_debts),
842 GFP_KERNEL); 839 GFP_KERNEL);
@@ -863,6 +860,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
863 sbi->s_gdb_count = db_count; 860 sbi->s_gdb_count = db_count;
864 get_random_bytes(&sbi->s_next_generation, sizeof(u32)); 861 get_random_bytes(&sbi->s_next_generation, sizeof(u32));
865 spin_lock_init(&sbi->s_next_gen_lock); 862 spin_lock_init(&sbi->s_next_gen_lock);
863
864 percpu_counter_init(&sbi->s_freeblocks_counter,
865 ext2_count_free_blocks(sb));
866 percpu_counter_init(&sbi->s_freeinodes_counter,
867 ext2_count_free_inodes(sb));
868 percpu_counter_init(&sbi->s_dirs_counter,
869 ext2_count_dirs(sb));
866 /* 870 /*
867 * set up enough so that it can read an inode 871 * set up enough so that it can read an inode
868 */ 872 */
@@ -874,24 +878,18 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
874 if (!sb->s_root) { 878 if (!sb->s_root) {
875 iput(root); 879 iput(root);
876 printk(KERN_ERR "EXT2-fs: get root inode failed\n"); 880 printk(KERN_ERR "EXT2-fs: get root inode failed\n");
877 goto failed_mount2; 881 goto failed_mount3;
878 } 882 }
879 if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { 883 if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
880 dput(sb->s_root); 884 dput(sb->s_root);
881 sb->s_root = NULL; 885 sb->s_root = NULL;
882 printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n"); 886 printk(KERN_ERR "EXT2-fs: corrupt root inode, run e2fsck\n");
883 goto failed_mount2; 887 goto failed_mount3;
884 } 888 }
885 if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) 889 if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
886 ext2_warning(sb, __FUNCTION__, 890 ext2_warning(sb, __FUNCTION__,
887 "mounting ext3 filesystem as ext2"); 891 "mounting ext3 filesystem as ext2");
888 ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY); 892 ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
889 percpu_counter_mod(&sbi->s_freeblocks_counter,
890 ext2_count_free_blocks(sb));
891 percpu_counter_mod(&sbi->s_freeinodes_counter,
892 ext2_count_free_inodes(sb));
893 percpu_counter_mod(&sbi->s_dirs_counter,
894 ext2_count_dirs(sb));
895 return 0; 893 return 0;
896 894
897cantfind_ext2: 895cantfind_ext2:
@@ -899,7 +897,10 @@ cantfind_ext2:
899 printk("VFS: Can't find an ext2 filesystem on dev %s.\n", 897 printk("VFS: Can't find an ext2 filesystem on dev %s.\n",
900 sb->s_id); 898 sb->s_id);
901 goto failed_mount; 899 goto failed_mount;
902 900failed_mount3:
901 percpu_counter_destroy(&sbi->s_freeblocks_counter);
902 percpu_counter_destroy(&sbi->s_freeinodes_counter);
903 percpu_counter_destroy(&sbi->s_dirs_counter);
903failed_mount2: 904failed_mount2:
904 for (i = 0; i < db_count; i++) 905 for (i = 0; i < db_count; i++)
905 brelse(sbi->s_group_desc[i]); 906 brelse(sbi->s_group_desc[i]);
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 1a198b3985c9..a60cc6ec130f 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -1580,9 +1580,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
1580 goto failed_mount; 1580 goto failed_mount;
1581 } 1581 }
1582 1582
1583 percpu_counter_init(&sbi->s_freeblocks_counter);
1584 percpu_counter_init(&sbi->s_freeinodes_counter);
1585 percpu_counter_init(&sbi->s_dirs_counter);
1586 bgl_lock_init(&sbi->s_blockgroup_lock); 1583 bgl_lock_init(&sbi->s_blockgroup_lock);
1587 1584
1588 for (i = 0; i < db_count; i++) { 1585 for (i = 0; i < db_count; i++) {
@@ -1602,6 +1599,14 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
1602 sbi->s_gdb_count = db_count; 1599 sbi->s_gdb_count = db_count;
1603 get_random_bytes(&sbi->s_next_generation, sizeof(u32)); 1600 get_random_bytes(&sbi->s_next_generation, sizeof(u32));
1604 spin_lock_init(&sbi->s_next_gen_lock); 1601 spin_lock_init(&sbi->s_next_gen_lock);
1602
1603 percpu_counter_init(&sbi->s_freeblocks_counter,
1604 ext3_count_free_blocks(sb));
1605 percpu_counter_init(&sbi->s_freeinodes_counter,
1606 ext3_count_free_inodes(sb));
1607 percpu_counter_init(&sbi->s_dirs_counter,
1608 ext3_count_dirs(sb));
1609
1605 /* per fileystem reservation list head & lock */ 1610 /* per fileystem reservation list head & lock */
1606 spin_lock_init(&sbi->s_rsv_window_lock); 1611 spin_lock_init(&sbi->s_rsv_window_lock);
1607 sbi->s_rsv_window_root = RB_ROOT; 1612 sbi->s_rsv_window_root = RB_ROOT;
@@ -1640,16 +1645,16 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
1640 if (!test_opt(sb, NOLOAD) && 1645 if (!test_opt(sb, NOLOAD) &&
1641 EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { 1646 EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
1642 if (ext3_load_journal(sb, es, journal_devnum)) 1647 if (ext3_load_journal(sb, es, journal_devnum))
1643 goto failed_mount2; 1648 goto failed_mount3;
1644 } else if (journal_inum) { 1649 } else if (journal_inum) {
1645 if (ext3_create_journal(sb, es, journal_inum)) 1650 if (ext3_create_journal(sb, es, journal_inum))
1646 goto failed_mount2; 1651 goto failed_mount3;
1647 } else { 1652 } else {
1648 if (!silent) 1653 if (!silent)
1649 printk (KERN_ERR 1654 printk (KERN_ERR
1650 "ext3: No journal on filesystem on %s\n", 1655 "ext3: No journal on filesystem on %s\n",
1651 sb->s_id); 1656 sb->s_id);
1652 goto failed_mount2; 1657 goto failed_mount3;
1653 } 1658 }
1654 1659
1655 /* We have now updated the journal if required, so we can 1660 /* We have now updated the journal if required, so we can
@@ -1672,7 +1677,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
1672 (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) { 1677 (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) {
1673 printk(KERN_ERR "EXT3-fs: Journal does not support " 1678 printk(KERN_ERR "EXT3-fs: Journal does not support "
1674 "requested data journaling mode\n"); 1679 "requested data journaling mode\n");
1675 goto failed_mount3; 1680 goto failed_mount4;
1676 } 1681 }
1677 default: 1682 default:
1678 break; 1683 break;
@@ -1695,13 +1700,13 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
1695 if (!sb->s_root) { 1700 if (!sb->s_root) {
1696 printk(KERN_ERR "EXT3-fs: get root inode failed\n"); 1701 printk(KERN_ERR "EXT3-fs: get root inode failed\n");
1697 iput(root); 1702 iput(root);
1698 goto failed_mount3; 1703 goto failed_mount4;
1699 } 1704 }
1700 if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { 1705 if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
1701 dput(sb->s_root); 1706 dput(sb->s_root);
1702 sb->s_root = NULL; 1707 sb->s_root = NULL;
1703 printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n"); 1708 printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n");
1704 goto failed_mount3; 1709 goto failed_mount4;
1705 } 1710 }
1706 1711
1707 ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY); 1712 ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
@@ -1724,13 +1729,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
1724 test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": 1729 test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered":
1725 "writeback"); 1730 "writeback");
1726 1731
1727 percpu_counter_mod(&sbi->s_freeblocks_counter,
1728 ext3_count_free_blocks(sb));
1729 percpu_counter_mod(&sbi->s_freeinodes_counter,
1730 ext3_count_free_inodes(sb));
1731 percpu_counter_mod(&sbi->s_dirs_counter,
1732 ext3_count_dirs(sb));
1733
1734 lock_kernel(); 1732 lock_kernel();
1735 return 0; 1733 return 0;
1736 1734
@@ -1740,8 +1738,12 @@ cantfind_ext3:
1740 sb->s_id); 1738 sb->s_id);
1741 goto failed_mount; 1739 goto failed_mount;
1742 1740
1743failed_mount3: 1741failed_mount4:
1744 journal_destroy(sbi->s_journal); 1742 journal_destroy(sbi->s_journal);
1743failed_mount3:
1744 percpu_counter_destroy(&sbi->s_freeblocks_counter);
1745 percpu_counter_destroy(&sbi->s_freeinodes_counter);
1746 percpu_counter_destroy(&sbi->s_dirs_counter);
1745failed_mount2: 1747failed_mount2:
1746 for (i = 0; i < db_count; i++) 1748 for (i = 0; i < db_count; i++)
1747 brelse(sbi->s_group_desc[i]); 1749 brelse(sbi->s_group_desc[i]);
diff --git a/fs/file_table.c b/fs/file_table.c
index bcea1998b4de..506d5307108d 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -300,5 +300,5 @@ void __init files_init(unsigned long mempages)
300 if (files_stat.max_files < NR_FILE) 300 if (files_stat.max_files < NR_FILE)
301 files_stat.max_files = NR_FILE; 301 files_stat.max_files = NR_FILE;
302 files_defer_init(); 302 files_defer_init();
303 percpu_counter_init(&nr_files); 303 percpu_counter_init(&nr_files, 0);
304} 304}
diff --git a/include/linux/percpu_counter.h b/include/linux/percpu_counter.h
index 66b5de404f22..f5aa593ccf32 100644
--- a/include/linux/percpu_counter.h
+++ b/include/linux/percpu_counter.h
@@ -10,13 +10,14 @@
10#include <linux/smp.h> 10#include <linux/smp.h>
11#include <linux/threads.h> 11#include <linux/threads.h>
12#include <linux/percpu.h> 12#include <linux/percpu.h>
13#include <linux/types.h>
13 14
14#ifdef CONFIG_SMP 15#ifdef CONFIG_SMP
15 16
16struct percpu_counter { 17struct percpu_counter {
17 spinlock_t lock; 18 spinlock_t lock;
18 long count; 19 s64 count;
19 long *counters; 20 s32 *counters;
20}; 21};
21 22
22#if NR_CPUS >= 16 23#if NR_CPUS >= 16
@@ -25,11 +26,11 @@ struct percpu_counter {
25#define FBC_BATCH (NR_CPUS*4) 26#define FBC_BATCH (NR_CPUS*4)
26#endif 27#endif
27 28
28static inline void percpu_counter_init(struct percpu_counter *fbc) 29static inline void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
29{ 30{
30 spin_lock_init(&fbc->lock); 31 spin_lock_init(&fbc->lock);
31 fbc->count = 0; 32 fbc->count = amount;
32 fbc->counters = alloc_percpu(long); 33 fbc->counters = alloc_percpu(s32);
33} 34}
34 35
35static inline void percpu_counter_destroy(struct percpu_counter *fbc) 36static inline void percpu_counter_destroy(struct percpu_counter *fbc)
@@ -37,10 +38,10 @@ static inline void percpu_counter_destroy(struct percpu_counter *fbc)
37 free_percpu(fbc->counters); 38 free_percpu(fbc->counters);
38} 39}
39 40
40void percpu_counter_mod(struct percpu_counter *fbc, long amount); 41void percpu_counter_mod(struct percpu_counter *fbc, s32 amount);
41long percpu_counter_sum(struct percpu_counter *fbc); 42s64 percpu_counter_sum(struct percpu_counter *fbc);
42 43
43static inline long percpu_counter_read(struct percpu_counter *fbc) 44static inline s64 percpu_counter_read(struct percpu_counter *fbc)
44{ 45{
45 return fbc->count; 46 return fbc->count;
46} 47}
@@ -48,13 +49,14 @@ static inline long percpu_counter_read(struct percpu_counter *fbc)
48/* 49/*
49 * It is possible for the percpu_counter_read() to return a small negative 50 * It is possible for the percpu_counter_read() to return a small negative
50 * number for some counter which should never be negative. 51 * number for some counter which should never be negative.
52 *
51 */ 53 */
52static inline long percpu_counter_read_positive(struct percpu_counter *fbc) 54static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
53{ 55{
54 long ret = fbc->count; 56 s64 ret = fbc->count;
55 57
56 barrier(); /* Prevent reloads of fbc->count */ 58 barrier(); /* Prevent reloads of fbc->count */
57 if (ret > 0) 59 if (ret >= 0)
58 return ret; 60 return ret;
59 return 1; 61 return 1;
60} 62}
@@ -62,12 +64,12 @@ static inline long percpu_counter_read_positive(struct percpu_counter *fbc)
62#else 64#else
63 65
64struct percpu_counter { 66struct percpu_counter {
65 long count; 67 s64 count;
66}; 68};
67 69
68static inline void percpu_counter_init(struct percpu_counter *fbc) 70static inline void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
69{ 71{
70 fbc->count = 0; 72 fbc->count = amount;
71} 73}
72 74
73static inline void percpu_counter_destroy(struct percpu_counter *fbc) 75static inline void percpu_counter_destroy(struct percpu_counter *fbc)
@@ -75,24 +77,24 @@ static inline void percpu_counter_destroy(struct percpu_counter *fbc)
75} 77}
76 78
77static inline void 79static inline void
78percpu_counter_mod(struct percpu_counter *fbc, long amount) 80percpu_counter_mod(struct percpu_counter *fbc, s32 amount)
79{ 81{
80 preempt_disable(); 82 preempt_disable();
81 fbc->count += amount; 83 fbc->count += amount;
82 preempt_enable(); 84 preempt_enable();
83} 85}
84 86
85static inline long percpu_counter_read(struct percpu_counter *fbc) 87static inline s64 percpu_counter_read(struct percpu_counter *fbc)
86{ 88{
87 return fbc->count; 89 return fbc->count;
88} 90}
89 91
90static inline long percpu_counter_read_positive(struct percpu_counter *fbc) 92static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
91{ 93{
92 return fbc->count; 94 return fbc->count;
93} 95}
94 96
95static inline long percpu_counter_sum(struct percpu_counter *fbc) 97static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
96{ 98{
97 return percpu_counter_read_positive(fbc); 99 return percpu_counter_read_positive(fbc);
98} 100}
diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c
index 7a87003f8e8f..850449080e1c 100644
--- a/lib/percpu_counter.c
+++ b/lib/percpu_counter.c
@@ -5,10 +5,10 @@
5#include <linux/percpu_counter.h> 5#include <linux/percpu_counter.h>
6#include <linux/module.h> 6#include <linux/module.h>
7 7
8void percpu_counter_mod(struct percpu_counter *fbc, long amount) 8void percpu_counter_mod(struct percpu_counter *fbc, s32 amount)
9{ 9{
10 long count; 10 long count;
11 long *pcount; 11 s32 *pcount;
12 int cpu = get_cpu(); 12 int cpu = get_cpu();
13 13
14 pcount = per_cpu_ptr(fbc->counters, cpu); 14 pcount = per_cpu_ptr(fbc->counters, cpu);
@@ -29,15 +29,15 @@ EXPORT_SYMBOL(percpu_counter_mod);
29 * Add up all the per-cpu counts, return the result. This is a more accurate 29 * Add up all the per-cpu counts, return the result. This is a more accurate
30 * but much slower version of percpu_counter_read_positive() 30 * but much slower version of percpu_counter_read_positive()
31 */ 31 */
32long percpu_counter_sum(struct percpu_counter *fbc) 32s64 percpu_counter_sum(struct percpu_counter *fbc)
33{ 33{
34 long ret; 34 s64 ret;
35 int cpu; 35 int cpu;
36 36
37 spin_lock(&fbc->lock); 37 spin_lock(&fbc->lock);
38 ret = fbc->count; 38 ret = fbc->count;
39 for_each_possible_cpu(cpu) { 39 for_each_possible_cpu(cpu) {
40 long *pcount = per_cpu_ptr(fbc->counters, cpu); 40 s32 *pcount = per_cpu_ptr(fbc->counters, cpu);
41 ret += *pcount; 41 ret += *pcount;
42 } 42 }
43 spin_unlock(&fbc->lock); 43 spin_unlock(&fbc->lock);