aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/acct.c85
1 files changed, 52 insertions, 33 deletions
diff --git a/kernel/acct.c b/kernel/acct.c
index 21fbb3c27c2a..6fd375f15626 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -79,9 +79,14 @@ int acct_parm[3] = {4, 2, 30};
79static void do_acct_process(struct bsd_acct_struct *acct); 79static void do_acct_process(struct bsd_acct_struct *acct);
80 80
81struct bsd_acct_struct { 81struct bsd_acct_struct {
82 long count; 82 atomic_long_t count;
83 struct hlist_node s_list; 83 union {
84 struct hlist_node m_list; 84 struct {
85 struct hlist_node s_list;
86 struct hlist_node m_list;
87 };
88 struct rcu_head rcu;
89 };
85 struct mutex lock; 90 struct mutex lock;
86 int active; 91 int active;
87 unsigned long needcheck; 92 unsigned long needcheck;
@@ -89,6 +94,11 @@ struct bsd_acct_struct {
89 struct pid_namespace *ns; 94 struct pid_namespace *ns;
90}; 95};
91 96
97static void acct_free_rcu(struct rcu_head *head)
98{
99 kfree(container_of(head, struct bsd_acct_struct, rcu));
100}
101
92static DEFINE_SPINLOCK(acct_lock); 102static DEFINE_SPINLOCK(acct_lock);
93 103
94/* 104/*
@@ -128,22 +138,22 @@ out:
128 138
129static void acct_put(struct bsd_acct_struct *p) 139static void acct_put(struct bsd_acct_struct *p)
130{ 140{
131 spin_lock(&acct_lock); 141 if (atomic_long_dec_and_test(&p->count))
132 if (!--p->count) 142 call_rcu(&p->rcu, acct_free_rcu);
133 kfree(p);
134 spin_unlock(&acct_lock);
135} 143}
136 144
137static struct bsd_acct_struct *__acct_get(struct bsd_acct_struct *res) 145static struct bsd_acct_struct *__acct_get(struct bsd_acct_struct *res)
138{ 146{
139 res->count++; 147 if (!atomic_long_inc_not_zero(&res->count)) {
140 spin_unlock(&acct_lock); 148 rcu_read_unlock();
149 cpu_relax();
150 return NULL;
151 }
152 rcu_read_unlock();
141 mutex_lock(&res->lock); 153 mutex_lock(&res->lock);
142 if (!res->ns) { 154 if (!res->ns) {
143 mutex_unlock(&res->lock); 155 mutex_unlock(&res->lock);
144 spin_lock(&acct_lock); 156 acct_put(res);
145 if (!--res->count)
146 kfree(res);
147 return NULL; 157 return NULL;
148 } 158 }
149 return res; 159 return res;
@@ -152,13 +162,15 @@ static struct bsd_acct_struct *__acct_get(struct bsd_acct_struct *res)
152static struct bsd_acct_struct *acct_get(struct pid_namespace *ns) 162static struct bsd_acct_struct *acct_get(struct pid_namespace *ns)
153{ 163{
154 struct bsd_acct_struct *res; 164 struct bsd_acct_struct *res;
155 spin_lock(&acct_lock);
156again: 165again:
157 if (!ns->bacct) { 166 smp_rmb();
158 spin_unlock(&acct_lock); 167 rcu_read_lock();
168 res = ACCESS_ONCE(ns->bacct);
169 if (!res) {
170 rcu_read_unlock();
159 return NULL; 171 return NULL;
160 } 172 }
161 res = __acct_get(ns->bacct); 173 res = __acct_get(res);
162 if (!res) 174 if (!res)
163 goto again; 175 goto again;
164 return res; 176 return res;
@@ -170,26 +182,27 @@ static void acct_kill(struct bsd_acct_struct *acct,
170 if (acct) { 182 if (acct) {
171 struct file *file = acct->file; 183 struct file *file = acct->file;
172 struct pid_namespace *ns = acct->ns; 184 struct pid_namespace *ns = acct->ns;
185 do_acct_process(acct);
186 mnt_unpin(file->f_path.mnt);
187 filp_close(file, NULL);
173 spin_lock(&acct_lock); 188 spin_lock(&acct_lock);
174 hlist_del(&acct->m_list); 189 hlist_del(&acct->m_list);
175 hlist_del(&acct->s_list); 190 hlist_del(&acct->s_list);
176 mnt_unpin(file->f_path.mnt);
177 spin_unlock(&acct_lock); 191 spin_unlock(&acct_lock);
178 do_acct_process(acct);
179 filp_close(file, NULL);
180 spin_lock(&acct_lock);
181 ns->bacct = new; 192 ns->bacct = new;
182 if (new) { 193 if (new) {
183 struct vfsmount *m = new->file->f_path.mnt; 194 struct vfsmount *m = new->file->f_path.mnt;
184 mnt_pin(m); 195 mnt_pin(m);
196 spin_lock(&acct_lock);
185 hlist_add_head(&new->s_list, &m->mnt_sb->s_pins); 197 hlist_add_head(&new->s_list, &m->mnt_sb->s_pins);
186 hlist_add_head(&new->m_list, &real_mount(m)->mnt_pins); 198 hlist_add_head(&new->m_list, &real_mount(m)->mnt_pins);
199 spin_unlock(&acct_lock);
200 mutex_unlock(&new->lock);
187 } 201 }
188 acct->ns = NULL; 202 acct->ns = NULL;
203 atomic_long_dec(&acct->count);
189 mutex_unlock(&acct->lock); 204 mutex_unlock(&acct->lock);
190 if (!(acct->count -= 2)) 205 acct_put(acct);
191 kfree(acct);
192 spin_unlock(&acct_lock);
193 } 206 }
194} 207}
195 208
@@ -223,7 +236,7 @@ static int acct_on(struct filename *pathname)
223 return -EIO; 236 return -EIO;
224 } 237 }
225 238
226 acct->count = 1; 239 atomic_long_set(&acct->count, 1);
227 acct->file = file; 240 acct->file = file;
228 acct->needcheck = jiffies; 241 acct->needcheck = jiffies;
229 acct->ns = ns; 242 acct->ns = ns;
@@ -231,15 +244,17 @@ static int acct_on(struct filename *pathname)
231 mnt = file->f_path.mnt; 244 mnt = file->f_path.mnt;
232 245
233 old = acct_get(ns); 246 old = acct_get(ns);
247 mutex_lock_nested(&acct->lock, 1); /* nobody has seen it yet */
234 if (old) { 248 if (old) {
235 acct_kill(old, acct); 249 acct_kill(old, acct);
236 } else { 250 } else {
237 spin_lock(&acct_lock);
238 ns->bacct = acct; 251 ns->bacct = acct;
252 spin_lock(&acct_lock);
239 mnt_pin(mnt); 253 mnt_pin(mnt);
240 hlist_add_head(&acct->s_list, &mnt->mnt_sb->s_pins); 254 hlist_add_head(&acct->s_list, &mnt->mnt_sb->s_pins);
241 hlist_add_head(&acct->m_list, &real_mount(mnt)->mnt_pins); 255 hlist_add_head(&acct->m_list, &real_mount(mnt)->mnt_pins);
242 spin_unlock(&acct_lock); 256 spin_unlock(&acct_lock);
257 mutex_unlock(&acct->lock);
243 } 258 }
244 mntput(mnt); /* it's pinned, now give up active reference */ 259 mntput(mnt); /* it's pinned, now give up active reference */
245 return 0; 260 return 0;
@@ -282,28 +297,32 @@ SYSCALL_DEFINE1(acct, const char __user *, name)
282 297
283void acct_auto_close_mnt(struct hlist_head *list) 298void acct_auto_close_mnt(struct hlist_head *list)
284{ 299{
300 rcu_read_lock();
285 while (1) { 301 while (1) {
286 spin_lock(&acct_lock); 302 struct hlist_node *p = ACCESS_ONCE(list->first);
287 if (!list->first) 303 if (!p)
288 break; 304 break;
289 acct_kill(__acct_get(hlist_entry(list->first, 305 acct_kill(__acct_get(hlist_entry(p,
290 struct bsd_acct_struct, 306 struct bsd_acct_struct,
291 m_list)), NULL); 307 m_list)), NULL);
308 rcu_read_lock();
292 } 309 }
293 spin_unlock(&acct_lock); 310 rcu_read_unlock();
294} 311}
295 312
296void acct_auto_close(struct hlist_head *list) 313void acct_auto_close(struct hlist_head *list)
297{ 314{
315 rcu_read_lock();
298 while (1) { 316 while (1) {
299 spin_lock(&acct_lock); 317 struct hlist_node *p = ACCESS_ONCE(list->first);
300 if (!list->first) 318 if (!p)
301 break; 319 break;
302 acct_kill(__acct_get(hlist_entry(list->first, 320 acct_kill(__acct_get(hlist_entry(p,
303 struct bsd_acct_struct, 321 struct bsd_acct_struct,
304 s_list)), NULL); 322 s_list)), NULL);
323 rcu_read_lock();
305 } 324 }
306 spin_unlock(&acct_lock); 325 rcu_read_unlock();
307} 326}
308 327
309void acct_exit_ns(struct pid_namespace *ns) 328void acct_exit_ns(struct pid_namespace *ns)