aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-06-20 10:52:57 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-07-20 01:43:14 -0400
commit07b8ce1ee87d291ff564c02cf878fae973317a52 (patch)
tree94f07ed2b5d18aef71f1b28193375f88c0c947bc
parentf4d6ff89d8e54b68a4322388d26d518d6133fa4e (diff)
lockless get_write_access/deny_write_access
new helpers: atomic_inc_unless_negative()/atomic_dec_unless_positive() Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namei.c46
-rw-r--r--include/linux/atomic.h26
-rw-r--r--include/linux/fs.h29
3 files changed, 52 insertions, 49 deletions
diff --git a/fs/namei.c b/fs/namei.c
index e04f15ae4b07..d286cbc3f3e5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -341,52 +341,6 @@ ok:
341 return security_inode_exec_permission(inode, flags); 341 return security_inode_exec_permission(inode, flags);
342} 342}
343 343
344/*
345 * get_write_access() gets write permission for a file.
346 * put_write_access() releases this write permission.
347 * This is used for regular files.
348 * We cannot support write (and maybe mmap read-write shared) accesses and
349 * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode
350 * can have the following values:
351 * 0: no writers, no VM_DENYWRITE mappings
352 * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
353 * > 0: (i_writecount) users are writing to the file.
354 *
355 * Normally we operate on that counter with atomic_{inc,dec} and it's safe
356 * except for the cases where we don't hold i_writecount yet. Then we need to
357 * use {get,deny}_write_access() - these functions check the sign and refuse
358 * to do the change if sign is wrong. Exclusion between them is provided by
359 * the inode->i_lock spinlock.
360 */
361
362int get_write_access(struct inode * inode)
363{
364 spin_lock(&inode->i_lock);
365 if (atomic_read(&inode->i_writecount) < 0) {
366 spin_unlock(&inode->i_lock);
367 return -ETXTBSY;
368 }
369 atomic_inc(&inode->i_writecount);
370 spin_unlock(&inode->i_lock);
371
372 return 0;
373}
374
375int deny_write_access(struct file * file)
376{
377 struct inode *inode = file->f_path.dentry->d_inode;
378
379 spin_lock(&inode->i_lock);
380 if (atomic_read(&inode->i_writecount) > 0) {
381 spin_unlock(&inode->i_lock);
382 return -ETXTBSY;
383 }
384 atomic_dec(&inode->i_writecount);
385 spin_unlock(&inode->i_lock);
386
387 return 0;
388}
389
390/** 344/**
391 * path_get - get a reference to a path 345 * path_get - get a reference to a path
392 * @path: path to get the reference to 346 * @path: path to get the reference to
diff --git a/include/linux/atomic.h b/include/linux/atomic.h
index ee456c79b0e6..bc6615d4132b 100644
--- a/include/linux/atomic.h
+++ b/include/linux/atomic.h
@@ -34,6 +34,32 @@ static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint)
34} 34}
35#endif 35#endif
36 36
37#ifndef atomic_inc_unless_negative
38static inline int atomic_inc_unless_negative(atomic_t *p)
39{
40 int v, v1;
41 for (v = 0; v >= 0; v = v1) {
42 v1 = atomic_cmpxchg(p, v, v + 1);
43 if (likely(v1 == v))
44 return 1;
45 }
46 return 0;
47}
48#endif
49
50#ifndef atomic_dec_unless_positive
51static inline int atomic_dec_unless_positive(atomic_t *p)
52{
53 int v, v1;
54 for (v = 0; v <= 0; v = v1) {
55 v1 = atomic_cmpxchg(p, v, v - 1);
56 if (likely(v1 == v))
57 return 1;
58 }
59 return 0;
60}
61#endif
62
37#ifndef CONFIG_ARCH_HAS_ATOMIC_OR 63#ifndef CONFIG_ARCH_HAS_ATOMIC_OR
38static inline void atomic_or(int i, atomic_t *v) 64static inline void atomic_or(int i, atomic_t *v)
39{ 65{
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d04e55586a17..8c84ed930389 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -392,8 +392,8 @@ struct inodes_stat_t {
392#include <linux/semaphore.h> 392#include <linux/semaphore.h>
393#include <linux/fiemap.h> 393#include <linux/fiemap.h>
394#include <linux/rculist_bl.h> 394#include <linux/rculist_bl.h>
395#include <linux/atomic.h>
395 396
396#include <asm/atomic.h>
397#include <asm/byteorder.h> 397#include <asm/byteorder.h>
398 398
399struct export_operations; 399struct export_operations;
@@ -2195,8 +2195,31 @@ static inline bool execute_ok(struct inode *inode)
2195 return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode); 2195 return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode);
2196} 2196}
2197 2197
2198extern int get_write_access(struct inode *); 2198/*
2199extern int deny_write_access(struct file *); 2199 * get_write_access() gets write permission for a file.
2200 * put_write_access() releases this write permission.
2201 * This is used for regular files.
2202 * We cannot support write (and maybe mmap read-write shared) accesses and
2203 * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode
2204 * can have the following values:
2205 * 0: no writers, no VM_DENYWRITE mappings
2206 * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
2207 * > 0: (i_writecount) users are writing to the file.
2208 *
2209 * Normally we operate on that counter with atomic_{inc,dec} and it's safe
2210 * except for the cases where we don't hold i_writecount yet. Then we need to
2211 * use {get,deny}_write_access() - these functions check the sign and refuse
2212 * to do the change if sign is wrong.
2213 */
2214static inline int get_write_access(struct inode *inode)
2215{
2216 return atomic_inc_unless_negative(&inode->i_writecount) ? 0 : -ETXTBSY;
2217}
2218static inline int deny_write_access(struct file *file)
2219{
2220 struct inode *inode = file->f_path.dentry->d_inode;
2221 return atomic_dec_unless_positive(&inode->i_writecount) ? 0 : -ETXTBSY;
2222}
2200static inline void put_write_access(struct inode * inode) 2223static inline void put_write_access(struct inode * inode)
2201{ 2224{
2202 atomic_dec(&inode->i_writecount); 2225 atomic_dec(&inode->i_writecount);