From: Trond Myklebust This makes for an interesting situation in which programs compiled to use flock() and running on the server will not see the locks that are set by the clients. The clients will, however, see both POSIX and flock() locks set by other clients. It is the best you can do, given the limitations of the protocol. Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton --- 25-akpm/fs/lockd/clntproc.c | 26 ++++++++++++++--- 25-akpm/fs/nfs/file.c | 61 +++++++++++++++++++++++++++++++++++------ 25-akpm/fs/nfs/nfs4proc.c | 23 ++++++++++++++- 25-akpm/include/linux/nfs_fs.h | 5 --- 4 files changed, 95 insertions(+), 20 deletions(-) diff -puN fs/lockd/clntproc.c~nfs-flock fs/lockd/clntproc.c --- 25/fs/lockd/clntproc.c~nfs-flock 2005-01-23 01:19:54.282025296 -0800 +++ 25-akpm/fs/lockd/clntproc.c 2005-01-23 01:19:54.291023928 -0800 @@ -516,6 +516,24 @@ static void nlmclnt_locks_init_private(s fl->fl_ops = &nlmclnt_lock_ops; } +static void do_vfs_lock(struct file_lock *fl) +{ + int res = 0; + switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) { + case FL_POSIX: + res = posix_lock_file_wait(fl->fl_file, fl); + break; + case FL_FLOCK: + res = flock_lock_file_wait(fl->fl_file, fl); + break; + default: + BUG(); + } + if (res < 0) + printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", + __FUNCTION__); +} + /* * LOCK: Try to create a lock * @@ -564,9 +582,7 @@ 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_flags |= FL_SLEEP; - if (posix_lock_file_wait(fl->fl_file, fl) < 0) - printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", - __FUNCTION__); + do_vfs_lock(fl); } status = nlm_stat_to_errno(resp->status); out: @@ -635,7 +651,7 @@ nlmclnt_unlock(struct nlm_rqst *req, str nlmclnt_unlock_callback); /* Hrmf... Do the unlock early since locks_remove_posix() * really expects us to free the lock synchronously */ - posix_lock_file(fl->fl_file, fl); + do_vfs_lock(fl); if (status < 0) { nlmclnt_release_lockargs(req); kfree(req); @@ -648,7 +664,7 @@ nlmclnt_unlock(struct nlm_rqst *req, str if (status < 0) return status; - posix_lock_file(fl->fl_file, fl); + do_vfs_lock(fl); if (resp->status == NLM_LCK_GRANTED) return 0; diff -puN fs/nfs/file.c~nfs-flock fs/nfs/file.c --- 25/fs/nfs/file.c~nfs-flock 2005-01-23 01:19:54.283025144 -0800 +++ 25-akpm/fs/nfs/file.c 2005-01-23 01:19:54.292023776 -0800 @@ -44,6 +44,8 @@ static ssize_t nfs_file_write(struct kio 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_operatio .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, i 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, in 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, i * 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, str 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, str * 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); diff -puN fs/nfs/nfs4proc.c~nfs-flock fs/nfs/nfs4proc.c --- 25/fs/nfs/nfs4proc.c~nfs-flock 2005-01-23 01:19:54.285024840 -0800 +++ 25-akpm/fs/nfs/nfs4proc.c 2005-01-23 01:19:54.295023320 -0800 @@ -2361,6 +2361,25 @@ static int nfs4_proc_getlk(struct nfs4_s return err; } +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 _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) { struct inode *inode = state->inode; @@ -2408,7 +2427,7 @@ static int _nfs4_proc_unlck(struct nfs4_ out: up(&state->lock_sema); if (status == 0) - posix_lock_file(request->fl_file, request); + do_vfs_lock(request->fl_file, request); up_read(&clp->cl_sem); return status; } @@ -2517,7 +2536,7 @@ static int _nfs4_proc_setlk(struct nfs4_ if (status == 0) { /* Note: we always want to sleep here! */ request->fl_flags |= FL_SLEEP; - if (posix_lock_file_wait(request->fl_file, request) < 0) + if (do_vfs_lock(request->fl_file, request) < 0) printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); } up_read(&clp->cl_sem); diff -puN include/linux/nfs_fs.h~nfs-flock include/linux/nfs_fs.h --- 25/include/linux/nfs_fs.h~nfs-flock 2005-01-23 01:19:54.287024536 -0800 +++ 25-akpm/include/linux/nfs_fs.h 2005-01-23 01:19:54.293023624 -0800 @@ -351,11 +351,6 @@ extern struct dentry_operations nfs_dent extern struct inode_operations nfs_symlink_inode_operations; /* - * linux/fs/nfs/locks.c - */ -extern int nfs_lock(struct file *, int, struct file_lock *); - -/* * linux/fs/nfs/unlink.c */ extern int nfs_async_unlink(struct dentry *); _