From: Matthew Wilcox <willy@debian.org>
To: linux-fsdevel@vger.kernel.org
Subject: lock_operations
Date: Wed, 20 Nov 2002 07:20:50 +0000 [thread overview]
Message-ID: <20021120072050.B12656@parcelfarce.linux.theplanet.co.uk> (raw)
So... switching locks_remove_posix to use the unlock call was Bad, Evil
and Wrong. But I still really want the underlying filesystem to know
about what's coming since I don't want it to sleep in fl_remove.
Comments on this patch?
- introduces lock_operations
- splits old f_op->lock method into l_op->set_lock and ->get_lock
- moves fl->fl_insert and fl_remove methods to l_op->lock_insert and
l_op->lock_remove
- introduces remove_posix() and remove_flock().
I've fixed up NFS to the point where it will compile. I suspect that it's
possible to simplify NFS from here, but that would only clutter this patch.
I think the `nfsd over a clusterfs' problem is solvable with this
infrastructure. Introduce a new method that takes whatever information
(a pointer to a struct host, i guess?) the fs needs to construct a
meaningful owner field. But that's a patch for another day ...
diff -urpNX dontdiff linux-2.5.48/fs/lockd/clntproc.c linux-2.5.48-flock/fs/lockd/clntproc.c
--- linux-2.5.48/fs/lockd/clntproc.c 2002-11-17 23:29:21.000000000 -0500
+++ linux-2.5.48-flock/fs/lockd/clntproc.c 2002-11-19 18:38:39.000000000 -0500
@@ -462,8 +462,6 @@ nlmclnt_lock(struct nlm_rqst *req, struc
fl->fl_u.nfs_fl.state = host->h_state;
fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
fl->fl_u.nfs_fl.host = host;
- fl->fl_insert = nlmclnt_insert_lock_callback;
- fl->fl_remove = nlmclnt_remove_lock_callback;
}
return nlm_stat_to_errno(resp->status);
@@ -689,3 +687,30 @@ nlm_stat_to_errno(u32 status)
printk(KERN_NOTICE "lockd: unexpected server status %d\n", status);
return -ENOLCK;
}
+
+static int nlmclnt_set_lock(struct file *filp, struct file_lock *fl)
+{
+ if (fl->fl_flags & FL_SLEEP) {
+ nfs_lock(filp, F_SETLKW, fl);
+ } else {
+ nfs_lock(filp, F_SETLK, fl);
+ }
+}
+
+static int nlmclnt_get_lock(struct file *filp, struct file_lock *fl)
+{
+ nfs_lock(filp, F_GETLK, fl);
+}
+
+static int nlmclnt_remove_posix(struct file *filp, fl_owner_t id)
+{
+ printk("remove posix support not yet implemented\n");
+}
+
+struct lock_operations nfs_client_lops = {
+ .set_lock = nlmclnt_set_lock,
+ .get_lock = nlmclnt_get_lock,
+ .remove_posix = nlmclnt_remove_posix,
+ .lock_insert = nlmclnt_insert_lock_callback,
+ .lock_remove = nlmclnt_remove_lock_callback,
+};
diff -urpNX dontdiff linux-2.5.48/fs/locks.c linux-2.5.48-flock/fs/locks.c
--- linux-2.5.48/fs/locks.c 2002-11-17 23:29:56.000000000 -0500
+++ linux-2.5.48-flock/fs/locks.c 2002-11-19 19:31:23.000000000 -0500
@@ -187,8 +187,6 @@ void locks_init_lock(struct file_lock *f
fl->fl_type = 0;
fl->fl_start = fl->fl_end = 0;
fl->fl_notify = NULL;
- fl->fl_insert = NULL;
- fl->fl_remove = NULL;
}
/*
@@ -219,8 +217,6 @@ void locks_copy_lock(struct file_lock *n
new->fl_start = fl->fl_start;
new->fl_end = fl->fl_end;
new->fl_notify = fl->fl_notify;
- new->fl_insert = fl->fl_insert;
- new->fl_remove = fl->fl_remove;
new->fl_u = fl->fl_u;
}
@@ -312,8 +308,6 @@ static int flock_to_posix_lock(struct fi
fl->fl_file = filp;
fl->fl_flags = FL_POSIX;
fl->fl_notify = NULL;
- fl->fl_insert = NULL;
- fl->fl_remove = NULL;
return assign_type(fl, l->l_type);
}
@@ -352,8 +346,6 @@ static int flock64_to_posix_lock(struct
fl->fl_file = filp;
fl->fl_flags = FL_POSIX;
fl->fl_notify = NULL;
- fl->fl_insert = NULL;
- fl->fl_remove = NULL;
switch (l->l_type) {
case F_RDLCK:
@@ -388,8 +380,6 @@ static int lease_alloc(struct file *filp
fl->fl_start = 0;
fl->fl_end = OFFSET_MAX;
fl->fl_notify = NULL;
- fl->fl_insert = NULL;
- fl->fl_remove = NULL;
*flp = fl;
return 0;
@@ -465,14 +455,17 @@ static void locks_wake_up_blocks(struct
*/
static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
{
+ struct lock_operations *l_op = NULL;
list_add(&fl->fl_link, &file_lock_list);
/* insert into file's list */
fl->fl_next = *pos;
*pos = fl;
- if (fl->fl_insert)
- fl->fl_insert(fl);
+ if (fl->fl_file->f_op)
+ l_op = fl->fl_file->f_op->lock;
+ if (l_op && l_op->lock_insert)
+ l_op->lock_insert(fl);
}
/*
@@ -484,6 +477,7 @@ static void locks_insert_lock(struct fil
static void locks_delete_lock(struct file_lock **thisfl_p)
{
struct file_lock *fl = *thisfl_p;
+ struct lock_operations *l_op = NULL;
*thisfl_p = fl->fl_next;
fl->fl_next = NULL;
@@ -495,8 +489,10 @@ static void locks_delete_lock(struct fil
fl->fl_fasync = NULL;
}
- if (fl->fl_remove)
- fl->fl_remove(fl);
+ if (fl->fl_file->f_op)
+ l_op = fl->fl_file->f_op->lock;
+ if (l_op && l_op->lock_remove)
+ l_op->lock_remove(fl);
locks_wake_up_blocks(fl);
locks_free_lock(fl);
@@ -1324,6 +1320,7 @@ asmlinkage long sys_flock(unsigned int f
int fcntl_getlk(struct file *filp, struct flock *l)
{
struct file_lock *fl, file_lock;
+ struct lock_operations *l_op = NULL;
struct flock flock;
int error;
@@ -1338,15 +1335,13 @@ int fcntl_getlk(struct file *filp, struc
if (error)
goto out;
- if (filp->f_op && filp->f_op->lock) {
- error = filp->f_op->lock(filp, F_GETLK, &file_lock);
+ if (filp->f_op)
+ l_op = filp->f_op->lock;
+ if (l_op && l_op->get_lock) {
+ error = l_op->get_lock(filp, &file_lock);
if (error < 0)
goto out;
- else if (error == LOCK_USE_CLNT)
- /* Bypass for NFS with no locking - 2.0.36 compat */
- fl = posix_test_lock(filp, &file_lock);
- else
- fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
+ fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
} else {
fl = posix_test_lock(filp, &file_lock);
}
@@ -1380,19 +1375,48 @@ out:
return error;
}
+int vfs_setlock_posix(struct file *filp, struct file_lock *fl)
+{
+ struct lock_operations *l_op = NULL;
+ int error;
+
+ error = security_ops->file_lock(filp, fl->fl_type);
+ if (error)
+ return error;
+
+ if (filp->f_op)
+ l_op = filp->f_op->lock;
+ if (l_op && l_op->set_lock)
+ return l_op->set_lock(filp, fl);
+
+ for (;;) {
+ error = posix_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;
+
+ lock_kernel();
+ locks_delete_block(fl);
+ unlock_kernel();
+ break;
+ }
+
+ return error;
+}
+
/* Apply the lock described by l to an open file descriptor.
* This implements both the F_SETLK and F_SETLKW commands of fcntl().
*/
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;
struct flock flock;
struct inode *inode;
int error;
- if (file_lock == NULL)
- return -ENOLCK;
-
/*
* This might block, so we do it before checking the inode.
*/
@@ -1417,11 +1441,12 @@ int fcntl_setlk(struct file *filp, unsig
}
#endif
- error = flock_to_posix_lock(filp, file_lock, &flock);
+ locks_init_lock(&file_lock);
+ error = flock_to_posix_lock(filp, &file_lock, &flock);
if (error)
goto out;
if (cmd == F_SETLKW) {
- file_lock->fl_flags |= FL_SLEEP;
+ file_lock.fl_flags |= FL_SLEEP;
}
error = -EBADF;
@@ -1441,33 +1466,9 @@ int fcntl_setlk(struct file *filp, unsig
goto out;
}
- error = security_ops->file_lock(filp, file_lock->fl_type);
- if (error)
- goto out;
-
- if (filp->f_op && filp->f_op->lock != NULL) {
- error = filp->f_op->lock(filp, cmd, file_lock);
- if (error < 0)
- goto out;
- }
-
- for (;;) {
- error = posix_lock_file(filp, file_lock);
- if ((error != -EAGAIN) || (cmd == F_SETLK))
- break;
- error = wait_event_interruptible(file_lock->fl_wait,
- !file_lock->fl_next);
- if (!error)
- continue;
-
- lock_kernel();
- locks_delete_block(file_lock);
- unlock_kernel();
- break;
- }
+ error = vfs_setlock_posix(filp, &file_lock);
out:
- locks_free_lock(file_lock);
return error;
}
@@ -1478,6 +1479,7 @@ int fcntl_setlk(struct file *filp, unsig
int fcntl_getlk64(struct file *filp, struct flock64 *l)
{
struct file_lock *fl, file_lock;
+ struct lock_operations *l_op = NULL;
struct flock64 flock;
int error;
@@ -1492,15 +1494,13 @@ int fcntl_getlk64(struct file *filp, str
if (error)
goto out;
- if (filp->f_op && filp->f_op->lock) {
- error = filp->f_op->lock(filp, F_GETLK, &file_lock);
+ if (filp->f_op)
+ l_op = filp->f_op->lock;
+ if (l_op && l_op->get_lock) {
+ error = l_op->get_lock(filp, &file_lock);
if (error < 0)
goto out;
- else if (error == LOCK_USE_CLNT)
- /* Bypass for NFS with no locking - 2.0.36 compat */
- fl = posix_test_lock(filp, &file_lock);
- else
- fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
+ fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
} else {
fl = posix_test_lock(filp, &file_lock);
}
@@ -1527,14 +1527,11 @@ out:
*/
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;
struct flock64 flock;
struct inode *inode;
int error;
- if (file_lock == NULL)
- return -ENOLCK;
-
/*
* This might block, so we do it before checking the inode.
*/
@@ -1544,6 +1541,7 @@ int fcntl_setlk64(struct file *filp, uns
inode = filp->f_dentry->d_inode;
+#ifdef CONFIG_MMU
/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
*/
@@ -1556,12 +1554,13 @@ int fcntl_setlk64(struct file *filp, uns
goto out;
}
}
+#endif
- error = flock64_to_posix_lock(filp, file_lock, &flock);
+ error = flock64_to_posix_lock(filp, &file_lock, &flock);
if (error)
goto out;
if (cmd == F_SETLKW64) {
- file_lock->fl_flags |= FL_SLEEP;
+ file_lock.fl_flags |= FL_SLEEP;
}
error = -EBADF;
@@ -1581,33 +1580,9 @@ int fcntl_setlk64(struct file *filp, uns
goto out;
}
- error = security_ops->file_lock(filp, file_lock->fl_type);
- if (error)
- goto out;
-
- if (filp->f_op && filp->f_op->lock != NULL) {
- error = filp->f_op->lock(filp, cmd, file_lock);
- if (error < 0)
- goto out;
- }
-
- for (;;) {
- error = posix_lock_file(filp, file_lock);
- if ((error != -EAGAIN) || (cmd == F_SETLK64))
- break;
- error = wait_event_interruptible(file_lock->fl_wait,
- !file_lock->fl_next);
- if (!error)
- continue;
-
- lock_kernel();
- locks_delete_block(file_lock);
- unlock_kernel();
- break;
- }
+ error = vfs_setlock_posix(filp, &file_lock);
-out:
- locks_free_lock(file_lock);
+ out:
return error;
}
#endif /* BITS_PER_LONG == 32 */
@@ -1619,30 +1594,34 @@ out:
*/
void locks_remove_posix(struct file *filp, fl_owner_t owner)
{
- struct file_lock lock;
+ struct file_lock *fl, **before;
+ struct lock_operations *l_op = NULL;
+ struct inode *inode = filp->f_dentry->d_inode;
/*
- * 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 there are no locks held on this file, we don't need to do
+ * anything. Another thread could be setting a lock on this
+ * file at the same time, but it's a race we just won.
*/
- if (!filp->f_dentry->d_inode->i_flock)
+ if (!inode->i_flock)
return;
- lock.fl_type = F_UNLCK;
- lock.fl_flags = FL_POSIX;
- lock.fl_start = 0;
- lock.fl_end = OFFSET_MAX;
- lock.fl_owner = owner;
- lock.fl_pid = current->tgid;
- lock.fl_file = filp;
-
- if (filp->f_op && filp->f_op->lock != NULL) {
- filp->f_op->lock(filp, F_SETLK, &lock);
- /* Ignore any error -- we must remove the locks anyway */
+ if (filp->f_op)
+ l_op = filp->f_op->lock;
+ if (l_op && l_op->remove_posix) {
+ l_op->remove_posix(filp, owner);
+ } else {
+ lock_kernel();
+ before = &inode->i_flock;
+ while ((fl = *before) != NULL) {
+ if (IS_POSIX(fl) && fl->fl_owner == owner) {
+ locks_delete_lock(before);
+ continue;
+ }
+ before = &fl->fl_next;
+ }
+ unlock_kernel();
}
-
- posix_lock_file(filp, &lock);
}
/*
diff -urpNX dontdiff linux-2.5.48/include/linux/fs.h linux-2.5.48-flock/include/linux/fs.h
--- linux-2.5.48/include/linux/fs.h 2002-11-17 23:29:29.000000000 -0500
+++ linux-2.5.48-flock/include/linux/fs.h 2002-11-19 19:24:41.000000000 -0500
@@ -540,8 +540,6 @@ struct file_lock {
loff_t fl_end;
void (*fl_notify)(struct file_lock *); /* unblock callback */
- void (*fl_insert)(struct file_lock *); /* lock insertion callback */
- void (*fl_remove)(struct file_lock *); /* lock removal callback */
struct fasync_struct * fl_fasync; /* for lease break notifications */
unsigned long fl_break_time; /* for nonblocking lease breaks */
@@ -734,6 +732,42 @@ typedef struct {
typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long);
+/**
+ * struct lock_operations - filesystem hooks for file locking
+ *
+ * This struct is a work in progress. It is intended to be per-filesystem;
+ * indeed it could be part of f_ops were it not pure bloat for non-network
+ * filesystems. I suspect lock_insert and lock_remove are now unnecessary,
+ * but need feedback from FS maintainers.
+ *
+ * @set_lock:
+ * Attempt to set a new lock. BKL not held, may sleep.
+ * @get_lock:
+ * Return any lock which would conflict with the incoming lock.
+ * No locks held, may sleep.
+ * @remove_posix:
+ * A process closed a file descriptor. Any locks on this @filp owned
+ * by @owner should be removed. BKL not held, may sleep.
+ * @remove_flock:
+ * This @filp has been closed. All locks owned by this process should
+ * be removed. BKL not held, may sleep.
+ * @lock_insert:
+ * Notification that @fl, which was previously blocked, is now being
+ * inserted. BKL might not be held. Must not sleep.
+ * @lock_remove:
+ * Notification that @fl, which was an active lock, is now being
+ * removed from the @filp. BKL might not be held. Must not sleep.
+ */
+
+struct lock_operations {
+ int (*set_lock) (struct file *filp, struct file_lock *fl);
+ int (*get_lock) (struct file *filp, struct file_lock *fl);
+ void (*remove_posix) (struct file *filp, fl_owner_t owner);
+ void (*remove_flock) (struct file *filp);
+ void (*lock_insert) (struct file_lock *fl);
+ void (*lock_remove) (struct file_lock *fl);
+};
+
/*
* NOTE:
* read, write, poll, fsync, readv, writev can be called
@@ -757,7 +791,7 @@ struct file_operations {
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
- int (*lock) (struct file *, int, struct file_lock *);
+ struct lock_operations *lock;
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
--
Revolutions do not require corporate support.
next reply other threads:[~2002-11-20 7:20 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-11-20 7:20 Matthew Wilcox [this message]
2002-11-20 17:54 ` lock_operations Trond Myklebust
2002-11-20 18:29 ` lock_operations Matthew Wilcox
2002-11-20 19:04 ` lock_operations Trond Myklebust
2002-11-21 11:16 ` lock_operations Matthew Wilcox
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20021120072050.B12656@parcelfarce.linux.theplanet.co.uk \
--to=willy@debian.org \
--cc=linux-fsdevel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.