diff options
Diffstat (limited to 'kernel/acct.c')
-rw-r--r-- | kernel/acct.c | 92 |
1 files changed, 62 insertions, 30 deletions
diff --git a/kernel/acct.c b/kernel/acct.c index 2e3f4a47e7d0..6312d6bd43e3 100644 --- a/kernel/acct.c +++ b/kernel/acct.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/jiffies.h> | 54 | #include <linux/jiffies.h> |
55 | #include <linux/times.h> | 55 | #include <linux/times.h> |
56 | #include <linux/syscalls.h> | 56 | #include <linux/syscalls.h> |
57 | #include <linux/mount.h> | ||
57 | #include <asm/uaccess.h> | 58 | #include <asm/uaccess.h> |
58 | #include <asm/div64.h> | 59 | #include <asm/div64.h> |
59 | #include <linux/blkdev.h> /* sector_div */ | 60 | #include <linux/blkdev.h> /* sector_div */ |
@@ -192,6 +193,7 @@ static void acct_file_reopen(struct file *file) | |||
192 | add_timer(&acct_globals.timer); | 193 | add_timer(&acct_globals.timer); |
193 | } | 194 | } |
194 | if (old_acct) { | 195 | if (old_acct) { |
196 | mnt_unpin(old_acct->f_vfsmnt); | ||
195 | spin_unlock(&acct_globals.lock); | 197 | spin_unlock(&acct_globals.lock); |
196 | do_acct_process(0, old_acct); | 198 | do_acct_process(0, old_acct); |
197 | filp_close(old_acct, NULL); | 199 | filp_close(old_acct, NULL); |
@@ -199,6 +201,42 @@ static void acct_file_reopen(struct file *file) | |||
199 | } | 201 | } |
200 | } | 202 | } |
201 | 203 | ||
204 | static int acct_on(char *name) | ||
205 | { | ||
206 | struct file *file; | ||
207 | int error; | ||
208 | |||
209 | /* Difference from BSD - they don't do O_APPEND */ | ||
210 | file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0); | ||
211 | if (IS_ERR(file)) | ||
212 | return PTR_ERR(file); | ||
213 | |||
214 | if (!S_ISREG(file->f_dentry->d_inode->i_mode)) { | ||
215 | filp_close(file, NULL); | ||
216 | return -EACCES; | ||
217 | } | ||
218 | |||
219 | if (!file->f_op->write) { | ||
220 | filp_close(file, NULL); | ||
221 | return -EIO; | ||
222 | } | ||
223 | |||
224 | error = security_acct(file); | ||
225 | if (error) { | ||
226 | filp_close(file, NULL); | ||
227 | return error; | ||
228 | } | ||
229 | |||
230 | spin_lock(&acct_globals.lock); | ||
231 | mnt_pin(file->f_vfsmnt); | ||
232 | acct_file_reopen(file); | ||
233 | spin_unlock(&acct_globals.lock); | ||
234 | |||
235 | mntput(file->f_vfsmnt); /* it's pinned, now give up active reference */ | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
202 | /** | 240 | /** |
203 | * sys_acct - enable/disable process accounting | 241 | * sys_acct - enable/disable process accounting |
204 | * @name: file name for accounting records or NULL to shutdown accounting | 242 | * @name: file name for accounting records or NULL to shutdown accounting |
@@ -212,47 +250,41 @@ static void acct_file_reopen(struct file *file) | |||
212 | */ | 250 | */ |
213 | asmlinkage long sys_acct(const char __user *name) | 251 | asmlinkage long sys_acct(const char __user *name) |
214 | { | 252 | { |
215 | struct file *file = NULL; | ||
216 | char *tmp; | ||
217 | int error; | 253 | int error; |
218 | 254 | ||
219 | if (!capable(CAP_SYS_PACCT)) | 255 | if (!capable(CAP_SYS_PACCT)) |
220 | return -EPERM; | 256 | return -EPERM; |
221 | 257 | ||
222 | if (name) { | 258 | if (name) { |
223 | tmp = getname(name); | 259 | char *tmp = getname(name); |
224 | if (IS_ERR(tmp)) { | 260 | if (IS_ERR(tmp)) |
225 | return (PTR_ERR(tmp)); | 261 | return (PTR_ERR(tmp)); |
226 | } | 262 | error = acct_on(tmp); |
227 | /* Difference from BSD - they don't do O_APPEND */ | ||
228 | file = filp_open(tmp, O_WRONLY|O_APPEND|O_LARGEFILE, 0); | ||
229 | putname(tmp); | 263 | putname(tmp); |
230 | if (IS_ERR(file)) { | 264 | } else { |
231 | return (PTR_ERR(file)); | 265 | error = security_acct(NULL); |
232 | } | 266 | if (!error) { |
233 | if (!S_ISREG(file->f_dentry->d_inode->i_mode)) { | 267 | spin_lock(&acct_globals.lock); |
234 | filp_close(file, NULL); | 268 | acct_file_reopen(NULL); |
235 | return (-EACCES); | 269 | spin_unlock(&acct_globals.lock); |
236 | } | ||
237 | |||
238 | if (!file->f_op->write) { | ||
239 | filp_close(file, NULL); | ||
240 | return (-EIO); | ||
241 | } | 270 | } |
242 | } | 271 | } |
272 | return error; | ||
273 | } | ||
243 | 274 | ||
244 | error = security_acct(file); | 275 | /** |
245 | if (error) { | 276 | * acct_auto_close - turn off a filesystem's accounting if it is on |
246 | if (file) | 277 | * @m: vfsmount being shut down |
247 | filp_close(file, NULL); | 278 | * |
248 | return error; | 279 | * If the accounting is turned on for a file in the subtree pointed to |
249 | } | 280 | * to by m, turn accounting off. Done when m is about to die. |
250 | 281 | */ | |
282 | void acct_auto_close_mnt(struct vfsmount *m) | ||
283 | { | ||
251 | spin_lock(&acct_globals.lock); | 284 | spin_lock(&acct_globals.lock); |
252 | acct_file_reopen(file); | 285 | if (acct_globals.file && acct_globals.file->f_vfsmnt == m) |
286 | acct_file_reopen(NULL); | ||
253 | spin_unlock(&acct_globals.lock); | 287 | spin_unlock(&acct_globals.lock); |
254 | |||
255 | return (0); | ||
256 | } | 288 | } |
257 | 289 | ||
258 | /** | 290 | /** |
@@ -266,8 +298,8 @@ void acct_auto_close(struct super_block *sb) | |||
266 | { | 298 | { |
267 | spin_lock(&acct_globals.lock); | 299 | spin_lock(&acct_globals.lock); |
268 | if (acct_globals.file && | 300 | if (acct_globals.file && |
269 | acct_globals.file->f_dentry->d_inode->i_sb == sb) { | 301 | acct_globals.file->f_vfsmnt->mnt_sb == sb) { |
270 | acct_file_reopen((struct file *)NULL); | 302 | acct_file_reopen(NULL); |
271 | } | 303 | } |
272 | spin_unlock(&acct_globals.lock); | 304 | spin_unlock(&acct_globals.lock); |
273 | } | 305 | } |