summaryrefslogtreecommitdiff
path: root/fs/nfs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/file.c')
-rw-r--r--fs/nfs/file.c61
1 files changed, 53 insertions, 8 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 57ccbd277fce..bae0528bad8a 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -44,6 +44,8 @@ static ssize_t nfs_file_write(struct kiocb *, const char __user *, size_t, loff_
static int nfs_file_flush(struct file *);
static int nfs_fsync(struct file *, struct dentry *dentry, int datasync);
static int nfs_check_flags(int flags);
+static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
+static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
struct file_operations nfs_file_operations = {
.llseek = remote_llseek,
@@ -57,6 +59,7 @@ struct file_operations nfs_file_operations = {
.release = nfs_file_release,
.fsync = nfs_fsync,
.lock = nfs_lock,
+ .flock = nfs_flock,
.sendfile = nfs_file_sendfile,
.check_flags = nfs_check_flags,
};
@@ -312,6 +315,25 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
return status;
}
+static int do_vfs_lock(struct file *file, struct file_lock *fl)
+{
+ int res = 0;
+ switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
+ case FL_POSIX:
+ res = posix_lock_file_wait(file, fl);
+ break;
+ case FL_FLOCK:
+ res = flock_lock_file_wait(file, fl);
+ break;
+ default:
+ BUG();
+ }
+ if (res < 0)
+ printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
+ __FUNCTION__);
+ return res;
+}
+
static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
{
struct inode *inode = filp->f_mapping->host;
@@ -338,7 +360,7 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
status = NFS_PROTO(inode)->lock(filp, cmd, fl);
else
- status = posix_lock_file_wait(filp, fl);
+ status = do_vfs_lock(filp, fl);
unlock_kernel();
rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset);
return status;
@@ -377,9 +399,9 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
* the process exits.
*/
if (status == -EINTR || status == -ERESTARTSYS)
- posix_lock_file_wait(filp, fl);
+ do_vfs_lock(filp, fl);
} else
- status = posix_lock_file_wait(filp, fl);
+ status = do_vfs_lock(filp, fl);
unlock_kernel();
if (status < 0)
goto out;
@@ -401,8 +423,7 @@ out:
/*
* Lock a (portion of) a file
*/
-int
-nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
+static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
{
struct inode * inode = filp->f_mapping->host;
@@ -418,6 +439,27 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
return -ENOLCK;
+ if (IS_GETLK(cmd))
+ return do_getlk(filp, cmd, fl);
+ if (fl->fl_type == F_UNLCK)
+ return do_unlk(filp, cmd, fl);
+ return do_setlk(filp, cmd, fl);
+}
+
+/*
+ * Lock a (portion of) a file
+ */
+static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
+{
+ struct inode * inode = filp->f_mapping->host;
+
+ dprintk("NFS: nfs_flock(f=%s/%ld, t=%x, fl=%x)\n",
+ inode->i_sb->s_id, inode->i_ino,
+ fl->fl_type, fl->fl_flags);
+
+ if (!inode)
+ return -EINVAL;
+
/*
* No BSD flocks over NFS allowed.
* Note: we could try to fake a POSIX lock request here by
@@ -425,11 +467,14 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
* Not sure whether that would be unique, though, or whether
* that would break in other places.
*/
- if (!fl->fl_owner || !(fl->fl_flags & FL_POSIX))
+ if (!(fl->fl_flags & FL_FLOCK))
return -ENOLCK;
- if (IS_GETLK(cmd))
- return do_getlk(filp, cmd, fl);
+ /* We're simulating flock() locks using posix locks on the server */
+ fl->fl_owner = (fl_owner_t)filp;
+ fl->fl_start = 0;
+ fl->fl_end = OFFSET_MAX;
+
if (fl->fl_type == F_UNLCK)
return do_unlk(filp, cmd, fl);
return do_setlk(filp, cmd, fl);