summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Preslan <kpreslan@redhat.com>2004-09-07 17:50:11 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-09-07 17:50:11 -0700
commit22141f0513da328f8f4e405953e5e52fb7c4e65a (patch)
treeebaa56d878ec10506714ab5765bf07648d1432f2
parentc1b76a2b004bbba387a7c6d26b29434a905bc058 (diff)
[PATCH] Allow cluster-wide flock
Below is a patch that lets a cluster filesystem (such as GFS) implement flock across the cluster. Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/locks.c50
-rw-r--r--include/linux/fs.h2
2 files changed, 41 insertions, 11 deletions
diff --git a/fs/locks.c b/fs/locks.c
index 596119474493..e80312cd5c22 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1318,6 +1318,33 @@ out_unlock:
}
/**
+ * flock_lock_file_wait - Apply a FLOCK-style lock to a file
+ * @filp: The file to apply the lock to
+ * @fl: The lock to be applied
+ *
+ * Add a FLOCK style lock to a file.
+ */
+int flock_lock_file_wait(struct file *filp, struct file_lock *fl)
+{
+ int error;
+ might_sleep();
+ for (;;) {
+ error = flock_lock_file(filp, fl);
+ if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
+ break;
+ error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
+ if (!error)
+ continue;
+
+ locks_delete_block(fl);
+ break;
+ }
+ return error;
+}
+
+EXPORT_SYMBOL(flock_lock_file_wait);
+
+/**
* sys_flock: - flock() system call.
* @fd: the file descriptor to lock.
* @cmd: the type of lock to apply.
@@ -1365,17 +1392,12 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
if (error)
goto out_free;
- for (;;) {
- error = flock_lock_file(filp, lock);
- if ((error != -EAGAIN) || !can_sleep)
- break;
- error = wait_event_interruptible(lock->fl_wait, !lock->fl_next);
- if (!error)
- continue;
-
- locks_delete_block(lock);
- break;
- }
+ if (filp->f_op && filp->f_op->flock)
+ error = filp->f_op->flock(filp,
+ (can_sleep) ? F_SETLKW : F_SETLK,
+ lock);
+ else
+ error = flock_lock_file_wait(filp, lock);
out_free:
if (list_empty(&lock->fl_link)) {
@@ -1732,6 +1754,12 @@ void locks_remove_flock(struct file *filp)
if (!inode->i_flock)
return;
+ if (filp->f_op && filp->f_op->flock) {
+ struct file_lock fl = { .fl_flags = FL_FLOCK,
+ .fl_type = F_UNLCK };
+ filp->f_op->flock(filp, F_SETLKW, &fl);
+ }
+
lock_kernel();
before = &inode->i_flock;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 68d486024d56..861be6705127 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -695,6 +695,7 @@ extern int posix_lock_file_wait(struct file *, 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 *);
+extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
extern int __break_lease(struct inode *inode, unsigned int flags);
extern void lease_get_mtime(struct inode *, struct timespec *time);
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
@@ -912,6 +913,7 @@ struct file_operations {
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
+ int (*flock) (struct file *, int, struct file_lock *);
};
struct inode_operations {