aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-06-12 10:20:35 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-07-31 01:40:38 -0400
commiteb04c28288bb0098d0e75d81ba2a575239de71d8 (patch)
tree82912fd7c78be269560a8af7d8516918c279255b /fs
parent5accdf82ba25cacefd6c1867f1704beb4d244cdd (diff)
fs: Add freezing handling to mnt_want_write() / mnt_drop_write()
Most of places where we want freeze protection coincides with the places where we also have remount-ro protection. So make mnt_want_write() and mnt_drop_write() (and their _file alternative) prevent freezing as well. For the few cases that are really interested only in remount-ro protection provide new function variants. BugLink: https://bugs.launchpad.net/bugs/897421 Tested-by: Kamal Mostafa <kamal@canonical.com> Tested-by: Peter M. Petrakis <peter.petrakis@canonical.com> Tested-by: Dann Frazier <dann.frazier@canonical.com> Tested-by: Massimo Morana <massimo.morana@canonical.com> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/file_table.c2
-rw-r--r--fs/inode.c4
-rw-r--r--fs/internal.h4
-rw-r--r--fs/namespace.c97
-rw-r--r--fs/open.c2
5 files changed, 85 insertions, 24 deletions
diff --git a/fs/file_table.c b/fs/file_table.c
index b54bf7fd0b15..701985e4ccda 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -217,7 +217,7 @@ static void drop_file_write_access(struct file *file)
217 return; 217 return;
218 if (file_check_writeable(file) != 0) 218 if (file_check_writeable(file) != 0)
219 return; 219 return;
220 mnt_drop_write(mnt); 220 __mnt_drop_write(mnt);
221 file_release_write(file); 221 file_release_write(file);
222} 222}
223 223
diff --git a/fs/inode.c b/fs/inode.c
index 775cbabd4fa5..006c85ca06eb 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1660,11 +1660,11 @@ int file_update_time(struct file *file)
1660 return 0; 1660 return 0;
1661 1661
1662 /* Finally allowed to write? Takes lock. */ 1662 /* Finally allowed to write? Takes lock. */
1663 if (mnt_want_write_file(file)) 1663 if (__mnt_want_write_file(file))
1664 return 0; 1664 return 0;
1665 1665
1666 ret = update_time(inode, &now, sync_it); 1666 ret = update_time(inode, &now, sync_it);
1667 mnt_drop_write_file(file); 1667 __mnt_drop_write_file(file);
1668 1668
1669 return ret; 1669 return ret;
1670} 1670}
diff --git a/fs/internal.h b/fs/internal.h
index a6fd56c68b11..371bcc4b1697 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -61,6 +61,10 @@ extern void __init mnt_init(void);
61 61
62extern struct lglock vfsmount_lock; 62extern struct lglock vfsmount_lock;
63 63
64extern int __mnt_want_write(struct vfsmount *);
65extern int __mnt_want_write_file(struct file *);
66extern void __mnt_drop_write(struct vfsmount *);
67extern void __mnt_drop_write_file(struct file *);
64 68
65/* 69/*
66 * fs_struct.c 70 * fs_struct.c
diff --git a/fs/namespace.c b/fs/namespace.c
index c53d3381b0d0..4d31f73e2561 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -283,24 +283,22 @@ static int mnt_is_readonly(struct vfsmount *mnt)
283} 283}
284 284
285/* 285/*
286 * Most r/o checks on a fs are for operations that take 286 * Most r/o & frozen checks on a fs are for operations that take discrete
287 * discrete amounts of time, like a write() or unlink(). 287 * amounts of time, like a write() or unlink(). We must keep track of when
288 * We must keep track of when those operations start 288 * those operations start (for permission checks) and when they end, so that we
289 * (for permission checks) and when they end, so that 289 * can determine when writes are able to occur to a filesystem.
290 * we can determine when writes are able to occur to
291 * a filesystem.
292 */ 290 */
293/** 291/**
294 * mnt_want_write - get write access to a mount 292 * __mnt_want_write - get write access to a mount without freeze protection
295 * @m: the mount on which to take a write 293 * @m: the mount on which to take a write
296 * 294 *
297 * This tells the low-level filesystem that a write is 295 * This tells the low-level filesystem that a write is about to be performed to
298 * about to be performed to it, and makes sure that 296 * it, and makes sure that writes are allowed (mnt it read-write) before
299 * writes are allowed before returning success. When 297 * returning success. This operation does not protect against filesystem being
300 * the write operation is finished, mnt_drop_write() 298 * frozen. When the write operation is finished, __mnt_drop_write() must be
301 * must be called. This is effectively a refcount. 299 * called. This is effectively a refcount.
302 */ 300 */
303int mnt_want_write(struct vfsmount *m) 301int __mnt_want_write(struct vfsmount *m)
304{ 302{
305 struct mount *mnt = real_mount(m); 303 struct mount *mnt = real_mount(m);
306 int ret = 0; 304 int ret = 0;
@@ -326,6 +324,27 @@ int mnt_want_write(struct vfsmount *m)
326 ret = -EROFS; 324 ret = -EROFS;
327 } 325 }
328 preempt_enable(); 326 preempt_enable();
327
328 return ret;
329}
330
331/**
332 * mnt_want_write - get write access to a mount
333 * @m: the mount on which to take a write
334 *
335 * This tells the low-level filesystem that a write is about to be performed to
336 * it, and makes sure that writes are allowed (mount is read-write, filesystem
337 * is not frozen) before returning success. When the write operation is
338 * finished, mnt_drop_write() must be called. This is effectively a refcount.
339 */
340int mnt_want_write(struct vfsmount *m)
341{
342 int ret;
343
344 sb_start_write(m->mnt_sb);
345 ret = __mnt_want_write(m);
346 if (ret)
347 sb_end_write(m->mnt_sb);
329 return ret; 348 return ret;
330} 349}
331EXPORT_SYMBOL_GPL(mnt_want_write); 350EXPORT_SYMBOL_GPL(mnt_want_write);
@@ -355,38 +374,76 @@ int mnt_clone_write(struct vfsmount *mnt)
355EXPORT_SYMBOL_GPL(mnt_clone_write); 374EXPORT_SYMBOL_GPL(mnt_clone_write);
356 375
357/** 376/**
358 * mnt_want_write_file - get write access to a file's mount 377 * __mnt_want_write_file - get write access to a file's mount
359 * @file: the file who's mount on which to take a write 378 * @file: the file who's mount on which to take a write
360 * 379 *
361 * This is like mnt_want_write, but it takes a file and can 380 * This is like __mnt_want_write, but it takes a file and can
362 * do some optimisations if the file is open for write already 381 * do some optimisations if the file is open for write already
363 */ 382 */
364int mnt_want_write_file(struct file *file) 383int __mnt_want_write_file(struct file *file)
365{ 384{
366 struct inode *inode = file->f_dentry->d_inode; 385 struct inode *inode = file->f_dentry->d_inode;
386
367 if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode)) 387 if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode))
368 return mnt_want_write(file->f_path.mnt); 388 return __mnt_want_write(file->f_path.mnt);
369 else 389 else
370 return mnt_clone_write(file->f_path.mnt); 390 return mnt_clone_write(file->f_path.mnt);
371} 391}
392
393/**
394 * mnt_want_write_file - get write access to a file's mount
395 * @file: the file who's mount on which to take a write
396 *
397 * This is like mnt_want_write, but it takes a file and can
398 * do some optimisations if the file is open for write already
399 */
400int mnt_want_write_file(struct file *file)
401{
402 int ret;
403
404 sb_start_write(file->f_path.mnt->mnt_sb);
405 ret = __mnt_want_write_file(file);
406 if (ret)
407 sb_end_write(file->f_path.mnt->mnt_sb);
408 return ret;
409}
372EXPORT_SYMBOL_GPL(mnt_want_write_file); 410EXPORT_SYMBOL_GPL(mnt_want_write_file);
373 411
374/** 412/**
375 * mnt_drop_write - give up write access to a mount 413 * __mnt_drop_write - give up write access to a mount
376 * @mnt: the mount on which to give up write access 414 * @mnt: the mount on which to give up write access
377 * 415 *
378 * Tells the low-level filesystem that we are done 416 * Tells the low-level filesystem that we are done
379 * performing writes to it. Must be matched with 417 * performing writes to it. Must be matched with
380 * mnt_want_write() call above. 418 * __mnt_want_write() call above.
381 */ 419 */
382void mnt_drop_write(struct vfsmount *mnt) 420void __mnt_drop_write(struct vfsmount *mnt)
383{ 421{
384 preempt_disable(); 422 preempt_disable();
385 mnt_dec_writers(real_mount(mnt)); 423 mnt_dec_writers(real_mount(mnt));
386 preempt_enable(); 424 preempt_enable();
387} 425}
426
427/**
428 * mnt_drop_write - give up write access to a mount
429 * @mnt: the mount on which to give up write access
430 *
431 * Tells the low-level filesystem that we are done performing writes to it and
432 * also allows filesystem to be frozen again. Must be matched with
433 * mnt_want_write() call above.
434 */
435void mnt_drop_write(struct vfsmount *mnt)
436{
437 __mnt_drop_write(mnt);
438 sb_end_write(mnt->mnt_sb);
439}
388EXPORT_SYMBOL_GPL(mnt_drop_write); 440EXPORT_SYMBOL_GPL(mnt_drop_write);
389 441
442void __mnt_drop_write_file(struct file *file)
443{
444 __mnt_drop_write(file->f_path.mnt);
445}
446
390void mnt_drop_write_file(struct file *file) 447void mnt_drop_write_file(struct file *file)
391{ 448{
392 mnt_drop_write(file->f_path.mnt); 449 mnt_drop_write(file->f_path.mnt);
diff --git a/fs/open.c b/fs/open.c
index 8d2c8970029c..9ddc18565503 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -620,7 +620,7 @@ static inline int __get_file_write_access(struct inode *inode,
620 /* 620 /*
621 * Balanced in __fput() 621 * Balanced in __fput()
622 */ 622 */
623 error = mnt_want_write(mnt); 623 error = __mnt_want_write(mnt);
624 if (error) 624 if (error)
625 put_write_access(inode); 625 put_write_access(inode);
626 } 626 }