Commit fd3020fe authored by Matthew Wilcox's avatar Matthew Wilcox Committed by Linus Torvalds

[PATCH] fs/locks.c: more cleanup

Define the for_each_lock macro and start replacing ugly special for loops
with it.  Rejig the interface between sys_flock and flock_lock_file to
always pass a struct file_lock rather than a command.  Eliminate some
gotos by simplifying the logic.  Remove some redundant initialisation.
parent 10f25922
...@@ -132,6 +132,9 @@ ...@@ -132,6 +132,9 @@
int leases_enable = 1; int leases_enable = 1;
int lease_break_time = 45; int lease_break_time = 45;
#define for_each_lock(inode, lockp) \
for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next)
LIST_HEAD(file_lock_list); LIST_HEAD(file_lock_list);
static LIST_HEAD(blocked_list); static LIST_HEAD(blocked_list);
...@@ -220,25 +223,41 @@ void locks_copy_lock(struct file_lock *new, struct file_lock *fl) ...@@ -220,25 +223,41 @@ void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
new->fl_u = fl->fl_u; new->fl_u = fl->fl_u;
} }
static inline int flock_translate_cmd(int cmd) {
if (cmd & LOCK_MAND)
return cmd & (LOCK_MAND | LOCK_RW);
switch (cmd &~ LOCK_NB) {
case LOCK_SH:
return F_RDLCK;
case LOCK_EX:
return F_WRLCK;
case LOCK_UN:
return F_UNLCK;
}
return -EINVAL;
}
/* Fill in a file_lock structure with an appropriate FLOCK lock. */ /* Fill in a file_lock structure with an appropriate FLOCK lock. */
static struct file_lock *flock_make_lock(struct file *filp, unsigned int type) static int flock_make_lock(struct file *filp,
struct file_lock **lock, unsigned int cmd)
{ {
struct file_lock *fl = locks_alloc_lock(1); struct file_lock *fl;
int type = flock_translate_cmd(cmd);
if (type < 0)
return type;
fl = locks_alloc_lock(1);
if (fl == NULL) if (fl == NULL)
return NULL; return -ENOMEM;
fl->fl_owner = NULL;
fl->fl_file = filp; fl->fl_file = filp;
fl->fl_pid = current->pid; fl->fl_pid = current->pid;
fl->fl_flags = FL_FLOCK; fl->fl_flags = FL_FLOCK;
fl->fl_type = type; fl->fl_type = type;
fl->fl_start = 0;
fl->fl_end = OFFSET_MAX; fl->fl_end = OFFSET_MAX;
fl->fl_notify = NULL;
fl->fl_insert = NULL;
fl->fl_remove = NULL;
return fl; *lock = fl;
return 0;
} }
static int assign_type(struct file_lock *fl, int type) static int assign_type(struct file_lock *fl, int type)
...@@ -756,59 +775,45 @@ int locks_mandatory_area(int read_write, struct inode *inode, ...@@ -756,59 +775,45 @@ int locks_mandatory_area(int read_write, struct inode *inode,
* at the head of the list, but that's secret knowledge known only to * at the head of the list, but that's secret knowledge known only to
* flock_lock_file and posix_lock_file. * flock_lock_file and posix_lock_file.
*/ */
static int flock_lock_file(struct file *filp, unsigned int lock_type, static int flock_lock_file(struct file *filp, struct file_lock *new_fl,
unsigned int wait) unsigned int wait)
{ {
struct file_lock *fl;
struct file_lock *new_fl = NULL;
struct file_lock **before; struct file_lock **before;
struct inode * inode = filp->f_dentry->d_inode; struct inode * inode = filp->f_dentry->d_inode;
int error, change; int error = 0;
int unlock = (lock_type == F_UNLCK); int found = 0;
/*
* If we need a new lock, get it in advance to avoid races.
*/
if (!unlock) {
error = -ENOLCK;
new_fl = flock_make_lock(filp, lock_type);
if (!new_fl)
return error;
}
error = 0; lock_kernel();
search: for_each_lock(inode, before) {
change = 0; struct file_lock *fl = *before;
before = &inode->i_flock; if (IS_POSIX(fl))
while (((fl = *before) != NULL) && IS_FLOCK(fl)) {
if (filp == fl->fl_file) {
if (lock_type == fl->fl_type)
goto out;
change = 1;
break; break;
} if (IS_LEASE(fl))
before = &fl->fl_next; continue;
} if (filp != fl->fl_file)
/* change means that we are changing the type of an existing lock, continue;
* or else unlocking it. if (new_fl->fl_type == fl->fl_type)
*/ goto out;
if (change) { found = 1;
/* N.B. What if the wait argument is false? */
locks_delete_lock(before); locks_delete_lock(before);
if (!unlock) { break;
yield();
/*
* If we waited, another lock may have been added ...
*/
goto search;
}
} }
if (unlock) unlock_kernel();
goto out;
if (found)
yield();
if (new_fl->fl_type == F_UNLCK)
return 0;
lock_kernel();
repeat: repeat:
for (fl = inode->i_flock; (fl != NULL) && IS_FLOCK(fl); for_each_lock(inode, before) {
fl = fl->fl_next) { struct file_lock *fl = *before;
if (IS_POSIX(fl))
break;
if (IS_LEASE(fl))
continue;
if (!flock_locks_conflict(new_fl, fl)) if (!flock_locks_conflict(new_fl, fl))
continue; continue;
error = -EAGAIN; error = -EAGAIN;
...@@ -820,12 +825,10 @@ static int flock_lock_file(struct file *filp, unsigned int lock_type, ...@@ -820,12 +825,10 @@ static int flock_lock_file(struct file *filp, unsigned int lock_type,
goto repeat; goto repeat;
} }
locks_insert_lock(&inode->i_flock, new_fl); locks_insert_lock(&inode->i_flock, new_fl);
new_fl = NULL;
error = 0; error = 0;
out: out:
if (new_fl) unlock_kernel();
locks_free_lock(new_fl);
return error; return error;
} }
...@@ -1025,20 +1028,6 @@ int posix_lock_file(struct file *filp, struct file_lock *caller, ...@@ -1025,20 +1028,6 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
return error; return error;
} }
static inline int flock_translate_cmd(int cmd) {
if (cmd & LOCK_MAND)
return cmd & (LOCK_MAND | LOCK_RW);
switch (cmd &~ LOCK_NB) {
case LOCK_SH:
return F_RDLCK;
case LOCK_EX:
return F_WRLCK;
case LOCK_UN:
return F_UNLCK;
}
return -EINVAL;
}
/** /**
* __get_lease - revoke all outstanding leases on file * __get_lease - revoke all outstanding leases on file
* @inode: the inode of the file to return * @inode: the inode of the file to return
...@@ -1307,26 +1296,26 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) ...@@ -1307,26 +1296,26 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
{ {
struct file *filp; struct file *filp;
int error, type; struct file_lock *lock;
int error;
error = -EBADF; error = -EBADF;
filp = fget(fd); filp = fget(fd);
if (!filp) if (!filp)
goto out; goto out;
error = flock_translate_cmd(cmd); if ((cmd != LOCK_UN) && !(cmd & LOCK_MAND) && !(filp->f_mode & 3))
if (error < 0)
goto out_putf; goto out_putf;
type = error;
error = -EBADF; error = flock_make_lock(filp, &lock, cmd);
if ((type != F_UNLCK) && !(type & LOCK_MAND) && !(filp->f_mode & 3)) if (error < 0)
goto out_putf; goto out_putf;
lock_kernel(); error = flock_lock_file(filp, lock,
error = flock_lock_file(filp, type,
(cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1); (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
unlock_kernel();
if (error)
locks_free_lock(lock);
out_putf: out_putf:
fput(filp); fput(filp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment