mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-11-01 02:21:16 +00:00
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>
This commit is contained in:
parent
5accdf82ba
commit
eb04c28288
5 changed files with 86 additions and 25 deletions
|
@ -217,7 +217,7 @@ static void drop_file_write_access(struct file *file)
|
||||||
return;
|
return;
|
||||||
if (file_check_writeable(file) != 0)
|
if (file_check_writeable(file) != 0)
|
||||||
return;
|
return;
|
||||||
mnt_drop_write(mnt);
|
__mnt_drop_write(mnt);
|
||||||
file_release_write(file);
|
file_release_write(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1660,11 +1660,11 @@ int file_update_time(struct file *file)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Finally allowed to write? Takes lock. */
|
/* Finally allowed to write? Takes lock. */
|
||||||
if (mnt_want_write_file(file))
|
if (__mnt_want_write_file(file))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = update_time(inode, &now, sync_it);
|
ret = update_time(inode, &now, sync_it);
|
||||||
mnt_drop_write_file(file);
|
__mnt_drop_write_file(file);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,10 @@ extern void __init mnt_init(void);
|
||||||
|
|
||||||
extern struct lglock vfsmount_lock;
|
extern struct lglock vfsmount_lock;
|
||||||
|
|
||||||
|
extern int __mnt_want_write(struct vfsmount *);
|
||||||
|
extern int __mnt_want_write_file(struct file *);
|
||||||
|
extern void __mnt_drop_write(struct vfsmount *);
|
||||||
|
extern void __mnt_drop_write_file(struct file *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fs_struct.c
|
* fs_struct.c
|
||||||
|
|
|
@ -283,24 +283,22 @@ static int mnt_is_readonly(struct vfsmount *mnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Most r/o checks on a fs are for operations that take
|
* Most r/o & frozen checks on a fs are for operations that take discrete
|
||||||
* discrete amounts of time, like a write() or unlink().
|
* amounts of time, like a write() or unlink(). We must keep track of when
|
||||||
* We must keep track of when those operations start
|
* those operations start (for permission checks) and when they end, so that we
|
||||||
* (for permission checks) and when they end, so that
|
* can determine when writes are able to occur to a filesystem.
|
||||||
* we can determine when writes are able to occur to
|
|
||||||
* a filesystem.
|
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* mnt_want_write - get write access to a mount
|
* __mnt_want_write - get write access to a mount without freeze protection
|
||||||
* @m: the mount on which to take a write
|
* @m: the mount on which to take a write
|
||||||
*
|
*
|
||||||
* This tells the low-level filesystem that a write is
|
* This tells the low-level filesystem that a write is about to be performed to
|
||||||
* about to be performed to it, and makes sure that
|
* it, and makes sure that writes are allowed (mnt it read-write) before
|
||||||
* writes are allowed before returning success. When
|
* returning success. This operation does not protect against filesystem being
|
||||||
* the write operation is finished, mnt_drop_write()
|
* frozen. When the write operation is finished, __mnt_drop_write() must be
|
||||||
* must be called. This is effectively a refcount.
|
* called. This is effectively a refcount.
|
||||||
*/
|
*/
|
||||||
int mnt_want_write(struct vfsmount *m)
|
int __mnt_want_write(struct vfsmount *m)
|
||||||
{
|
{
|
||||||
struct mount *mnt = real_mount(m);
|
struct mount *mnt = real_mount(m);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -326,6 +324,27 @@ int mnt_want_write(struct vfsmount *m)
|
||||||
ret = -EROFS;
|
ret = -EROFS;
|
||||||
}
|
}
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mnt_want_write - get write access to a mount
|
||||||
|
* @m: the mount on which to take a write
|
||||||
|
*
|
||||||
|
* This tells the low-level filesystem that a write is about to be performed to
|
||||||
|
* it, and makes sure that writes are allowed (mount is read-write, filesystem
|
||||||
|
* is not frozen) before returning success. When the write operation is
|
||||||
|
* finished, mnt_drop_write() must be called. This is effectively a refcount.
|
||||||
|
*/
|
||||||
|
int mnt_want_write(struct vfsmount *m)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
sb_start_write(m->mnt_sb);
|
||||||
|
ret = __mnt_want_write(m);
|
||||||
|
if (ret)
|
||||||
|
sb_end_write(m->mnt_sb);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mnt_want_write);
|
EXPORT_SYMBOL_GPL(mnt_want_write);
|
||||||
|
@ -354,6 +373,23 @@ int mnt_clone_write(struct vfsmount *mnt)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mnt_clone_write);
|
EXPORT_SYMBOL_GPL(mnt_clone_write);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __mnt_want_write_file - get write access to a file's mount
|
||||||
|
* @file: the file who's mount on which to take a write
|
||||||
|
*
|
||||||
|
* This is like __mnt_want_write, but it takes a file and can
|
||||||
|
* do some optimisations if the file is open for write already
|
||||||
|
*/
|
||||||
|
int __mnt_want_write_file(struct file *file)
|
||||||
|
{
|
||||||
|
struct inode *inode = file->f_dentry->d_inode;
|
||||||
|
|
||||||
|
if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode))
|
||||||
|
return __mnt_want_write(file->f_path.mnt);
|
||||||
|
else
|
||||||
|
return mnt_clone_write(file->f_path.mnt);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mnt_want_write_file - get write access to a file's mount
|
* mnt_want_write_file - get write access to a file's mount
|
||||||
* @file: the file who's mount on which to take a write
|
* @file: the file who's mount on which to take a write
|
||||||
|
@ -363,30 +399,51 @@ EXPORT_SYMBOL_GPL(mnt_clone_write);
|
||||||
*/
|
*/
|
||||||
int mnt_want_write_file(struct file *file)
|
int mnt_want_write_file(struct file *file)
|
||||||
{
|
{
|
||||||
struct inode *inode = file->f_dentry->d_inode;
|
int ret;
|
||||||
if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode))
|
|
||||||
return mnt_want_write(file->f_path.mnt);
|
sb_start_write(file->f_path.mnt->mnt_sb);
|
||||||
else
|
ret = __mnt_want_write_file(file);
|
||||||
return mnt_clone_write(file->f_path.mnt);
|
if (ret)
|
||||||
|
sb_end_write(file->f_path.mnt->mnt_sb);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mnt_want_write_file);
|
EXPORT_SYMBOL_GPL(mnt_want_write_file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mnt_drop_write - give up write access to a mount
|
* __mnt_drop_write - give up write access to a mount
|
||||||
* @mnt: the mount on which to give up write access
|
* @mnt: the mount on which to give up write access
|
||||||
*
|
*
|
||||||
* Tells the low-level filesystem that we are done
|
* Tells the low-level filesystem that we are done
|
||||||
* performing writes to it. Must be matched with
|
* performing writes to it. Must be matched with
|
||||||
* mnt_want_write() call above.
|
* __mnt_want_write() call above.
|
||||||
*/
|
*/
|
||||||
void mnt_drop_write(struct vfsmount *mnt)
|
void __mnt_drop_write(struct vfsmount *mnt)
|
||||||
{
|
{
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
mnt_dec_writers(real_mount(mnt));
|
mnt_dec_writers(real_mount(mnt));
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mnt_drop_write - give up write access to a mount
|
||||||
|
* @mnt: the mount on which to give up write access
|
||||||
|
*
|
||||||
|
* Tells the low-level filesystem that we are done performing writes to it and
|
||||||
|
* also allows filesystem to be frozen again. Must be matched with
|
||||||
|
* mnt_want_write() call above.
|
||||||
|
*/
|
||||||
|
void mnt_drop_write(struct vfsmount *mnt)
|
||||||
|
{
|
||||||
|
__mnt_drop_write(mnt);
|
||||||
|
sb_end_write(mnt->mnt_sb);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL_GPL(mnt_drop_write);
|
EXPORT_SYMBOL_GPL(mnt_drop_write);
|
||||||
|
|
||||||
|
void __mnt_drop_write_file(struct file *file)
|
||||||
|
{
|
||||||
|
__mnt_drop_write(file->f_path.mnt);
|
||||||
|
}
|
||||||
|
|
||||||
void mnt_drop_write_file(struct file *file)
|
void mnt_drop_write_file(struct file *file)
|
||||||
{
|
{
|
||||||
mnt_drop_write(file->f_path.mnt);
|
mnt_drop_write(file->f_path.mnt);
|
||||||
|
|
|
@ -620,7 +620,7 @@ static inline int __get_file_write_access(struct inode *inode,
|
||||||
/*
|
/*
|
||||||
* Balanced in __fput()
|
* Balanced in __fput()
|
||||||
*/
|
*/
|
||||||
error = mnt_want_write(mnt);
|
error = __mnt_want_write(mnt);
|
||||||
if (error)
|
if (error)
|
||||||
put_write_access(inode);
|
put_write_access(inode);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue