From: Trond Myklebust Signed-off-by: Trond Myklebust Signed-off-by: Andrew Morton --- 25-akpm/fs/lockd/clntproc.c | 26 ++++++++++--- 25-akpm/fs/nfs/file.c | 80 ++++++++++++++++++++++++++++++++++++++--- 25-akpm/fs/nfs/nfs4proc.c | 23 ++++++++++- 25-akpm/include/linux/nfs_fs.h | 5 -- 4 files changed, 117 insertions(+), 17 deletions(-) diff -puN fs/lockd/clntproc.c~nfs-flock fs/lockd/clntproc.c --- 25/fs/lockd/clntproc.c~nfs-flock 2005-01-18 03:26:54.074623192 -0800 +++ 25-akpm/fs/lockd/clntproc.c 2005-01-18 03:26:54.082621976 -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-18 03:26:54.075623040 -0800 +++ 25-akpm/fs/nfs/file.c 2005-01-18 03:27:27.986467808 -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,10 +423,10 @@ 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; + struct file_lock **lockp; dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n", inode->i_sb->s_id, inode->i_ino, @@ -427,6 +449,12 @@ nfs_lock(struct file *filp, int cmd, str */ if (!fl->fl_owner || !(fl->fl_flags & FL_POSIX)) return -ENOLCK; + for(lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) { + if (!((*lockp)->fl_flags & FL_FLOCK)) + continue; + if (fl->fl_owner == (*lockp)->fl_owner) + return -ENOLCK; + } if (IS_GETLK(cmd)) return do_getlk(filp, cmd, fl); @@ -434,3 +462,45 @@ nfs_lock(struct file *filp, int cmd, str 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; + struct file_lock **lockp; + + 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 + * using ((u32) filp | 0x80000000) or some such as the pid. + * Not sure whether that would be unique, though, or whether + * that would break in other places. + */ + if (!(fl->fl_flags & FL_FLOCK)) + return -ENOLCK; + + /* We're simulating flock() locks using posix locks on the server */ + fl->fl_owner = current->files; + fl->fl_start = 0; + fl->fl_end = OFFSET_MAX; + + for(lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) { + if (!((*lockp)->fl_flags & FL_POSIX)) + continue; + if (fl->fl_owner == (*lockp)->fl_owner) + return -ENOLCK; + } + + 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-18 03:26:54.077622736 -0800 +++ 25-akpm/fs/nfs/nfs4proc.c 2005-01-18 03:26:54.086621368 -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-18 03:26:54.078622584 -0800 +++ 25-akpm/include/linux/nfs_fs.h 2005-01-18 03:26:54.086621368 -0800 @@ -357,11 +357,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 *); _