aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/file.c
diff options
context:
space:
mode:
authorSuresh Jayaraman <sjayaraman@suse.de>2010-09-23 08:55:58 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-09-23 08:55:58 -0400
commit5eebde23223aeb0ad2d9e3be6590ff8bbfab0fc2 (patch)
tree7cfabe0191855550292b0a0c9b317315dffb2a50 /fs/nfs/file.c
parent63185942c5f138c62de16b4cbc7eee494a58fea8 (diff)
nfs: introduce mount option '-olocal_lock' to make locks local
NFS clients since 2.6.12 support flock locks by emulating fcntl byte-range locks. Due to this, some windows applications which seem to use both flock (share mode lock mapped as flock by Samba) and fcntl locks sequentially on the same file, can't lock as they falsely assume the file is already locked. The problem was reported on a setup with windows clients accessing excel files on a Samba exported share which is originally a NFS mount from a NetApp filer. Older NFS clients (< 2.6.12) did not see this problem as flock locks were considered local. To support legacy flock behavior, this patch adds a mount option "-olocal_lock=" which can take the following values: 'none' - Neither flock locks nor POSIX locks are local 'flock' - flock locks are local 'posix' - fcntl/POSIX locks are local 'all' - Both flock locks and POSIX locks are local Testing: - This patch was tested by using -olocal_lock option with different values and the NLM calls were noted from the network packet captured. 'none' - NLM calls were seen during both flock() and fcntl(), flock lock was granted, fcntl was denied 'flock' - no NLM calls for flock(), NLM call was seen for fcntl(), granted 'posix' - NLM call was seen for flock() - granted, no NLM call for fcntl() 'all' - no NLM calls were seen during both flock() and fcntl() - No bugs were seen during NFSv4 locking/unlocking in general and NFSv4 reboot recovery. Cc: Neil Brown <neilb@suse.de> Signed-off-by: Suresh Jayaraman <sjayaraman@suse.de> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/file.c')
-rw-r--r--fs/nfs/file.c45
1 files changed, 32 insertions, 13 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index eb51bd6201da..59cbe1ba0511 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -684,7 +684,8 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
684 return ret; 684 return ret;
685} 685}
686 686
687static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) 687static int
688do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
688{ 689{
689 struct inode *inode = filp->f_mapping->host; 690 struct inode *inode = filp->f_mapping->host;
690 int status = 0; 691 int status = 0;
@@ -699,7 +700,7 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
699 if (nfs_have_delegation(inode, FMODE_READ)) 700 if (nfs_have_delegation(inode, FMODE_READ))
700 goto out_noconflict; 701 goto out_noconflict;
701 702
702 if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM) 703 if (is_local)
703 goto out_noconflict; 704 goto out_noconflict;
704 705
705 status = NFS_PROTO(inode)->lock(filp, cmd, fl); 706 status = NFS_PROTO(inode)->lock(filp, cmd, fl);
@@ -730,7 +731,8 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
730 return res; 731 return res;
731} 732}
732 733
733static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) 734static int
735do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
734{ 736{
735 struct inode *inode = filp->f_mapping->host; 737 struct inode *inode = filp->f_mapping->host;
736 int status; 738 int status;
@@ -745,15 +747,19 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
745 * If we're signalled while cleaning up locks on process exit, we 747 * If we're signalled while cleaning up locks on process exit, we
746 * still need to complete the unlock. 748 * still need to complete the unlock.
747 */ 749 */
748 /* Use local locking if mounted with "-onolock" */ 750 /*
749 if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) 751 * Use local locking if mounted with "-onolock" or with appropriate
752 * "-olocal_lock="
753 */
754 if (!is_local)
750 status = NFS_PROTO(inode)->lock(filp, cmd, fl); 755 status = NFS_PROTO(inode)->lock(filp, cmd, fl);
751 else 756 else
752 status = do_vfs_lock(filp, fl); 757 status = do_vfs_lock(filp, fl);
753 return status; 758 return status;
754} 759}
755 760
756static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) 761static int
762do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
757{ 763{
758 struct inode *inode = filp->f_mapping->host; 764 struct inode *inode = filp->f_mapping->host;
759 int status; 765 int status;
@@ -766,8 +772,11 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
766 if (status != 0) 772 if (status != 0)
767 goto out; 773 goto out;
768 774
769 /* Use local locking if mounted with "-onolock" */ 775 /*
770 if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) 776 * Use local locking if mounted with "-onolock" or with appropriate
777 * "-olocal_lock="
778 */
779 if (!is_local)
771 status = NFS_PROTO(inode)->lock(filp, cmd, fl); 780 status = NFS_PROTO(inode)->lock(filp, cmd, fl);
772 else 781 else
773 status = do_vfs_lock(filp, fl); 782 status = do_vfs_lock(filp, fl);
@@ -791,6 +800,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
791{ 800{
792 struct inode *inode = filp->f_mapping->host; 801 struct inode *inode = filp->f_mapping->host;
793 int ret = -ENOLCK; 802 int ret = -ENOLCK;
803 int is_local = 0;
794 804
795 dprintk("NFS: lock(%s/%s, t=%x, fl=%x, r=%lld:%lld)\n", 805 dprintk("NFS: lock(%s/%s, t=%x, fl=%x, r=%lld:%lld)\n",
796 filp->f_path.dentry->d_parent->d_name.name, 806 filp->f_path.dentry->d_parent->d_name.name,
@@ -804,6 +814,9 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
804 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) 814 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
805 goto out_err; 815 goto out_err;
806 816
817 if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FCNTL)
818 is_local = 1;
819
807 if (NFS_PROTO(inode)->lock_check_bounds != NULL) { 820 if (NFS_PROTO(inode)->lock_check_bounds != NULL) {
808 ret = NFS_PROTO(inode)->lock_check_bounds(fl); 821 ret = NFS_PROTO(inode)->lock_check_bounds(fl);
809 if (ret < 0) 822 if (ret < 0)
@@ -811,11 +824,11 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
811 } 824 }
812 825
813 if (IS_GETLK(cmd)) 826 if (IS_GETLK(cmd))
814 ret = do_getlk(filp, cmd, fl); 827 ret = do_getlk(filp, cmd, fl, is_local);
815 else if (fl->fl_type == F_UNLCK) 828 else if (fl->fl_type == F_UNLCK)
816 ret = do_unlk(filp, cmd, fl); 829 ret = do_unlk(filp, cmd, fl, is_local);
817 else 830 else
818 ret = do_setlk(filp, cmd, fl); 831 ret = do_setlk(filp, cmd, fl, is_local);
819out_err: 832out_err:
820 return ret; 833 return ret;
821} 834}
@@ -825,6 +838,9 @@ out_err:
825 */ 838 */
826static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) 839static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
827{ 840{
841 struct inode *inode = filp->f_mapping->host;
842 int is_local = 0;
843
828 dprintk("NFS: flock(%s/%s, t=%x, fl=%x)\n", 844 dprintk("NFS: flock(%s/%s, t=%x, fl=%x)\n",
829 filp->f_path.dentry->d_parent->d_name.name, 845 filp->f_path.dentry->d_parent->d_name.name,
830 filp->f_path.dentry->d_name.name, 846 filp->f_path.dentry->d_name.name,
@@ -833,14 +849,17 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
833 if (!(fl->fl_flags & FL_FLOCK)) 849 if (!(fl->fl_flags & FL_FLOCK))
834 return -ENOLCK; 850 return -ENOLCK;
835 851
852 if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FLOCK)
853 is_local = 1;
854
836 /* We're simulating flock() locks using posix locks on the server */ 855 /* We're simulating flock() locks using posix locks on the server */
837 fl->fl_owner = (fl_owner_t)filp; 856 fl->fl_owner = (fl_owner_t)filp;
838 fl->fl_start = 0; 857 fl->fl_start = 0;
839 fl->fl_end = OFFSET_MAX; 858 fl->fl_end = OFFSET_MAX;
840 859
841 if (fl->fl_type == F_UNLCK) 860 if (fl->fl_type == F_UNLCK)
842 return do_unlk(filp, cmd, fl); 861 return do_unlk(filp, cmd, fl, is_local);
843 return do_setlk(filp, cmd, fl); 862 return do_setlk(filp, cmd, fl, is_local);
844} 863}
845 864
846/* 865/*