mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-12 08:09:56 +00:00
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>
This commit is contained in:
parent
f4d6ff89d8
commit
07b8ce1ee8
46
fs/namei.c
46
fs/namei.c
@ -341,52 +341,6 @@ ok:
|
|||||||
return security_inode_exec_permission(inode, flags);
|
return security_inode_exec_permission(inode, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* get_write_access() gets write permission for a file.
|
|
||||||
* put_write_access() releases this write permission.
|
|
||||||
* This is used for regular files.
|
|
||||||
* We cannot support write (and maybe mmap read-write shared) accesses and
|
|
||||||
* MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode
|
|
||||||
* can have the following values:
|
|
||||||
* 0: no writers, no VM_DENYWRITE mappings
|
|
||||||
* < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
|
|
||||||
* > 0: (i_writecount) users are writing to the file.
|
|
||||||
*
|
|
||||||
* Normally we operate on that counter with atomic_{inc,dec} and it's safe
|
|
||||||
* except for the cases where we don't hold i_writecount yet. Then we need to
|
|
||||||
* use {get,deny}_write_access() - these functions check the sign and refuse
|
|
||||||
* to do the change if sign is wrong. Exclusion between them is provided by
|
|
||||||
* the inode->i_lock spinlock.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int get_write_access(struct inode * inode)
|
|
||||||
{
|
|
||||||
spin_lock(&inode->i_lock);
|
|
||||||
if (atomic_read(&inode->i_writecount) < 0) {
|
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
return -ETXTBSY;
|
|
||||||
}
|
|
||||||
atomic_inc(&inode->i_writecount);
|
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int deny_write_access(struct file * file)
|
|
||||||
{
|
|
||||||
struct inode *inode = file->f_path.dentry->d_inode;
|
|
||||||
|
|
||||||
spin_lock(&inode->i_lock);
|
|
||||||
if (atomic_read(&inode->i_writecount) > 0) {
|
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
return -ETXTBSY;
|
|
||||||
}
|
|
||||||
atomic_dec(&inode->i_writecount);
|
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_get - get a reference to a path
|
* path_get - get a reference to a path
|
||||||
* @path: path to get the reference to
|
* @path: path to get the reference to
|
||||||
|
@ -34,6 +34,32 @@ static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef atomic_inc_unless_negative
|
||||||
|
static inline int atomic_inc_unless_negative(atomic_t *p)
|
||||||
|
{
|
||||||
|
int v, v1;
|
||||||
|
for (v = 0; v >= 0; v = v1) {
|
||||||
|
v1 = atomic_cmpxchg(p, v, v + 1);
|
||||||
|
if (likely(v1 == v))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef atomic_dec_unless_positive
|
||||||
|
static inline int atomic_dec_unless_positive(atomic_t *p)
|
||||||
|
{
|
||||||
|
int v, v1;
|
||||||
|
for (v = 0; v <= 0; v = v1) {
|
||||||
|
v1 = atomic_cmpxchg(p, v, v - 1);
|
||||||
|
if (likely(v1 == v))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_ARCH_HAS_ATOMIC_OR
|
#ifndef CONFIG_ARCH_HAS_ATOMIC_OR
|
||||||
static inline void atomic_or(int i, atomic_t *v)
|
static inline void atomic_or(int i, atomic_t *v)
|
||||||
{
|
{
|
||||||
|
@ -392,8 +392,8 @@ struct inodes_stat_t {
|
|||||||
#include <linux/semaphore.h>
|
#include <linux/semaphore.h>
|
||||||
#include <linux/fiemap.h>
|
#include <linux/fiemap.h>
|
||||||
#include <linux/rculist_bl.h>
|
#include <linux/rculist_bl.h>
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
|
||||||
#include <asm/atomic.h>
|
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
|
|
||||||
struct export_operations;
|
struct export_operations;
|
||||||
@ -2195,8 +2195,31 @@ static inline bool execute_ok(struct inode *inode)
|
|||||||
return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode);
|
return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int get_write_access(struct inode *);
|
/*
|
||||||
extern int deny_write_access(struct file *);
|
* get_write_access() gets write permission for a file.
|
||||||
|
* put_write_access() releases this write permission.
|
||||||
|
* This is used for regular files.
|
||||||
|
* We cannot support write (and maybe mmap read-write shared) accesses and
|
||||||
|
* MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode
|
||||||
|
* can have the following values:
|
||||||
|
* 0: no writers, no VM_DENYWRITE mappings
|
||||||
|
* < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist
|
||||||
|
* > 0: (i_writecount) users are writing to the file.
|
||||||
|
*
|
||||||
|
* Normally we operate on that counter with atomic_{inc,dec} and it's safe
|
||||||
|
* except for the cases where we don't hold i_writecount yet. Then we need to
|
||||||
|
* use {get,deny}_write_access() - these functions check the sign and refuse
|
||||||
|
* to do the change if sign is wrong.
|
||||||
|
*/
|
||||||
|
static inline int get_write_access(struct inode *inode)
|
||||||
|
{
|
||||||
|
return atomic_inc_unless_negative(&inode->i_writecount) ? 0 : -ETXTBSY;
|
||||||
|
}
|
||||||
|
static inline int deny_write_access(struct file *file)
|
||||||
|
{
|
||||||
|
struct inode *inode = file->f_path.dentry->d_inode;
|
||||||
|
return atomic_dec_unless_positive(&inode->i_writecount) ? 0 : -ETXTBSY;
|
||||||
|
}
|
||||||
static inline void put_write_access(struct inode * inode)
|
static inline void put_write_access(struct inode * inode)
|
||||||
{
|
{
|
||||||
atomic_dec(&inode->i_writecount);
|
atomic_dec(&inode->i_writecount);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user