Example #1
0
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks at
 * the head of the list, but that's secret knowledge known only to the next
 * two functions.
 */
static int flock_lock_file(struct file *filp, struct file_lock *caller,
			   unsigned int wait)
{
	struct file_lock *fl;
	struct file_lock *new_fl = NULL;
	struct file_lock **before;
	int error;
	int change;
	int unlock = (caller->fl_type == F_UNLCK);

	/*
	 * If we need a new lock, get it in advance to avoid races.
	 */
	if (!unlock) {
		error = -ENOLCK;
		new_fl = locks_alloc_lock(caller);
		if (!new_fl)
			goto out;
	}


	error = 0;
search:
	change = 0;

	before = &filp->f_inode->i_flock;

	if ((fl = *before) && (fl->fl_flags & FL_POSIX)) {
		error = -EBUSY;
		goto out;
	}

	while ((fl = *before) != NULL) {
		if (caller->fl_file == fl->fl_file) {
			if (caller->fl_type == fl->fl_type)
				goto out;
			change = 1;
			break;
		}
		before = &fl->fl_next;
	}
	/* change means that we are changing the type of an existing lock, or
	 * or else unlocking it.
	 */
	if (change) {
		/* N.B. What if the wait argument is false? */
		locks_delete_lock(before, !unlock);
		/*
		 * If we waited, another lock may have been added ...
		 */
		if (!unlock)
			goto search;
	}
	if (unlock)
		goto out;

repeat:
	/* Check signals each time we start */
	error = -ERESTARTSYS;
	if (current->signal & ~current->blocked)
		goto out;
	error = -EBUSY;
	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & FL_POSIX))
		goto out;

	while (fl != NULL) {
		if (!flock_locks_conflict(new_fl, fl)) {
			fl = fl->fl_next;
			continue;
		}
		error = -EAGAIN;
		if (!wait)
			goto out;
		locks_insert_block(fl, new_fl);
		interruptible_sleep_on(&new_fl->fl_wait);
		locks_delete_block(fl, new_fl);
		goto repeat;
	}
	locks_insert_lock(&filp->f_inode->i_flock, new_fl);
	new_fl = NULL;
	error = 0;

out:
	if (new_fl)
		locks_free_lock(new_fl);
	return (error);
}
Example #2
0
/* Try to create a FLOCK lock on filp. We always insert new locks at
 * the head of the list.
 */
static int flock_lock_file(struct file *filp, struct file_lock *caller,
			   unsigned int wait)
{
	struct file_lock *fl;
	struct file_lock *new_fl;
	struct file_lock **before;
	int change = 0;

	before = &filp->f_inode->i_flock;

	if ((fl = *before) && (fl->fl_flags & F_POSIX))
		return (-EBUSY);

	while ((fl = *before) != NULL) {
		if (caller->fl_file == fl->fl_file) {
			if (caller->fl_type == fl->fl_type)
				return (0);
			change = 1;
			break;
		}
		before = &fl->fl_next;
	}
	/* change means that we are changing the type of an existing lock, or
	 * or else unlocking it.
	 */
	if (change)
		locks_delete_lock(before, caller->fl_type != F_UNLCK);
	if (caller->fl_type == F_UNLCK)
		return (0);
	if ((new_fl = locks_alloc_lock(caller)) == NULL)
		return (-ENOLCK);
repeat:
	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & F_POSIX)) {
		locks_free_lock(new_fl);
		return (-EBUSY);
	}

	while (fl != NULL) {
		if (flock_locks_conflict(new_fl, fl)) {
			if (!wait) {
				locks_free_lock(new_fl);
				return (-EAGAIN);
			}
			if (current->signal & ~current->blocked) {
				/* Note: new_fl is not in any queue at this
				 * point, so we must use locks_free_lock()
				 * instead of locks_delete_lock()
				 * 	Dmitry Gorodchanin 09/02/96.
				 */
				locks_free_lock(new_fl);
				return (-ERESTARTSYS);
			}
			locks_insert_block(fl, new_fl);
			interruptible_sleep_on(&new_fl->fl_wait);
			wake_up(&new_fl->fl_wait);
			if (current->signal & ~current->blocked) {
				/* If we are here, than we were awakened
				 * by a signal, so new_fl is still in the
				 * block queue of fl. We need to remove 
				 * new_fl and then free it.
				 * 	Dmitry Gorodchanin 09/02/96.
				 */
				locks_delete_block(fl, new_fl);
				locks_free_lock(new_fl);
				return (-ERESTARTSYS);
			}
			goto repeat;
		}
		fl = fl->fl_next;
	}
	locks_insert_lock(&filp->f_inode->i_flock, new_fl);
	return (0);
}