Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07b8ce1e authored by Al Viro's avatar Al Viro
Browse files

lockless get_write_access/deny_write_access



new helpers: atomic_inc_unless_negative()/atomic_dec_unless_positive()

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent f4d6ff89
Loading
Loading
Loading
Loading
+0 −46
Original line number Original line Diff line number Diff line
@@ -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
+26 −0
Original line number Original line Diff line number Diff line
@@ -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)
{
{
+26 −3
Original line number Original line Diff line number Diff line
@@ -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);