diff options
-rw-r--r-- | fs/dquot.c | 18 | ||||
-rw-r--r-- | fs/namespace.c | 64 | ||||
-rw-r--r-- | fs/super.c | 1 | ||||
-rw-r--r-- | include/linux/acct.h | 3 | ||||
-rw-r--r-- | include/linux/mount.h | 13 | ||||
-rw-r--r-- | include/linux/quota.h | 1 | ||||
-rw-r--r-- | kernel/acct.c | 92 |
7 files changed, 113 insertions, 79 deletions
diff --git a/fs/dquot.c b/fs/dquot.c index afa06a893468..05b60283c9c2 100644 --- a/fs/dquot.c +++ b/fs/dquot.c | |||
@@ -1321,13 +1321,11 @@ int vfs_quota_off(struct super_block *sb, int type) | |||
1321 | int cnt; | 1321 | int cnt; |
1322 | struct quota_info *dqopt = sb_dqopt(sb); | 1322 | struct quota_info *dqopt = sb_dqopt(sb); |
1323 | struct inode *toputinode[MAXQUOTAS]; | 1323 | struct inode *toputinode[MAXQUOTAS]; |
1324 | struct vfsmount *toputmnt[MAXQUOTAS]; | ||
1325 | 1324 | ||
1326 | /* We need to serialize quota_off() for device */ | 1325 | /* We need to serialize quota_off() for device */ |
1327 | down(&dqopt->dqonoff_sem); | 1326 | down(&dqopt->dqonoff_sem); |
1328 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | 1327 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { |
1329 | toputinode[cnt] = NULL; | 1328 | toputinode[cnt] = NULL; |
1330 | toputmnt[cnt] = NULL; | ||
1331 | if (type != -1 && cnt != type) | 1329 | if (type != -1 && cnt != type) |
1332 | continue; | 1330 | continue; |
1333 | if (!sb_has_quota_enabled(sb, cnt)) | 1331 | if (!sb_has_quota_enabled(sb, cnt)) |
@@ -1348,9 +1346,7 @@ int vfs_quota_off(struct super_block *sb, int type) | |||
1348 | put_quota_format(dqopt->info[cnt].dqi_format); | 1346 | put_quota_format(dqopt->info[cnt].dqi_format); |
1349 | 1347 | ||
1350 | toputinode[cnt] = dqopt->files[cnt]; | 1348 | toputinode[cnt] = dqopt->files[cnt]; |
1351 | toputmnt[cnt] = dqopt->mnt[cnt]; | ||
1352 | dqopt->files[cnt] = NULL; | 1349 | dqopt->files[cnt] = NULL; |
1353 | dqopt->mnt[cnt] = NULL; | ||
1354 | dqopt->info[cnt].dqi_flags = 0; | 1350 | dqopt->info[cnt].dqi_flags = 0; |
1355 | dqopt->info[cnt].dqi_igrace = 0; | 1351 | dqopt->info[cnt].dqi_igrace = 0; |
1356 | dqopt->info[cnt].dqi_bgrace = 0; | 1352 | dqopt->info[cnt].dqi_bgrace = 0; |
@@ -1358,10 +1354,7 @@ int vfs_quota_off(struct super_block *sb, int type) | |||
1358 | } | 1354 | } |
1359 | up(&dqopt->dqonoff_sem); | 1355 | up(&dqopt->dqonoff_sem); |
1360 | /* Sync the superblock so that buffers with quota data are written to | 1356 | /* Sync the superblock so that buffers with quota data are written to |
1361 | * disk (and so userspace sees correct data afterwards). | 1357 | * disk (and so userspace sees correct data afterwards). */ |
1362 | * The reference to vfsmnt we are still holding protects us from | ||
1363 | * umount (we don't have it only when quotas are turned on/off for | ||
1364 | * journal replay but in that case we are guarded by the fs anyway). */ | ||
1365 | if (sb->s_op->sync_fs) | 1358 | if (sb->s_op->sync_fs) |
1366 | sb->s_op->sync_fs(sb, 1); | 1359 | sb->s_op->sync_fs(sb, 1); |
1367 | sync_blockdev(sb->s_bdev); | 1360 | sync_blockdev(sb->s_bdev); |
@@ -1385,10 +1378,6 @@ int vfs_quota_off(struct super_block *sb, int type) | |||
1385 | iput(toputinode[cnt]); | 1378 | iput(toputinode[cnt]); |
1386 | } | 1379 | } |
1387 | up(&dqopt->dqonoff_sem); | 1380 | up(&dqopt->dqonoff_sem); |
1388 | /* We don't hold the reference when we turned on quotas | ||
1389 | * just for the journal replay... */ | ||
1390 | if (toputmnt[cnt]) | ||
1391 | mntput(toputmnt[cnt]); | ||
1392 | } | 1381 | } |
1393 | if (sb->s_bdev) | 1382 | if (sb->s_bdev) |
1394 | invalidate_bdev(sb->s_bdev, 0); | 1383 | invalidate_bdev(sb->s_bdev, 0); |
@@ -1503,11 +1492,8 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) | |||
1503 | /* Quota file not on the same filesystem? */ | 1492 | /* Quota file not on the same filesystem? */ |
1504 | if (nd.mnt->mnt_sb != sb) | 1493 | if (nd.mnt->mnt_sb != sb) |
1505 | error = -EXDEV; | 1494 | error = -EXDEV; |
1506 | else { | 1495 | else |
1507 | error = vfs_quota_on_inode(nd.dentry->d_inode, type, format_id); | 1496 | error = vfs_quota_on_inode(nd.dentry->d_inode, type, format_id); |
1508 | if (!error) | ||
1509 | sb_dqopt(sb)->mnt[type] = mntget(nd.mnt); | ||
1510 | } | ||
1511 | out_path: | 1497 | out_path: |
1512 | path_release(&nd); | 1498 | path_release(&nd); |
1513 | return error; | 1499 | return error; |
diff --git a/fs/namespace.c b/fs/namespace.c index 2fa9fdf7d6f5..1d83302f30c3 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -172,7 +172,7 @@ clone_mnt(struct vfsmount *old, struct dentry *root) | |||
172 | return mnt; | 172 | return mnt; |
173 | } | 173 | } |
174 | 174 | ||
175 | void __mntput(struct vfsmount *mnt) | 175 | static inline void __mntput(struct vfsmount *mnt) |
176 | { | 176 | { |
177 | struct super_block *sb = mnt->mnt_sb; | 177 | struct super_block *sb = mnt->mnt_sb; |
178 | dput(mnt->mnt_root); | 178 | dput(mnt->mnt_root); |
@@ -180,7 +180,46 @@ void __mntput(struct vfsmount *mnt) | |||
180 | deactivate_super(sb); | 180 | deactivate_super(sb); |
181 | } | 181 | } |
182 | 182 | ||
183 | EXPORT_SYMBOL(__mntput); | 183 | void mntput_no_expire(struct vfsmount *mnt) |
184 | { | ||
185 | repeat: | ||
186 | if (atomic_dec_and_lock(&mnt->mnt_count, &vfsmount_lock)) { | ||
187 | if (likely(!mnt->mnt_pinned)) { | ||
188 | spin_unlock(&vfsmount_lock); | ||
189 | __mntput(mnt); | ||
190 | return; | ||
191 | } | ||
192 | atomic_add(mnt->mnt_pinned + 1, &mnt->mnt_count); | ||
193 | mnt->mnt_pinned = 0; | ||
194 | spin_unlock(&vfsmount_lock); | ||
195 | acct_auto_close_mnt(mnt); | ||
196 | security_sb_umount_close(mnt); | ||
197 | goto repeat; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | EXPORT_SYMBOL(mntput_no_expire); | ||
202 | |||
203 | void mnt_pin(struct vfsmount *mnt) | ||
204 | { | ||
205 | spin_lock(&vfsmount_lock); | ||
206 | mnt->mnt_pinned++; | ||
207 | spin_unlock(&vfsmount_lock); | ||
208 | } | ||
209 | |||
210 | EXPORT_SYMBOL(mnt_pin); | ||
211 | |||
212 | void mnt_unpin(struct vfsmount *mnt) | ||
213 | { | ||
214 | spin_lock(&vfsmount_lock); | ||
215 | if (mnt->mnt_pinned) { | ||
216 | atomic_inc(&mnt->mnt_count); | ||
217 | mnt->mnt_pinned--; | ||
218 | } | ||
219 | spin_unlock(&vfsmount_lock); | ||
220 | } | ||
221 | |||
222 | EXPORT_SYMBOL(mnt_unpin); | ||
184 | 223 | ||
185 | /* iterator */ | 224 | /* iterator */ |
186 | static void *m_start(struct seq_file *m, loff_t *pos) | 225 | static void *m_start(struct seq_file *m, loff_t *pos) |
@@ -435,16 +474,6 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
435 | down_write(¤t->namespace->sem); | 474 | down_write(¤t->namespace->sem); |
436 | spin_lock(&vfsmount_lock); | 475 | spin_lock(&vfsmount_lock); |
437 | 476 | ||
438 | if (atomic_read(&sb->s_active) == 1) { | ||
439 | /* last instance - try to be smart */ | ||
440 | spin_unlock(&vfsmount_lock); | ||
441 | lock_kernel(); | ||
442 | DQUOT_OFF(sb); | ||
443 | acct_auto_close(sb); | ||
444 | unlock_kernel(); | ||
445 | security_sb_umount_close(mnt); | ||
446 | spin_lock(&vfsmount_lock); | ||
447 | } | ||
448 | retval = -EBUSY; | 477 | retval = -EBUSY; |
449 | if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { | 478 | if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { |
450 | if (!list_empty(&mnt->mnt_list)) | 479 | if (!list_empty(&mnt->mnt_list)) |
@@ -850,17 +879,6 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts) | |||
850 | detach_mnt(mnt, &old_nd); | 879 | detach_mnt(mnt, &old_nd); |
851 | spin_unlock(&vfsmount_lock); | 880 | spin_unlock(&vfsmount_lock); |
852 | path_release(&old_nd); | 881 | path_release(&old_nd); |
853 | |||
854 | /* | ||
855 | * Now lay it to rest if this was the last ref on the superblock | ||
856 | */ | ||
857 | if (atomic_read(&mnt->mnt_sb->s_active) == 1) { | ||
858 | /* last instance - try to be smart */ | ||
859 | lock_kernel(); | ||
860 | DQUOT_OFF(mnt->mnt_sb); | ||
861 | acct_auto_close(mnt->mnt_sb); | ||
862 | unlock_kernel(); | ||
863 | } | ||
864 | mntput(mnt); | 882 | mntput(mnt); |
865 | } else { | 883 | } else { |
866 | /* | 884 | /* |
diff --git a/fs/super.c b/fs/super.c index eed6c3132905..6689dded3c84 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -171,6 +171,7 @@ void deactivate_super(struct super_block *s) | |||
171 | if (atomic_dec_and_lock(&s->s_active, &sb_lock)) { | 171 | if (atomic_dec_and_lock(&s->s_active, &sb_lock)) { |
172 | s->s_count -= S_BIAS-1; | 172 | s->s_count -= S_BIAS-1; |
173 | spin_unlock(&sb_lock); | 173 | spin_unlock(&sb_lock); |
174 | DQUOT_OFF(s); | ||
174 | down_write(&s->s_umount); | 175 | down_write(&s->s_umount); |
175 | fs->kill_sb(s); | 176 | fs->kill_sb(s); |
176 | put_filesystem(fs); | 177 | put_filesystem(fs); |
diff --git a/include/linux/acct.h b/include/linux/acct.h index 19f70462b3be..93c5b3cdf951 100644 --- a/include/linux/acct.h +++ b/include/linux/acct.h | |||
@@ -117,12 +117,15 @@ struct acct_v3 | |||
117 | #include <linux/config.h> | 117 | #include <linux/config.h> |
118 | 118 | ||
119 | #ifdef CONFIG_BSD_PROCESS_ACCT | 119 | #ifdef CONFIG_BSD_PROCESS_ACCT |
120 | struct vfsmount; | ||
120 | struct super_block; | 121 | struct super_block; |
122 | extern void acct_auto_close_mnt(struct vfsmount *m); | ||
121 | extern void acct_auto_close(struct super_block *sb); | 123 | extern void acct_auto_close(struct super_block *sb); |
122 | extern void acct_process(long exitcode); | 124 | extern void acct_process(long exitcode); |
123 | extern void acct_update_integrals(struct task_struct *tsk); | 125 | extern void acct_update_integrals(struct task_struct *tsk); |
124 | extern void acct_clear_integrals(struct task_struct *tsk); | 126 | extern void acct_clear_integrals(struct task_struct *tsk); |
125 | #else | 127 | #else |
128 | #define acct_auto_close_mnt(x) do { } while (0) | ||
126 | #define acct_auto_close(x) do { } while (0) | 129 | #define acct_auto_close(x) do { } while (0) |
127 | #define acct_process(x) do { } while (0) | 130 | #define acct_process(x) do { } while (0) |
128 | #define acct_update_integrals(x) do { } while (0) | 131 | #define acct_update_integrals(x) do { } while (0) |
diff --git a/include/linux/mount.h b/include/linux/mount.h index f8f39937e301..ffb0b5089880 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h | |||
@@ -37,6 +37,7 @@ struct vfsmount | |||
37 | struct list_head mnt_list; | 37 | struct list_head mnt_list; |
38 | struct list_head mnt_expire; /* link in fs-specific expiry list */ | 38 | struct list_head mnt_expire; /* link in fs-specific expiry list */ |
39 | struct namespace *mnt_namespace; /* containing namespace */ | 39 | struct namespace *mnt_namespace; /* containing namespace */ |
40 | int mnt_pinned; | ||
40 | }; | 41 | }; |
41 | 42 | ||
42 | static inline struct vfsmount *mntget(struct vfsmount *mnt) | 43 | static inline struct vfsmount *mntget(struct vfsmount *mnt) |
@@ -46,15 +47,9 @@ static inline struct vfsmount *mntget(struct vfsmount *mnt) | |||
46 | return mnt; | 47 | return mnt; |
47 | } | 48 | } |
48 | 49 | ||
49 | extern void __mntput(struct vfsmount *mnt); | 50 | extern void mntput_no_expire(struct vfsmount *mnt); |
50 | 51 | extern void mnt_pin(struct vfsmount *mnt); | |
51 | static inline void mntput_no_expire(struct vfsmount *mnt) | 52 | extern void mnt_unpin(struct vfsmount *mnt); |
52 | { | ||
53 | if (mnt) { | ||
54 | if (atomic_dec_and_test(&mnt->mnt_count)) | ||
55 | __mntput(mnt); | ||
56 | } | ||
57 | } | ||
58 | 53 | ||
59 | static inline void mntput(struct vfsmount *mnt) | 54 | static inline void mntput(struct vfsmount *mnt) |
60 | { | 55 | { |
diff --git a/include/linux/quota.h b/include/linux/quota.h index 700ead45084f..f33aeb22c26a 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h | |||
@@ -289,7 +289,6 @@ struct quota_info { | |||
289 | struct semaphore dqonoff_sem; /* Serialize quotaon & quotaoff */ | 289 | struct semaphore dqonoff_sem; /* Serialize quotaon & quotaoff */ |
290 | struct rw_semaphore dqptr_sem; /* serialize ops using quota_info struct, pointers from inode to dquots */ | 290 | struct rw_semaphore dqptr_sem; /* serialize ops using quota_info struct, pointers from inode to dquots */ |
291 | struct inode *files[MAXQUOTAS]; /* inodes of quotafiles */ | 291 | struct inode *files[MAXQUOTAS]; /* inodes of quotafiles */ |
292 | struct vfsmount *mnt[MAXQUOTAS]; /* mountpoint entries of filesystems with quota files */ | ||
293 | struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ | 292 | struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ |
294 | struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ | 293 | struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ |
295 | }; | 294 | }; |
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 | } |