summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2018-08-22 00:55:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-22 13:52:46 -0400
commite58dd0de5eadf145895b13451a1fef8ef03946eb (patch)
treef5db856cd6e69abf35e136e8c2666469ac6b51d3
parentcedc5b6aab493f6b1b1d381dccc0cc082da7d3d8 (diff)
bdi: use refcount_t for reference counting instead atomic_t
refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This permits avoiding accidental refcounter overflows that might lead to use-after-free situations. Link: http://lkml.kernel.org/r/20180703200141.28415-4-bigeasy@linutronix.de Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Reviewed-by: Andrew Morton <akpm@linux-foundation.org> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Suggested-by: Peter Zijlstra <peterz@infradead.org> Cc: Jens Axboe <axboe@kernel.dk> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/backing-dev-defs.h3
-rw-r--r--include/linux/backing-dev.h4
-rw-r--r--mm/backing-dev.c12
3 files changed, 10 insertions, 9 deletions
diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h
index 24251762c20c..9a6bc0951cfa 100644
--- a/include/linux/backing-dev-defs.h
+++ b/include/linux/backing-dev-defs.h
@@ -12,6 +12,7 @@
12#include <linux/timer.h> 12#include <linux/timer.h>
13#include <linux/workqueue.h> 13#include <linux/workqueue.h>
14#include <linux/kref.h> 14#include <linux/kref.h>
15#include <linux/refcount.h>
15 16
16struct page; 17struct page;
17struct device; 18struct device;
@@ -75,7 +76,7 @@ enum wb_reason {
75 */ 76 */
76struct bdi_writeback_congested { 77struct bdi_writeback_congested {
77 unsigned long state; /* WB_[a]sync_congested flags */ 78 unsigned long state; /* WB_[a]sync_congested flags */
78 atomic_t refcnt; /* nr of attached wb's and blkg */ 79 refcount_t refcnt; /* nr of attached wb's and blkg */
79 80
80#ifdef CONFIG_CGROUP_WRITEBACK 81#ifdef CONFIG_CGROUP_WRITEBACK
81 struct backing_dev_info *__bdi; /* the associated bdi, set to NULL 82 struct backing_dev_info *__bdi; /* the associated bdi, set to NULL
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 72ca0f3d39f3..c28a47cbe355 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -404,13 +404,13 @@ static inline bool inode_cgwb_enabled(struct inode *inode)
404static inline struct bdi_writeback_congested * 404static inline struct bdi_writeback_congested *
405wb_congested_get_create(struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp) 405wb_congested_get_create(struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp)
406{ 406{
407 atomic_inc(&bdi->wb_congested->refcnt); 407 refcount_inc(&bdi->wb_congested->refcnt);
408 return bdi->wb_congested; 408 return bdi->wb_congested;
409} 409}
410 410
411static inline void wb_congested_put(struct bdi_writeback_congested *congested) 411static inline void wb_congested_put(struct bdi_writeback_congested *congested)
412{ 412{
413 if (atomic_dec_and_test(&congested->refcnt)) 413 if (refcount_dec_and_test(&congested->refcnt))
414 kfree(congested); 414 kfree(congested);
415} 415}
416 416
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 2e5d3df0853d..55a233d75f39 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -438,10 +438,10 @@ retry:
438 if (new_congested) { 438 if (new_congested) {
439 /* !found and storage for new one already allocated, insert */ 439 /* !found and storage for new one already allocated, insert */
440 congested = new_congested; 440 congested = new_congested;
441 new_congested = NULL;
442 rb_link_node(&congested->rb_node, parent, node); 441 rb_link_node(&congested->rb_node, parent, node);
443 rb_insert_color(&congested->rb_node, &bdi->cgwb_congested_tree); 442 rb_insert_color(&congested->rb_node, &bdi->cgwb_congested_tree);
444 goto found; 443 spin_unlock_irqrestore(&cgwb_lock, flags);
444 return congested;
445 } 445 }
446 446
447 spin_unlock_irqrestore(&cgwb_lock, flags); 447 spin_unlock_irqrestore(&cgwb_lock, flags);
@@ -451,13 +451,13 @@ retry:
451 if (!new_congested) 451 if (!new_congested)
452 return NULL; 452 return NULL;
453 453
454 atomic_set(&new_congested->refcnt, 0); 454 refcount_set(&new_congested->refcnt, 1);
455 new_congested->__bdi = bdi; 455 new_congested->__bdi = bdi;
456 new_congested->blkcg_id = blkcg_id; 456 new_congested->blkcg_id = blkcg_id;
457 goto retry; 457 goto retry;
458 458
459found: 459found:
460 atomic_inc(&congested->refcnt); 460 refcount_inc(&congested->refcnt);
461 spin_unlock_irqrestore(&cgwb_lock, flags); 461 spin_unlock_irqrestore(&cgwb_lock, flags);
462 kfree(new_congested); 462 kfree(new_congested);
463 return congested; 463 return congested;
@@ -474,7 +474,7 @@ void wb_congested_put(struct bdi_writeback_congested *congested)
474 unsigned long flags; 474 unsigned long flags;
475 475
476 local_irq_save(flags); 476 local_irq_save(flags);
477 if (!atomic_dec_and_lock(&congested->refcnt, &cgwb_lock)) { 477 if (!refcount_dec_and_lock(&congested->refcnt, &cgwb_lock)) {
478 local_irq_restore(flags); 478 local_irq_restore(flags);
479 return; 479 return;
480 } 480 }
@@ -804,7 +804,7 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi)
804 if (!bdi->wb_congested) 804 if (!bdi->wb_congested)
805 return -ENOMEM; 805 return -ENOMEM;
806 806
807 atomic_set(&bdi->wb_congested->refcnt, 1); 807 refcount_set(&bdi->wb_congested->refcnt, 1);
808 808
809 err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); 809 err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
810 if (err) { 810 if (err) {