2007-08-16 08:34:06

by Peter Zijlstra

[permalink] [raw]
Subject: [PATCH 09/23] lib: percpu_counter_init error handling

alloc_percpu can fail, propagate that error.

Signed-off-by: Peter Zijlstra <[email protected]>
---
fs/ext2/super.c | 11 ++++++++---
fs/ext3/super.c | 11 ++++++++---
fs/ext4/super.c | 11 ++++++++---
include/linux/percpu_counter.h | 5 +++--
lib/percpu_counter.c | 8 +++++++-
5 files changed, 34 insertions(+), 12 deletions(-)

Index: linux-2.6/fs/ext2/super.c
===================================================================
--- linux-2.6.orig/fs/ext2/super.c
+++ linux-2.6/fs/ext2/super.c
@@ -725,6 +725,7 @@ static int ext2_fill_super(struct super_
int db_count;
int i, j;
__le32 features;
+ int err;

sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
@@ -996,12 +997,16 @@ static int ext2_fill_super(struct super_
sbi->s_rsv_window_head.rsv_goal_size = 0;
ext2_rsv_window_add(sb, &sbi->s_rsv_window_head);

- percpu_counter_init(&sbi->s_freeblocks_counter,
+ err = percpu_counter_init(&sbi->s_freeblocks_counter,
ext2_count_free_blocks(sb));
- percpu_counter_init(&sbi->s_freeinodes_counter,
+ err |= percpu_counter_init(&sbi->s_freeinodes_counter,
ext2_count_free_inodes(sb));
- percpu_counter_init(&sbi->s_dirs_counter,
+ err |= percpu_counter_init(&sbi->s_dirs_counter,
ext2_count_dirs(sb));
+ if (err) {
+ printk(KERN_ERR "EXT2-fs: insufficient memory\n");
+ goto failed_mount3;
+ }
/*
* set up enough so that it can read an inode
*/
Index: linux-2.6/fs/ext3/super.c
===================================================================
--- linux-2.6.orig/fs/ext3/super.c
+++ linux-2.6/fs/ext3/super.c
@@ -1485,6 +1485,7 @@ static int ext3_fill_super (struct super
int i;
int needs_recovery;
__le32 features;
+ int err;

sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
@@ -1745,12 +1746,16 @@ static int ext3_fill_super (struct super
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
spin_lock_init(&sbi->s_next_gen_lock);

- percpu_counter_init(&sbi->s_freeblocks_counter,
+ err = percpu_counter_init(&sbi->s_freeblocks_counter,
ext3_count_free_blocks(sb));
- percpu_counter_init(&sbi->s_freeinodes_counter,
+ err |= percpu_counter_init(&sbi->s_freeinodes_counter,
ext3_count_free_inodes(sb));
- percpu_counter_init(&sbi->s_dirs_counter,
+ err |= percpu_counter_init(&sbi->s_dirs_counter,
ext3_count_dirs(sb));
+ if (err) {
+ printk(KERN_ERR "EXT3-fs: insufficient memory\n");
+ goto failed_mount3;
+ }

/* per fileystem reservation list head & lock */
spin_lock_init(&sbi->s_rsv_window_lock);
Index: linux-2.6/fs/ext4/super.c
===================================================================
--- linux-2.6.orig/fs/ext4/super.c
+++ linux-2.6/fs/ext4/super.c
@@ -1576,6 +1576,7 @@ static int ext4_fill_super (struct super
int needs_recovery;
__le32 features;
__u64 blocks_count;
+ int err;

sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
@@ -1857,12 +1858,16 @@ static int ext4_fill_super (struct super
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
spin_lock_init(&sbi->s_next_gen_lock);

- percpu_counter_init(&sbi->s_freeblocks_counter,
+ err = percpu_counter_init(&sbi->s_freeblocks_counter,
ext4_count_free_blocks(sb));
- percpu_counter_init(&sbi->s_freeinodes_counter,
+ err |= percpu_counter_init(&sbi->s_freeinodes_counter,
ext4_count_free_inodes(sb));
- percpu_counter_init(&sbi->s_dirs_counter,
+ err |= percpu_counter_init(&sbi->s_dirs_counter,
ext4_count_dirs(sb));
+ if (err) {
+ printk(KERN_ERR "EXT4-fs: insufficient memory\n");
+ goto failed_mount3;
+ }

/* per fileystem reservation list head & lock */
spin_lock_init(&sbi->s_rsv_window_lock);
Index: linux-2.6/include/linux/percpu_counter.h
===================================================================
--- linux-2.6.orig/include/linux/percpu_counter.h
+++ linux-2.6/include/linux/percpu_counter.h
@@ -30,7 +30,7 @@ struct percpu_counter {
#define FBC_BATCH (NR_CPUS*4)
#endif

-void percpu_counter_init(struct percpu_counter *fbc, s64 amount);
+int percpu_counter_init(struct percpu_counter *fbc, s64 amount);
void percpu_counter_destroy(struct percpu_counter *fbc);
void percpu_counter_set(struct percpu_counter *fbc, s64 amount);
void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch);
@@ -78,9 +78,10 @@ struct percpu_counter {
s64 count;
};

-static inline void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
+static inline int percpu_counter_init(struct percpu_counter *fbc, s64 amount)
{
fbc->count = amount;
+ return 0;
}

static inline void percpu_counter_destroy(struct percpu_counter *fbc)
Index: linux-2.6/lib/percpu_counter.c
===================================================================
--- linux-2.6.orig/lib/percpu_counter.c
+++ linux-2.6/lib/percpu_counter.c
@@ -68,21 +68,27 @@ s64 __percpu_counter_sum(struct percpu_c
}
EXPORT_SYMBOL(__percpu_counter_sum);

-void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
+int percpu_counter_init(struct percpu_counter *fbc, s64 amount)
{
spin_lock_init(&fbc->lock);
fbc->count = amount;
fbc->counters = alloc_percpu(s32);
+ if (!fbc->counters)
+ return -ENOMEM;
#ifdef CONFIG_HOTPLUG_CPU
mutex_lock(&percpu_counters_lock);
list_add(&fbc->list, &percpu_counters);
mutex_unlock(&percpu_counters_lock);
#endif
+ return 0;
}
EXPORT_SYMBOL(percpu_counter_init);

void percpu_counter_destroy(struct percpu_counter *fbc)
{
+ if (!fbc->counters)
+ return;
+
free_percpu(fbc->counters);
#ifdef CONFIG_HOTPLUG_CPU
mutex_lock(&percpu_counters_lock);

--


2007-08-17 15:57:47

by Josef Sipek

[permalink] [raw]
Subject: Re: [PATCH 09/23] lib: percpu_counter_init error handling

On Thu, Aug 16, 2007 at 09:45:34AM +0200, Peter Zijlstra wrote:
> alloc_percpu can fail, propagate that error.
>
> Signed-off-by: Peter Zijlstra <[email protected]>
> ---
> fs/ext2/super.c | 11 ++++++++---
> fs/ext3/super.c | 11 ++++++++---
> fs/ext4/super.c | 11 ++++++++---
> include/linux/percpu_counter.h | 5 +++--
> lib/percpu_counter.c | 8 +++++++-
> 5 files changed, 34 insertions(+), 12 deletions(-)
>
> Index: linux-2.6/fs/ext2/super.c
> ===================================================================
> --- linux-2.6.orig/fs/ext2/super.c
> +++ linux-2.6/fs/ext2/super.c
> @@ -725,6 +725,7 @@ static int ext2_fill_super(struct super_
> int db_count;
> int i, j;
> __le32 features;
> + int err;
>
> sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
> if (!sbi)
> @@ -996,12 +997,16 @@ static int ext2_fill_super(struct super_
> sbi->s_rsv_window_head.rsv_goal_size = 0;
> ext2_rsv_window_add(sb, &sbi->s_rsv_window_head);
>
> - percpu_counter_init(&sbi->s_freeblocks_counter,
> + err = percpu_counter_init(&sbi->s_freeblocks_counter,
> ext2_count_free_blocks(sb));
> - percpu_counter_init(&sbi->s_freeinodes_counter,
> + err |= percpu_counter_init(&sbi->s_freeinodes_counter,
> ext2_count_free_inodes(sb));
> - percpu_counter_init(&sbi->s_dirs_counter,
> + err |= percpu_counter_init(&sbi->s_dirs_counter,
> ext2_count_dirs(sb));
> + if (err) {
> + printk(KERN_ERR "EXT2-fs: insufficient memory\n");
> + goto failed_mount3;
> + }

Can percpu_counter_init fail with only one error code? If not, the error
code potentially used in future at failed_mount3 could be nonsensical
because of the bitwise or-ing.

> Index: linux-2.6/lib/percpu_counter.c
> ===================================================================
> --- linux-2.6.orig/lib/percpu_counter.c
> +++ linux-2.6/lib/percpu_counter.c
> @@ -68,21 +68,27 @@ s64 __percpu_counter_sum(struct percpu_c
> }
> EXPORT_SYMBOL(__percpu_counter_sum);
>
> -void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
> +int percpu_counter_init(struct percpu_counter *fbc, s64 amount)
> {
> spin_lock_init(&fbc->lock);
> fbc->count = amount;
> fbc->counters = alloc_percpu(s32);
> + if (!fbc->counters)
> + return -ENOMEM;
> #ifdef CONFIG_HOTPLUG_CPU
> mutex_lock(&percpu_counters_lock);
> list_add(&fbc->list, &percpu_counters);
> mutex_unlock(&percpu_counters_lock);
> #endif
> + return 0;
> }

I guess this answers my question. But I'd still be weary because a trivial
change here could produce very strange error codes in ext2/3/4.

Josef 'Jeff' Sipek.

--
Once you have their hardware. Never give it back.
(The First Rule of Hardware Acquisition)

2007-08-17 16:03:41

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH 09/23] lib: percpu_counter_init error handling

On Fri, 2007-08-17 at 11:56 -0400, Josef Sipek wrote:
> On Thu, Aug 16, 2007 at 09:45:34AM +0200, Peter Zijlstra wrote:
> )
> > @@ -996,12 +997,16 @@ static int ext2_fill_super(struct super_
> > sbi->s_rsv_window_head.rsv_goal_size = 0;
> > ext2_rsv_window_add(sb, &sbi->s_rsv_window_head);
> >
> > - percpu_counter_init(&sbi->s_freeblocks_counter,
> > + err = percpu_counter_init(&sbi->s_freeblocks_counter,
> > ext2_count_free_blocks(sb));
> > - percpu_counter_init(&sbi->s_freeinodes_counter,
> > + err |= percpu_counter_init(&sbi->s_freeinodes_counter,
> > ext2_count_free_inodes(sb));
> > - percpu_counter_init(&sbi->s_dirs_counter,
> > + err |= percpu_counter_init(&sbi->s_dirs_counter,
> > ext2_count_dirs(sb));
> > + if (err) {
> > + printk(KERN_ERR "EXT2-fs: insufficient memory\n");
> > + goto failed_mount3;
> > + }
>
> Can percpu_counter_init fail with only one error code? If not, the error
> code potentially used in future at failed_mount3 could be nonsensical
> because of the bitwise or-ing.

I guess I could have written saner code :-/ will try to come up with
something that is both clear and short.


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2007-08-18 08:10:00

by Peter Zijlstra

[permalink] [raw]
Subject: [PATCH 09/23] lib: percpu_counter_init error handling

On Fri, 2007-08-17 at 11:56 -0400, Josef Sipek wrote:
> On Thu, Aug 16, 2007 at 09:45:34AM +0200, Peter Zijlstra wrote:

> > Index: linux-2.6/fs/ext2/super.c
> > ===================================================================
> > --- linux-2.6.orig/fs/ext2/super.c
> > +++ linux-2.6/fs/ext2/super.c
> > @@ -725,6 +725,7 @@ static int ext2_fill_super(struct super_
> > int db_count;
> > int i, j;
> > __le32 features;
> > + int err;
> >
> > sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
> > if (!sbi)
> > @@ -996,12 +997,16 @@ static int ext2_fill_super(struct super_
> > sbi->s_rsv_window_head.rsv_goal_size = 0;
> > ext2_rsv_window_add(sb, &sbi->s_rsv_window_head);
> >
> > - percpu_counter_init(&sbi->s_freeblocks_counter,
> > + err = percpu_counter_init(&sbi->s_freeblocks_counter,
> > ext2_count_free_blocks(sb));
> > - percpu_counter_init(&sbi->s_freeinodes_counter,
> > + err |= percpu_counter_init(&sbi->s_freeinodes_counter,
> > ext2_count_free_inodes(sb));
> > - percpu_counter_init(&sbi->s_dirs_counter,
> > + err |= percpu_counter_init(&sbi->s_dirs_counter,
> > ext2_count_dirs(sb));
> > + if (err) {
> > + printk(KERN_ERR "EXT2-fs: insufficient memory\n");
> > + goto failed_mount3;
> > + }
>
> Can percpu_counter_init fail with only one error code? If not, the error
> code potentially used in future at failed_mount3 could be nonsensical
> because of the bitwise or-ing.

The actual value of err is irrelevant, it is not used after this not
zero check.

But how about this:
---
Subject: lib: percpu_counter_init error handling

alloc_percpu can fail, propagate that error.

Signed-off-by: Peter Zijlstra <[email protected]>
---
fs/ext2/super.c | 15 ++++++++++++---
fs/ext3/super.c | 21 +++++++++++++++------
fs/ext4/super.c | 21 +++++++++++++++------
include/linux/percpu_counter.h | 5 +++--
lib/percpu_counter.c | 8 +++++++-
5 files changed, 52 insertions(+), 18 deletions(-)

Index: linux-2.6/fs/ext2/super.c
===================================================================
--- linux-2.6.orig/fs/ext2/super.c
+++ linux-2.6/fs/ext2/super.c
@@ -725,6 +725,7 @@ static int ext2_fill_super(struct super_
int db_count;
int i, j;
__le32 features;
+ int err;

sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
@@ -996,12 +997,20 @@ static int ext2_fill_super(struct super_
sbi->s_rsv_window_head.rsv_goal_size = 0;
ext2_rsv_window_add(sb, &sbi->s_rsv_window_head);

- percpu_counter_init(&sbi->s_freeblocks_counter,
+ err = percpu_counter_init(&sbi->s_freeblocks_counter,
ext2_count_free_blocks(sb));
- percpu_counter_init(&sbi->s_freeinodes_counter,
+ if (!err) {
+ err = percpu_counter_init(&sbi->s_freeinodes_counter,
ext2_count_free_inodes(sb));
- percpu_counter_init(&sbi->s_dirs_counter,
+ }
+ if (!err) {
+ err = percpu_counter_init(&sbi->s_dirs_counter,
ext2_count_dirs(sb));
+ }
+ if (err) {
+ printk(KERN_ERR "EXT2-fs: insufficient memory\n");
+ goto failed_mount3;
+ }
/*
* set up enough so that it can read an inode
*/
Index: linux-2.6/fs/ext3/super.c
===================================================================
--- linux-2.6.orig/fs/ext3/super.c
+++ linux-2.6/fs/ext3/super.c
@@ -1485,6 +1485,7 @@ static int ext3_fill_super (struct super
int i;
int needs_recovery;
__le32 features;
+ int err;

sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
@@ -1745,12 +1746,20 @@ static int ext3_fill_super (struct super
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
spin_lock_init(&sbi->s_next_gen_lock);

- percpu_counter_init(&sbi->s_freeblocks_counter,
- ext3_count_free_blocks(sb));
- percpu_counter_init(&sbi->s_freeinodes_counter,
- ext3_count_free_inodes(sb));
- percpu_counter_init(&sbi->s_dirs_counter,
- ext3_count_dirs(sb));
+ err = percpu_counter_init(&sbi->s_freeblocks_counter,
+ ext3_count_free_blocks(sb));
+ if (!err) {
+ err = percpu_counter_init(&sbi->s_freeinodes_counter,
+ ext3_count_free_inodes(sb));
+ }
+ if (!err) {
+ err = percpu_counter_init(&sbi->s_dirs_counter,
+ ext3_count_dirs(sb));
+ }
+ if (err) {
+ printk(KERN_ERR "EXT3-fs: insufficient memory\n");
+ goto failed_mount3;
+ }

/* per fileystem reservation list head & lock */
spin_lock_init(&sbi->s_rsv_window_lock);
Index: linux-2.6/fs/ext4/super.c
===================================================================
--- linux-2.6.orig/fs/ext4/super.c
+++ linux-2.6/fs/ext4/super.c
@@ -1576,6 +1576,7 @@ static int ext4_fill_super (struct super
int needs_recovery;
__le32 features;
__u64 blocks_count;
+ int err;

sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
@@ -1857,12 +1858,20 @@ static int ext4_fill_super (struct super
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
spin_lock_init(&sbi->s_next_gen_lock);

- percpu_counter_init(&sbi->s_freeblocks_counter,
- ext4_count_free_blocks(sb));
- percpu_counter_init(&sbi->s_freeinodes_counter,
- ext4_count_free_inodes(sb));
- percpu_counter_init(&sbi->s_dirs_counter,
- ext4_count_dirs(sb));
+ err = percpu_counter_init(&sbi->s_freeblocks_counter,
+ ext4_count_free_blocks(sb));
+ if (!err) {
+ err = percpu_counter_init(&sbi->s_freeinodes_counter,
+ ext4_count_free_inodes(sb));
+ }
+ if (!err) {
+ err = percpu_counter_init(&sbi->s_dirs_counter,
+ ext4_count_dirs(sb));
+ }
+ if (err) {
+ printk(KERN_ERR "EXT4-fs: insufficient memory\n");
+ goto failed_mount3;
+ }

/* per fileystem reservation list head & lock */
spin_lock_init(&sbi->s_rsv_window_lock);
Index: linux-2.6/include/linux/percpu_counter.h
===================================================================
--- linux-2.6.orig/include/linux/percpu_counter.h
+++ linux-2.6/include/linux/percpu_counter.h
@@ -30,7 +30,7 @@ struct percpu_counter {
#define FBC_BATCH (NR_CPUS*4)
#endif

-void percpu_counter_init(struct percpu_counter *fbc, s64 amount);
+int percpu_counter_init(struct percpu_counter *fbc, s64 amount);
void percpu_counter_destroy(struct percpu_counter *fbc);
void percpu_counter_set(struct percpu_counter *fbc, s64 amount);
void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch);
@@ -78,9 +78,10 @@ struct percpu_counter {
s64 count;
};

-static inline void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
+static inline int percpu_counter_init(struct percpu_counter *fbc, s64 amount)
{
fbc->count = amount;
+ return 0;
}

static inline void percpu_counter_destroy(struct percpu_counter *fbc)
Index: linux-2.6/lib/percpu_counter.c
===================================================================
--- linux-2.6.orig/lib/percpu_counter.c
+++ linux-2.6/lib/percpu_counter.c
@@ -68,21 +68,27 @@ s64 __percpu_counter_sum(struct percpu_c
}
EXPORT_SYMBOL(__percpu_counter_sum);

-void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
+int percpu_counter_init(struct percpu_counter *fbc, s64 amount)
{
spin_lock_init(&fbc->lock);
fbc->count = amount;
fbc->counters = alloc_percpu(s32);
+ if (!fbc->counters)
+ return -ENOMEM;
#ifdef CONFIG_HOTPLUG_CPU
mutex_lock(&percpu_counters_lock);
list_add(&fbc->list, &percpu_counters);
mutex_unlock(&percpu_counters_lock);
#endif
+ return 0;
}
EXPORT_SYMBOL(percpu_counter_init);

void percpu_counter_destroy(struct percpu_counter *fbc)
{
+ if (!fbc->counters)
+ return;
+
free_percpu(fbc->counters);
#ifdef CONFIG_HOTPLUG_CPU
mutex_lock(&percpu_counters_lock);


Attachments:
signature.asc (189.00 B)
This is a digitally signed message part

2007-08-23 18:26:20

by Josef Sipek

[permalink] [raw]
Subject: Re: [PATCH 09/23] lib: percpu_counter_init error handling

On Sat, Aug 18, 2007 at 10:09:34AM +0200, Peter Zijlstra wrote:
> On Fri, 2007-08-17 at 11:56 -0400, Josef Sipek wrote:
> > On Thu, Aug 16, 2007 at 09:45:34AM +0200, Peter Zijlstra wrote:

Sorry...this mail got lost in the flood of email after a procmail rule
stopped working...

> The actual value of err is irrelevant, it is not used after this not
> zero check.
>
> But how about this:
> ---
> Subject: lib: percpu_counter_init error handling
>
> alloc_percpu can fail, propagate that error.
>
> Signed-off-by: Peter Zijlstra <[email protected]>
> ---
> fs/ext2/super.c | 15 ++++++++++++---
> fs/ext3/super.c | 21 +++++++++++++++------
> fs/ext4/super.c | 21 +++++++++++++++------
> include/linux/percpu_counter.h | 5 +++--
> lib/percpu_counter.c | 8 +++++++-
> 5 files changed, 52 insertions(+), 18 deletions(-)
>
> Index: linux-2.6/fs/ext2/super.c
> ===================================================================
> --- linux-2.6.orig/fs/ext2/super.c
> +++ linux-2.6/fs/ext2/super.c
> @@ -725,6 +725,7 @@ static int ext2_fill_super(struct super_
> int db_count;
> int i, j;
> __le32 features;
> + int err;
>
> sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
> if (!sbi)
> @@ -996,12 +997,20 @@ static int ext2_fill_super(struct super_
> sbi->s_rsv_window_head.rsv_goal_size = 0;
> ext2_rsv_window_add(sb, &sbi->s_rsv_window_head);
>
> - percpu_counter_init(&sbi->s_freeblocks_counter,
> + err = percpu_counter_init(&sbi->s_freeblocks_counter,
> ext2_count_free_blocks(sb));
> - percpu_counter_init(&sbi->s_freeinodes_counter,
> + if (!err) {
> + err = percpu_counter_init(&sbi->s_freeinodes_counter,
> ext2_count_free_inodes(sb));
> - percpu_counter_init(&sbi->s_dirs_counter,
> + }
> + if (!err) {
> + err = percpu_counter_init(&sbi->s_dirs_counter,
> ext2_count_dirs(sb));
> + }
> + if (err) {
> + printk(KERN_ERR "EXT2-fs: insufficient memory\n");
> + goto failed_mount3;
> + }
> /*
> * set up enough so that it can read an inode
> */

I find this more readable as I don't have to try to figure out what the
bitops are doing :)

Jeff.

--
Mankind invented the atomic bomb, but no mouse would ever construct a
mousetrap.
- Albert Einstein