static kmem_cache_t *filelock_cache;
/* Allocate an empty lock structure. */
-static struct file_lock *locks_alloc_lock(int account)
+static struct file_lock *locks_alloc_lock(void)
{
- struct file_lock *fl;
- if (account && current->locks >= current->rlim[RLIMIT_LOCKS].rlim_cur)
- return NULL;
- fl = kmem_cache_alloc(filelock_cache, SLAB_KERNEL);
- if (fl)
- current->locks++;
- return fl;
+ return kmem_cache_alloc(filelock_cache, SLAB_KERNEL);
}
/* Free a lock which is not in use. */
BUG();
return;
}
- current->locks--;
if (waitqueue_active(&fl->fl_wait))
panic("Attempting to free lock with active wait queue");
if (type < 0)
return type;
- fl = locks_alloc_lock(1);
+ fl = locks_alloc_lock();
if (fl == NULL)
return -ENOMEM;
/* Allocate a file_lock initialised to this type of lease */
static int lease_alloc(struct file *filp, int type, struct file_lock **flp)
{
- struct file_lock *fl = locks_alloc_lock(1);
+ struct file_lock *fl = locks_alloc_lock();
if (fl == NULL)
return -ENOMEM;
/* Remove waiter from blocker's block list.
* When blocker ends up pointing to itself then the list is empty.
*/
-static void locks_delete_block(struct file_lock *waiter)
+static inline void __locks_delete_block(struct file_lock *waiter)
{
list_del_init(&waiter->fl_block);
list_del_init(&waiter->fl_link);
waiter->fl_next = NULL;
}
+/*
+ */
+static void locks_delete_block(struct file_lock *waiter)
+{
+ lock_kernel();
+ __locks_delete_block(waiter);
+ unlock_kernel();
+}
+
/* Insert waiter into blocker's block list.
* We use a circular list so that processes can be easily woken up in
* the order they blocked. The documentation doesn't require this but
printk(KERN_ERR "locks_insert_block: removing duplicated lock "
"(pid=%d %Ld-%Ld type=%d)\n", waiter->fl_pid,
waiter->fl_start, waiter->fl_end, waiter->fl_type);
- locks_delete_block(waiter);
+ __locks_delete_block(waiter);
}
list_add_tail(&waiter->fl_block, &blocker->fl_block);
waiter->fl_next = blocker;
while (!list_empty(&blocker->fl_block)) {
struct file_lock *waiter = list_entry(blocker->fl_block.next,
struct file_lock, fl_block);
- locks_delete_block(waiter);
+ __locks_delete_block(waiter);
if (waiter->fl_notify)
waiter->fl_notify(waiter);
else
int result;
locks_insert_block(blocker, waiter);
result = interruptible_sleep_on_locked(&waiter->fl_wait, time);
- locks_delete_block(waiter);
+ __locks_delete_block(waiter);
return result;
}
* We may need two file_lock structures for this operation,
* so we get them in advance to avoid races.
*/
- new_fl = locks_alloc_lock(0);
- new_fl2 = locks_alloc_lock(0);
+ new_fl = locks_alloc_lock();
+ new_fl2 = locks_alloc_lock();
lock_kernel();
if (request->fl_type != F_UNLCK) {
continue;
}
- lock_kernel();
locks_delete_block(&fl);
- unlock_kernel();
break;
}
if (!error)
continue;
- lock_kernel();
locks_delete_block(lock);
- unlock_kernel();
break;
}
*/
int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock *l)
{
- struct file_lock *file_lock = locks_alloc_lock(0);
+ struct file_lock *file_lock = locks_alloc_lock();
struct flock flock;
struct inode *inode;
int error;
if (!error)
continue;
- lock_kernel();
locks_delete_block(file_lock);
- unlock_kernel();
break;
}
*/
int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 *l)
{
- struct file_lock *file_lock = locks_alloc_lock(0);
+ struct file_lock *file_lock = locks_alloc_lock();
struct flock64 flock;
struct inode *inode;
int error;
if (!error)
continue;
- lock_kernel();
locks_delete_block(file_lock);
- unlock_kernel();
break;
}
*/
void locks_remove_posix(struct file *filp, fl_owner_t owner)
{
- struct file_lock lock;
+ struct file_lock lock, **before;
/*
* If there are no locks held on this file, we don't need to call
* posix_lock_file(). Another process could be setting a lock on this
* file at the same time, but we wouldn't remove that lock anyway.
*/
- if (!filp->f_dentry->d_inode->i_flock)
+ before = &filp->f_dentry->d_inode->i_flock;
+ if (*before == NULL)
return;
lock.fl_type = F_UNLCK;
/* Ignore any error -- we must remove the locks anyway */
}
- posix_lock_file(filp, &lock);
+ /* Can't use posix_lock_file here; we need to remove it no matter
+ * which pid we have.
+ */
+ lock_kernel();
+ while (*before != NULL) {
+ struct file_lock *fl = *before;
+ if (IS_POSIX(fl) && (fl->fl_owner == owner)) {
+ locks_delete_lock(before);
+ continue;
+ }
+ before = &fl->fl_next;
+ }
+ unlock_kernel();
}
/*
lease_modify(before, F_UNLCK);
continue;
}
+ BUG();
}
before = &fl->fl_next;
}
*/
lock_kernel();
if (waiter->fl_next) {
- locks_delete_block(waiter);
+ __locks_delete_block(waiter);
unlock_kernel();
} else {
unlock_kernel();
? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
: (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
}
-#if WE_CAN_BREAK_LSLK_NOW
if (inode) {
+#if WE_CAN_BREAK_LSLK_NOW
out += sprintf(out, "%d %s:%ld ", fl->fl_pid,
inode->i_sb->s_id, inode->i_ino);
+#else
+ /* userspace relies on this representation of dev_t ;-( */
+ out += sprintf(out, "%d %02x:%02x:%ld ", fl->fl_pid,
+ MAJOR(inode->i_sb->s_dev),
+ MINOR(inode->i_sb->s_dev), inode->i_ino);
+#endif
} else {
out += sprintf(out, "%d <none>:0 ", fl->fl_pid);
}
-#else
- /* kdevname is a broken interface. but we expose it to userspace */
- out += sprintf(out, "%d %s:%ld ", fl->fl_pid,
- inode ? kdevname(to_kdev_t(inode->i_sb->s_dev)) : "<none>",
- inode ? inode->i_ino : 0);
-#endif
if (IS_POSIX(fl)) {
if (fl->fl_end == OFFSET_MAX)
out += sprintf(out, "%Ld EOF\n", fl->fl_start);