diff options
Diffstat (limited to 'fs/locks.c')
| -rw-r--r-- | fs/locks.c | 112 | 
1 files changed, 68 insertions, 44 deletions
diff --git a/fs/locks.c b/fs/locks.c index ab24d49fc04..8b2b6ad56a0 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -143,6 +143,22 @@ int lease_break_time = 45;  static LIST_HEAD(file_lock_list);  static LIST_HEAD(blocked_list); +/* + * Protects the two list heads above, plus the inode->i_flock list + * FIXME: should use a spinlock, once lockd and ceph are ready. + */ +void lock_flocks(void) +{ +	lock_kernel(); +} +EXPORT_SYMBOL_GPL(lock_flocks); + +void unlock_flocks(void) +{ +	unlock_kernel(); +} +EXPORT_SYMBOL_GPL(unlock_flocks); +  static struct kmem_cache *filelock_cache __read_mostly;  /* Allocate an empty lock structure. */ @@ -511,9 +527,9 @@ static void __locks_delete_block(struct file_lock *waiter)   */  static void locks_delete_block(struct file_lock *waiter)  { -	lock_kernel(); +	lock_flocks();  	__locks_delete_block(waiter); -	unlock_kernel(); +	unlock_flocks();  }  /* Insert waiter into blocker's block list. @@ -644,7 +660,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)  {  	struct file_lock *cfl; -	lock_kernel(); +	lock_flocks();  	for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {  		if (!IS_POSIX(cfl))  			continue; @@ -657,7 +673,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)  			fl->fl_pid = pid_vnr(cfl->fl_nspid);  	} else  		fl->fl_type = F_UNLCK; -	unlock_kernel(); +	unlock_flocks();  	return;  }  EXPORT_SYMBOL(posix_test_lock); @@ -730,18 +746,16 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)  	int error = 0;  	int found = 0; -	lock_kernel(); -	if (request->fl_flags & FL_ACCESS) -		goto find_conflict; - -	if (request->fl_type != F_UNLCK) { -		error = -ENOMEM; +	if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) {  		new_fl = locks_alloc_lock(); -		if (new_fl == NULL) -			goto out; -		error = 0; +		if (!new_fl) +			return -ENOMEM;  	} +	lock_flocks(); +	if (request->fl_flags & FL_ACCESS) +		goto find_conflict; +  	for_each_lock(inode, before) {  		struct file_lock *fl = *before;  		if (IS_POSIX(fl)) @@ -767,8 +781,11 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)  	 * If a higher-priority process was blocked on the old file lock,  	 * give it the opportunity to lock the file.  	 */ -	if (found) +	if (found) { +		unlock_flocks();  		cond_resched(); +		lock_flocks(); +	}  find_conflict:  	for_each_lock(inode, before) { @@ -794,7 +811,7 @@ find_conflict:  	error = 0;  out: -	unlock_kernel(); +	unlock_flocks();  	if (new_fl)  		locks_free_lock(new_fl);  	return error; @@ -823,7 +840,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str  		new_fl2 = locks_alloc_lock();  	} -	lock_kernel(); +	lock_flocks();  	if (request->fl_type != F_UNLCK) {  		for_each_lock(inode, before) {  			fl = *before; @@ -991,7 +1008,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str  		locks_wake_up_blocks(left);  	}   out: -	unlock_kernel(); +	unlock_flocks();  	/*  	 * Free any unused locks.  	 */ @@ -1066,14 +1083,14 @@ int locks_mandatory_locked(struct inode *inode)  	/*  	 * Search the lock list for this inode for any POSIX locks.  	 */ -	lock_kernel(); +	lock_flocks();  	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {  		if (!IS_POSIX(fl))  			continue;  		if (fl->fl_owner != owner)  			break;  	} -	unlock_kernel(); +	unlock_flocks();  	return fl ? -EAGAIN : 0;  } @@ -1186,7 +1203,7 @@ int __break_lease(struct inode *inode, unsigned int mode)  	new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK); -	lock_kernel(); +	lock_flocks();  	time_out_leases(inode); @@ -1247,8 +1264,10 @@ restart:  			break_time++;  	}  	locks_insert_block(flock, new_fl); +	unlock_flocks();  	error = wait_event_interruptible_timeout(new_fl->fl_wait,  						!new_fl->fl_next, break_time); +	lock_flocks();  	__locks_delete_block(new_fl);  	if (error >= 0) {  		if (error == 0) @@ -1263,7 +1282,7 @@ restart:  	}  out: -	unlock_kernel(); +	unlock_flocks();  	if (!IS_ERR(new_fl))  		locks_free_lock(new_fl);  	return error; @@ -1319,7 +1338,7 @@ int fcntl_getlease(struct file *filp)  	struct file_lock *fl;  	int type = F_UNLCK; -	lock_kernel(); +	lock_flocks();  	time_out_leases(filp->f_path.dentry->d_inode);  	for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl);  			fl = fl->fl_next) { @@ -1328,7 +1347,7 @@ int fcntl_getlease(struct file *filp)  			break;  		}  	} -	unlock_kernel(); +	unlock_flocks();  	return type;  } @@ -1341,7 +1360,7 @@ int fcntl_getlease(struct file *filp)   *	The (input) flp->fl_lmops->fl_break function is required   *	by break_lease().   * - *	Called with kernel lock held. + *	Called with file_lock_lock held.   */  int generic_setlease(struct file *filp, long arg, struct file_lock **flp)  { @@ -1436,7 +1455,15 @@ out:  }  EXPORT_SYMBOL(generic_setlease); - /** +static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease) +{ +	if (filp->f_op && filp->f_op->setlease) +		return filp->f_op->setlease(filp, arg, lease); +	else +		return generic_setlease(filp, arg, lease); +} + +/**   *	vfs_setlease        -       sets a lease on an open file   *	@filp: file pointer   *	@arg: type of lease to obtain @@ -1467,12 +1494,9 @@ int vfs_setlease(struct file *filp, long arg, struct file_lock **lease)  {  	int error; -	lock_kernel(); -	if (filp->f_op && filp->f_op->setlease) -		error = filp->f_op->setlease(filp, arg, lease); -	else -		error = generic_setlease(filp, arg, lease); -	unlock_kernel(); +	lock_flocks(); +	error = __vfs_setlease(filp, arg, lease); +	unlock_flocks();  	return error;  } @@ -1499,9 +1523,9 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)  	if (error)  		return error; -	lock_kernel(); +	lock_flocks(); -	error = vfs_setlease(filp, arg, &flp); +	error = __vfs_setlease(filp, arg, &flp);  	if (error || arg == F_UNLCK)  		goto out_unlock; @@ -1516,7 +1540,7 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)  	error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);  out_unlock: -	unlock_kernel(); +	unlock_flocks();  	return error;  } @@ -2020,7 +2044,7 @@ void locks_remove_flock(struct file *filp)  			fl.fl_ops->fl_release_private(&fl);  	} -	lock_kernel(); +	lock_flocks();  	before = &inode->i_flock;  	while ((fl = *before) != NULL) { @@ -2038,7 +2062,7 @@ void locks_remove_flock(struct file *filp)   		}  		before = &fl->fl_next;  	} -	unlock_kernel(); +	unlock_flocks();  }  /** @@ -2053,12 +2077,12 @@ posix_unblock_lock(struct file *filp, struct file_lock *waiter)  {  	int status = 0; -	lock_kernel(); +	lock_flocks();  	if (waiter->fl_next)  		__locks_delete_block(waiter);  	else  		status = -ENOENT; -	unlock_kernel(); +	unlock_flocks();  	return status;  } @@ -2172,7 +2196,7 @@ static int locks_show(struct seq_file *f, void *v)  static void *locks_start(struct seq_file *f, loff_t *pos)  { -	lock_kernel(); +	lock_flocks();  	f->private = (void *)1;  	return seq_list_start(&file_lock_list, *pos);  } @@ -2184,7 +2208,7 @@ static void *locks_next(struct seq_file *f, void *v, loff_t *pos)  static void locks_stop(struct seq_file *f, void *v)  { -	unlock_kernel(); +	unlock_flocks();  }  static const struct seq_operations locks_seq_operations = { @@ -2231,7 +2255,7 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len)  {  	struct file_lock *fl;  	int result = 1; -	lock_kernel(); +	lock_flocks();  	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {  		if (IS_POSIX(fl)) {  			if (fl->fl_type == F_RDLCK) @@ -2248,7 +2272,7 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len)  		result = 0;  		break;  	} -	unlock_kernel(); +	unlock_flocks();  	return result;  } @@ -2271,7 +2295,7 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)  {  	struct file_lock *fl;  	int result = 1; -	lock_kernel(); +	lock_flocks();  	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {  		if (IS_POSIX(fl)) {  			if ((fl->fl_end < start) || (fl->fl_start > (start + len))) @@ -2286,7 +2310,7 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)  		result = 0;  		break;  	} -	unlock_kernel(); +	unlock_flocks();  	return result;  }  |