diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-06-20 10:52:57 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-20 01:43:14 -0400 |
commit | 07b8ce1ee87d291ff564c02cf878fae973317a52 (patch) | |
tree | 94f07ed2b5d18aef71f1b28193375f88c0c947bc | |
parent | f4d6ff89d8e54b68a4322388d26d518d6133fa4e (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.c | 46 | ||||
-rw-r--r-- | include/linux/atomic.h | 26 | ||||
-rw-r--r-- | include/linux/fs.h | 29 |
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 | |||
362 | int 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 | |||
375 | int 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 | ||
38 | static 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 | ||
51 | static 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 |
38 | static inline void atomic_or(int i, atomic_t *v) | 64 | static 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 | ||
399 | struct export_operations; | 399 | struct 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 | ||
2198 | extern int get_write_access(struct inode *); | 2198 | /* |
2199 | extern 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 | */ | ||
2214 | static inline int get_write_access(struct inode *inode) | ||
2215 | { | ||
2216 | return atomic_inc_unless_negative(&inode->i_writecount) ? 0 : -ETXTBSY; | ||
2217 | } | ||
2218 | static 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 | } | ||
2200 | static inline void put_write_access(struct inode * inode) | 2223 | static inline void put_write_access(struct inode * inode) |
2201 | { | 2224 | { |
2202 | atomic_dec(&inode->i_writecount); | 2225 | atomic_dec(&inode->i_writecount); |