[PATCH] 2.5.59: ftruncate/truncate oopses with mandatory locking

Faik Uygur (faikuygur@ttnet.net.tr)
Thu, 23 Jan 2003 02:55:30 +0200


This patch fixes the truncate/ftruncate oopses with mandatory locking
enabled. The problem with ftruncate is that the local variable fl is
not initialized properly in locks_mandatory_area that it misbehaves at
various places like locks_insert_block. And the problem with truncate
is that the filp variable is NULL at posix_lock_file. The NULL value
comes from do_sys_truncate.

The bug report and details can be found at,
http://bugme.osdl.org/show_bug.cgi?id=280

diff -uNr linux-2.5.59-vanilla/fs/lockd/svclock.c linux-2.5.59/fs/lockd/svclock.c
--- linux-2.5.59-vanilla/fs/lockd/svclock.c Thu Nov 28 00:35:55 2002
+++ linux-2.5.59/fs/lockd/svclock.c Thu Jan 23 00:41:45 2003
@@ -315,7 +315,7 @@

again:
if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {
- error = posix_lock_file(&file->f_file, &lock->fl);
+ error = posix_lock_file(file->f_file.f_dentry->d_inode, &lock->fl);

if (block)
nlmsvc_delete_block(block, 0);
@@ -419,7 +419,7 @@
nlmsvc_cancel_blocked(file, lock);

lock->fl.fl_type = F_UNLCK;
- error = posix_lock_file(&file->f_file, &lock->fl);
+ error = posix_lock_file(file->f_file.f_dentry->d_inode, &lock->fl);

return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
}
@@ -523,7 +523,7 @@
* following yields an error, this is most probably due to low
* memory. Retry the lock in a few seconds.
*/
- if ((error = posix_lock_file(&file->f_file, &lock->fl)) < 0) {
+ if ((error = posix_lock_file(file->f_file.f_dentry->d_inode, &lock->fl)) < 0) {
printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
-error, __FUNCTION__);
nlmsvc_insert_block(block, 10 * HZ);
diff -uNr linux-2.5.59-vanilla/fs/lockd/svcsubs.c linux-2.5.59/fs/lockd/svcsubs.c
--- linux-2.5.59-vanilla/fs/lockd/svcsubs.c Thu Nov 28 00:36:14 2002
+++ linux-2.5.59/fs/lockd/svcsubs.c Thu Jan 23 01:01:51 2003
@@ -176,7 +176,7 @@
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
lock.fl_end = OFFSET_MAX;
- if (posix_lock_file(&file->f_file, &lock) < 0) {
+ if (posix_lock_file(file->f_file.f_dentry->d_inode, &lock) < 0) {
printk("lockd: unlock failure in %s:%d\n",
__FILE__, __LINE__);
return 1;
diff -uNr linux-2.5.59-vanilla/fs/locks.c linux-2.5.59/fs/locks.c
--- linux-2.5.59-vanilla/fs/locks.c Thu Jan 23 00:02:16 2003
+++ linux-2.5.59/fs/locks.c Thu Jan 23 01:58:16 2003
@@ -678,6 +678,10 @@
struct file_lock fl;
int error;

+ INIT_LIST_HEAD(&fl.fl_link);
+ INIT_LIST_HEAD(&fl.fl_block);
+ init_waitqueue_head(&fl.fl_wait);
+
fl.fl_owner = current->files;
fl.fl_pid = current->tgid;
fl.fl_file = filp;
@@ -685,9 +689,14 @@
fl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
fl.fl_start = offset;
fl.fl_end = offset + count - 1;
+ fl.fl_next = NULL;
+ fl.fl_notify = NULL;
+ fl.fl_insert = NULL;
+ fl.fl_remove = NULL;
+ fl.fl_fasync = NULL;

for (;;) {
- error = posix_lock_file(filp, &fl);
+ error = posix_lock_file(inode, &fl);
if (error != -EAGAIN)
break;
error = wait_event_interruptible(fl.fl_wait, !fl.fl_next);
@@ -772,9 +781,8 @@

/**
* posix_lock_file:
- * @filp: The file to apply the lock to
- * @caller: The lock to be applied
- * @wait: 1 to retry automatically, 0 to return -EAGAIN
+ * @inode: The inode of file to apply the lock to
+ * @request: The lock to be applied
*
* Add a POSIX style lock to a file.
* We merge adjacent locks whenever possible. POSIX locks are sorted by owner
@@ -788,14 +796,13 @@
* To all purists: Yes, I use a few goto's. Just pass on to the next function.
*/

-int posix_lock_file(struct file *filp, struct file_lock *request)
+int posix_lock_file(struct inode *inode, struct file_lock *request)
{
struct file_lock *fl;
struct file_lock *new_fl, *new_fl2;
struct file_lock *left = NULL;
struct file_lock *right = NULL;
struct file_lock **before;
- struct inode * inode = filp->f_dentry->d_inode;
int error, added = 0;

/*
@@ -1460,7 +1467,7 @@
}

for (;;) {
- error = posix_lock_file(filp, file_lock);
+ error = posix_lock_file(inode, file_lock);
if ((error != -EAGAIN) || (cmd == F_SETLK))
break;
error = wait_event_interruptible(file_lock->fl_wait,
@@ -1600,7 +1607,7 @@
}

for (;;) {
- error = posix_lock_file(filp, file_lock);
+ error = posix_lock_file(inode, file_lock);
if ((error != -EAGAIN) || (cmd == F_SETLK64))
break;
error = wait_event_interruptible(file_lock->fl_wait,
@@ -1650,7 +1657,7 @@
/* Ignore any error -- we must remove the locks anyway */
}

- posix_lock_file(filp, &lock);
+ posix_lock_file(filp->f_dentry->d_inode, &lock);
}

/*
@@ -1717,7 +1724,7 @@
} else {
unlock_kernel();
waiter->fl_type = F_UNLCK;
- posix_lock_file(filp, waiter);
+ posix_lock_file(filp->f_dentry->d_inode, waiter);
}
}

diff -uNr linux-2.5.59-vanilla/include/linux/fs.h linux-2.5.59/include/linux/fs.h
--- linux-2.5.59-vanilla/include/linux/fs.h Thu Jan 23 00:02:44 2003
+++ linux-2.5.59/include/linux/fs.h Thu Jan 23 00:48:25 2003
@@ -568,7 +568,7 @@
extern void locks_remove_posix(struct file *, fl_owner_t);
extern void locks_remove_flock(struct file *);
extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
-extern int posix_lock_file(struct file *, struct file_lock *);
+extern int posix_lock_file(struct inode *, struct file_lock *);
extern void posix_block_lock(struct file_lock *, struct file_lock *);
extern void posix_unblock_lock(struct file *, struct file_lock *);
extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/