diff options
| author | Ken Preslan <kpreslan@redhat.com> | 2004-09-07 17:50:11 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-09-07 17:50:11 -0700 |
| commit | 22141f0513da328f8f4e405953e5e52fb7c4e65a (patch) | |
| tree | ebaa56d878ec10506714ab5765bf07648d1432f2 | |
| parent | c1b76a2b004bbba387a7c6d26b29434a905bc058 (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.c | 50 | ||||
| -rw-r--r-- | include/linux/fs.h | 2 |
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 { |
