Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Sebastian Andrzej Siewior and committed by
Linus Torvalds
e58dd0de cedc5b6a

+10 -9
+2 -1
include/linux/backing-dev-defs.h
··· 12 12 #include <linux/timer.h> 13 13 #include <linux/workqueue.h> 14 14 #include <linux/kref.h> 15 + #include <linux/refcount.h> 15 16 16 17 struct page; 17 18 struct device; ··· 76 75 */ 77 76 struct bdi_writeback_congested { 78 77 unsigned long state; /* WB_[a]sync_congested flags */ 79 - atomic_t refcnt; /* nr of attached wb's and blkg */ 78 + refcount_t refcnt; /* nr of attached wb's and blkg */ 80 79 81 80 #ifdef CONFIG_CGROUP_WRITEBACK 82 81 struct backing_dev_info *__bdi; /* the associated bdi, set to NULL
+2 -2
include/linux/backing-dev.h
··· 404 404 static inline struct bdi_writeback_congested * 405 405 wb_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 408 return bdi->wb_congested; 409 409 } 410 410 411 411 static 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 414 kfree(congested); 415 415 } 416 416
+6 -6
mm/backing-dev.c
··· 438 438 if (new_congested) { 439 439 /* !found and storage for new one already allocated, insert */ 440 440 congested = new_congested; 441 - new_congested = NULL; 442 441 rb_link_node(&congested->rb_node, parent, node); 443 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 447 spin_unlock_irqrestore(&cgwb_lock, flags); ··· 451 451 if (!new_congested) 452 452 return NULL; 453 453 454 - atomic_set(&new_congested->refcnt, 0); 454 + refcount_set(&new_congested->refcnt, 1); 455 455 new_congested->__bdi = bdi; 456 456 new_congested->blkcg_id = blkcg_id; 457 457 goto retry; 458 458 459 459 found: 460 - atomic_inc(&congested->refcnt); 460 + refcount_inc(&congested->refcnt); 461 461 spin_unlock_irqrestore(&cgwb_lock, flags); 462 462 kfree(new_congested); 463 463 return congested; ··· 474 474 unsigned long flags; 475 475 476 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 478 local_irq_restore(flags); 479 479 return; 480 480 } ··· 804 804 if (!bdi->wb_congested) 805 805 return -ENOMEM; 806 806 807 - atomic_set(&bdi->wb_congested->refcnt, 1); 807 + refcount_set(&bdi->wb_congested->refcnt, 1); 808 808 809 809 err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); 810 810 if (err) {