+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
- 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
/*
- * 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;
+/**
+ * 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 *);