diff options
Diffstat (limited to 'fs/nfs/file.c')
| -rw-r--r-- | fs/nfs/file.c | 61 |
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); |
