diff options
-rw-r--r-- | fs/file_table.c | 21 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 3 | ||||
-rw-r--r-- | include/linux/file.h | 1 |
3 files changed, 22 insertions, 3 deletions
diff --git a/fs/file_table.c b/fs/file_table.c index 986ff4ed0a7c..3f73eb1f195a 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
@@ -211,6 +211,23 @@ void fput(struct file *file) | |||
211 | 211 | ||
212 | EXPORT_SYMBOL(fput); | 212 | EXPORT_SYMBOL(fput); |
213 | 213 | ||
214 | /** | ||
215 | * drop_file_write_access - give up ability to write to a file | ||
216 | * @file: the file to which we will stop writing | ||
217 | * | ||
218 | * This is a central place which will give up the ability | ||
219 | * to write to @file, along with access to write through | ||
220 | * its vfsmount. | ||
221 | */ | ||
222 | void drop_file_write_access(struct file *file) | ||
223 | { | ||
224 | struct dentry *dentry = file->f_path.dentry; | ||
225 | struct inode *inode = dentry->d_inode; | ||
226 | |||
227 | put_write_access(inode); | ||
228 | } | ||
229 | EXPORT_SYMBOL_GPL(drop_file_write_access); | ||
230 | |||
214 | /* __fput is called from task context when aio completion releases the last | 231 | /* __fput is called from task context when aio completion releases the last |
215 | * last use of a struct file *. Do not use otherwise. | 232 | * last use of a struct file *. Do not use otherwise. |
216 | */ | 233 | */ |
@@ -236,10 +253,10 @@ void __fput(struct file *file) | |||
236 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) | 253 | if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) |
237 | cdev_put(inode->i_cdev); | 254 | cdev_put(inode->i_cdev); |
238 | fops_put(file->f_op); | 255 | fops_put(file->f_op); |
239 | if (file->f_mode & FMODE_WRITE) | ||
240 | put_write_access(inode); | ||
241 | put_pid(file->f_owner.pid); | 256 | put_pid(file->f_owner.pid); |
242 | file_kill(file); | 257 | file_kill(file); |
258 | if (file->f_mode & FMODE_WRITE) | ||
259 | drop_file_write_access(file); | ||
243 | file->f_path.dentry = NULL; | 260 | file->f_path.dentry = NULL; |
244 | file->f_path.mnt = NULL; | 261 | file->f_path.mnt = NULL; |
245 | file_free(file); | 262 | file_free(file); |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index bcb97d8e8b8b..81a75f3081f4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/sunrpc/svc.h> | 41 | #include <linux/sunrpc/svc.h> |
42 | #include <linux/nfsd/nfsd.h> | 42 | #include <linux/nfsd/nfsd.h> |
43 | #include <linux/nfsd/cache.h> | 43 | #include <linux/nfsd/cache.h> |
44 | #include <linux/file.h> | ||
44 | #include <linux/mount.h> | 45 | #include <linux/mount.h> |
45 | #include <linux/workqueue.h> | 46 | #include <linux/workqueue.h> |
46 | #include <linux/smp_lock.h> | 47 | #include <linux/smp_lock.h> |
@@ -1239,7 +1240,7 @@ static inline void | |||
1239 | nfs4_file_downgrade(struct file *filp, unsigned int share_access) | 1240 | nfs4_file_downgrade(struct file *filp, unsigned int share_access) |
1240 | { | 1241 | { |
1241 | if (share_access & NFS4_SHARE_ACCESS_WRITE) { | 1242 | if (share_access & NFS4_SHARE_ACCESS_WRITE) { |
1242 | put_write_access(filp->f_path.dentry->d_inode); | 1243 | drop_file_write_access(filp); |
1243 | filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE; | 1244 | filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE; |
1244 | } | 1245 | } |
1245 | } | 1246 | } |
diff --git a/include/linux/file.h b/include/linux/file.h index 7239baac81a9..653477021e4c 100644 --- a/include/linux/file.h +++ b/include/linux/file.h | |||
@@ -61,6 +61,7 @@ extern struct kmem_cache *filp_cachep; | |||
61 | 61 | ||
62 | extern void __fput(struct file *); | 62 | extern void __fput(struct file *); |
63 | extern void fput(struct file *); | 63 | extern void fput(struct file *); |
64 | extern void drop_file_write_access(struct file *file); | ||
64 | 65 | ||
65 | struct file_operations; | 66 | struct file_operations; |
66 | struct vfsmount; | 67 | struct vfsmount; |