Commit ecf7ace9a8450303a987aa8364e53860cd50e554
Committed by
Dave Airlie
1 parent
d6ea88865d
kref: Add a kref_sub function
Makes it possible to optimize batched multiple unrefs. Initial user will be drivers/gpu/ttm which accumulates unrefs to be processed outside of atomic code. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Showing 2 changed files with 32 additions and 0 deletions Inline Diff
include/linux/kref.h
1 | /* | 1 | /* |
2 | * kref.h - library routines for handling generic reference counted objects | 2 | * kref.h - library routines for handling generic reference counted objects |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> | 4 | * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> |
5 | * Copyright (C) 2004 IBM Corp. | 5 | * Copyright (C) 2004 IBM Corp. |
6 | * | 6 | * |
7 | * based on kobject.h which was: | 7 | * based on kobject.h which was: |
8 | * Copyright (C) 2002-2003 Patrick Mochel <mochel@osdl.org> | 8 | * Copyright (C) 2002-2003 Patrick Mochel <mochel@osdl.org> |
9 | * Copyright (C) 2002-2003 Open Source Development Labs | 9 | * Copyright (C) 2002-2003 Open Source Development Labs |
10 | * | 10 | * |
11 | * This file is released under the GPLv2. | 11 | * This file is released under the GPLv2. |
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #ifndef _KREF_H_ | 15 | #ifndef _KREF_H_ |
16 | #define _KREF_H_ | 16 | #define _KREF_H_ |
17 | 17 | ||
18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
19 | 19 | ||
20 | struct kref { | 20 | struct kref { |
21 | atomic_t refcount; | 21 | atomic_t refcount; |
22 | }; | 22 | }; |
23 | 23 | ||
24 | void kref_init(struct kref *kref); | 24 | void kref_init(struct kref *kref); |
25 | void kref_get(struct kref *kref); | 25 | void kref_get(struct kref *kref); |
26 | int kref_put(struct kref *kref, void (*release) (struct kref *kref)); | 26 | int kref_put(struct kref *kref, void (*release) (struct kref *kref)); |
27 | int kref_sub(struct kref *kref, unsigned int count, | ||
28 | void (*release) (struct kref *kref)); | ||
27 | 29 | ||
28 | #endif /* _KREF_H_ */ | 30 | #endif /* _KREF_H_ */ |
29 | 31 |
lib/kref.c
1 | /* | 1 | /* |
2 | * kref.c - library routines for handling generic reference counted objects | 2 | * kref.c - library routines for handling generic reference counted objects |
3 | * | 3 | * |
4 | * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> | 4 | * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> |
5 | * Copyright (C) 2004 IBM Corp. | 5 | * Copyright (C) 2004 IBM Corp. |
6 | * | 6 | * |
7 | * based on lib/kobject.c which was: | 7 | * based on lib/kobject.c which was: |
8 | * Copyright (C) 2002-2003 Patrick Mochel <mochel@osdl.org> | 8 | * Copyright (C) 2002-2003 Patrick Mochel <mochel@osdl.org> |
9 | * | 9 | * |
10 | * This file is released under the GPLv2. | 10 | * This file is released under the GPLv2. |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/kref.h> | 14 | #include <linux/kref.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | 17 | ||
18 | /** | 18 | /** |
19 | * kref_init - initialize object. | 19 | * kref_init - initialize object. |
20 | * @kref: object in question. | 20 | * @kref: object in question. |
21 | */ | 21 | */ |
22 | void kref_init(struct kref *kref) | 22 | void kref_init(struct kref *kref) |
23 | { | 23 | { |
24 | atomic_set(&kref->refcount, 1); | 24 | atomic_set(&kref->refcount, 1); |
25 | smp_mb(); | 25 | smp_mb(); |
26 | } | 26 | } |
27 | 27 | ||
28 | /** | 28 | /** |
29 | * kref_get - increment refcount for object. | 29 | * kref_get - increment refcount for object. |
30 | * @kref: object. | 30 | * @kref: object. |
31 | */ | 31 | */ |
32 | void kref_get(struct kref *kref) | 32 | void kref_get(struct kref *kref) |
33 | { | 33 | { |
34 | WARN_ON(!atomic_read(&kref->refcount)); | 34 | WARN_ON(!atomic_read(&kref->refcount)); |
35 | atomic_inc(&kref->refcount); | 35 | atomic_inc(&kref->refcount); |
36 | smp_mb__after_atomic_inc(); | 36 | smp_mb__after_atomic_inc(); |
37 | } | 37 | } |
38 | 38 | ||
39 | /** | 39 | /** |
40 | * kref_put - decrement refcount for object. | 40 | * kref_put - decrement refcount for object. |
41 | * @kref: object. | 41 | * @kref: object. |
42 | * @release: pointer to the function that will clean up the object when the | 42 | * @release: pointer to the function that will clean up the object when the |
43 | * last reference to the object is released. | 43 | * last reference to the object is released. |
44 | * This pointer is required, and it is not acceptable to pass kfree | 44 | * This pointer is required, and it is not acceptable to pass kfree |
45 | * in as this function. | 45 | * in as this function. |
46 | * | 46 | * |
47 | * Decrement the refcount, and if 0, call release(). | 47 | * Decrement the refcount, and if 0, call release(). |
48 | * Return 1 if the object was removed, otherwise return 0. Beware, if this | 48 | * Return 1 if the object was removed, otherwise return 0. Beware, if this |
49 | * function returns 0, you still can not count on the kref from remaining in | 49 | * function returns 0, you still can not count on the kref from remaining in |
50 | * memory. Only use the return value if you want to see if the kref is now | 50 | * memory. Only use the return value if you want to see if the kref is now |
51 | * gone, not present. | 51 | * gone, not present. |
52 | */ | 52 | */ |
53 | int kref_put(struct kref *kref, void (*release)(struct kref *kref)) | 53 | int kref_put(struct kref *kref, void (*release)(struct kref *kref)) |
54 | { | 54 | { |
55 | WARN_ON(release == NULL); | 55 | WARN_ON(release == NULL); |
56 | WARN_ON(release == (void (*)(struct kref *))kfree); | 56 | WARN_ON(release == (void (*)(struct kref *))kfree); |
57 | 57 | ||
58 | if (atomic_dec_and_test(&kref->refcount)) { | 58 | if (atomic_dec_and_test(&kref->refcount)) { |
59 | release(kref); | 59 | release(kref); |
60 | return 1; | 60 | return 1; |
61 | } | 61 | } |
62 | return 0; | 62 | return 0; |
63 | } | 63 | } |
64 | 64 | ||
65 | |||
66 | /** | ||
67 | * kref_sub - subtract a number of refcounts for object. | ||
68 | * @kref: object. | ||
69 | * @count: Number of recounts to subtract. | ||
70 | * @release: pointer to the function that will clean up the object when the | ||
71 | * last reference to the object is released. | ||
72 | * This pointer is required, and it is not acceptable to pass kfree | ||
73 | * in as this function. | ||
74 | * | ||
75 | * Subtract @count from the refcount, and if 0, call release(). | ||
76 | * Return 1 if the object was removed, otherwise return 0. Beware, if this | ||
77 | * function returns 0, you still can not count on the kref from remaining in | ||
78 | * memory. Only use the return value if you want to see if the kref is now | ||
79 | * gone, not present. | ||
80 | */ | ||
81 | int kref_sub(struct kref *kref, unsigned int count, | ||
82 | void (*release)(struct kref *kref)) | ||
83 | { | ||
84 | WARN_ON(release == NULL); | ||
85 | WARN_ON(release == (void (*)(struct kref *))kfree); | ||
86 | |||
87 | if (atomic_sub_and_test((int) count, &kref->refcount)) { | ||
88 | release(kref); | ||
89 | return 1; | ||
90 | } | ||
91 | return 0; | ||
92 | } | ||
93 | |||
65 | EXPORT_SYMBOL(kref_init); | 94 | EXPORT_SYMBOL(kref_init); |
66 | EXPORT_SYMBOL(kref_get); | 95 | EXPORT_SYMBOL(kref_get); |
67 | EXPORT_SYMBOL(kref_put); | 96 | EXPORT_SYMBOL(kref_put); |
97 | EXPORT_SYMBOL(kref_sub); | ||
68 | 98 |