aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-10-23 00:42:37 -0400
committerSteve French <sfrench@us.ibm.com>2008-10-23 00:42:37 -0400
commit84210e9120a8c01a14379ba1f9a9b0f963641d94 (patch)
treeed20b210bb554f283d8458ee6d146a5c4439e37f
parenta364bc0b37f14ffd66c1f982af42990a9d77fa43 (diff)
[CIFS] improve setlease handling
fcntl(F_SETLEASE) currently is not exported by cifs (nor by local file systems) so cifs grants leases based on how other local processes have opened the file not by whether the file is cacheable (oplocked). This adds the check to make sure that the file is cacheable on the client before checking whether we can grant the lease locally (generic_setlease). It also adds a mount option for cifs (locallease) if the user wants to override this and try to grant leases even if the server did not grant oplock. Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/CHANGES3
-rw-r--r--fs/cifs/README16
-rw-r--r--fs/cifs/cifsfs.c41
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/connect.c8
5 files changed, 67 insertions, 2 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index a7255751ffbc..8f528ea24c48 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -3,7 +3,8 @@ Version 1.55
3Various fixes to make delete of open files behavior more predictable 3Various fixes to make delete of open files behavior more predictable
4(when delete of an open file fails we mark the file as "delete-on-close" 4(when delete of an open file fails we mark the file as "delete-on-close"
5in a way that more servers accept, but only if we can first rename the 5in a way that more servers accept, but only if we can first rename the
6file to a temporary name) 6file to a temporary name). Add experimental support for more safely
7handling fcntl(F_SETLEASE).
7 8
8Version 1.54 9Version 1.54
9------------ 10------------
diff --git a/fs/cifs/README b/fs/cifs/README
index cbe26fe40120..a439dc1739b3 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -491,6 +491,19 @@ A partial list of the supported mount options follows:
491 Note that this differs from the sign mount option in that it 491 Note that this differs from the sign mount option in that it
492 causes encryption of data sent over this mounted share but other 492 causes encryption of data sent over this mounted share but other
493 shares mounted to the same server are unaffected. 493 shares mounted to the same server are unaffected.
494 locallease This option is rarely needed. Fcntl F_SETLEASE is
495 used by some applications such as Samba and NFSv4 server to
496 check to see whether a file is cacheable. CIFS has no way
497 to explicitly request a lease, but can check whether a file
498 is cacheable (oplocked). Unfortunately, even if a file
499 is not oplocked, it could still be cacheable (ie cifs client
500 could grant fcntl leases if no other local processes are using
501 the file) for cases for example such as when the server does not
502 support oplocks and the user is sure that the only updates to
503 the file will be from this client. Specifying this mount option
504 will allow the cifs client to check for leases (only) locally
505 for files which are not oplocked instead of denying leases
506 in that case. (EXPERIMENTAL)
494 sec Security mode. Allowed values are: 507 sec Security mode. Allowed values are:
495 none attempt to connection as a null user (no name) 508 none attempt to connection as a null user (no name)
496 krb5 Use Kerberos version 5 authentication 509 krb5 Use Kerberos version 5 authentication
@@ -641,6 +654,9 @@ requires enabling CONFIG_CIFS_EXPERIMENTAL
641 cifsacl support needed to retrieve approximated mode bits based on 654 cifsacl support needed to retrieve approximated mode bits based on
642 the contents on the CIFS ACL. 655 the contents on the CIFS ACL.
643 656
657 lease support: cifs will check the oplock state before calling into
658 the vfs to see if we can grant a lease on a file.
659
644 DNOTIFY fcntl: needed for support of directory change 660 DNOTIFY fcntl: needed for support of directory change
645 notification and perhaps later for file leases) 661 notification and perhaps later for file leases)
646 662
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index c6aad775dd6d..76919c25acc7 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -618,6 +618,37 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
618 return generic_file_llseek_unlocked(file, offset, origin); 618 return generic_file_llseek_unlocked(file, offset, origin);
619} 619}
620 620
621#ifdef CONFIG_CIFS_EXPERIMENTAL
622static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
623{
624 /* note that this is called by vfs setlease with the BKL held
625 although I doubt that BKL is needed here in cifs */
626 struct inode *inode = file->f_path.dentry->d_inode;
627
628 if (!(S_ISREG(inode->i_mode)))
629 return -EINVAL;
630
631 /* check if file is oplocked */
632 if (((arg == F_RDLCK) &&
633 (CIFS_I(inode)->clientCanCacheRead)) ||
634 ((arg == F_WRLCK) &&
635 (CIFS_I(inode)->clientCanCacheAll)))
636 return generic_setlease(file, arg, lease);
637 else if (CIFS_SB(inode->i_sb)->tcon->local_lease &&
638 !CIFS_I(inode)->clientCanCacheRead)
639 /* If the server claims to support oplock on this
640 file, then we still need to check oplock even
641 if the local_lease mount option is set, but there
642 are servers which do not support oplock for which
643 this mount option may be useful if the user
644 knows that the file won't be changed on the server
645 by anyone else */
646 return generic_setlease(file, arg, lease);
647 else
648 return -EAGAIN;
649}
650#endif
651
621struct file_system_type cifs_fs_type = { 652struct file_system_type cifs_fs_type = {
622 .owner = THIS_MODULE, 653 .owner = THIS_MODULE,
623 .name = "cifs", 654 .name = "cifs",
@@ -696,6 +727,7 @@ const struct file_operations cifs_file_ops = {
696 727
697#ifdef CONFIG_CIFS_EXPERIMENTAL 728#ifdef CONFIG_CIFS_EXPERIMENTAL
698 .dir_notify = cifs_dir_notify, 729 .dir_notify = cifs_dir_notify,
730 .setlease = cifs_setlease,
699#endif /* CONFIG_CIFS_EXPERIMENTAL */ 731#endif /* CONFIG_CIFS_EXPERIMENTAL */
700}; 732};
701 733
@@ -716,6 +748,7 @@ const struct file_operations cifs_file_direct_ops = {
716 .llseek = cifs_llseek, 748 .llseek = cifs_llseek,
717#ifdef CONFIG_CIFS_EXPERIMENTAL 749#ifdef CONFIG_CIFS_EXPERIMENTAL
718 .dir_notify = cifs_dir_notify, 750 .dir_notify = cifs_dir_notify,
751 .setlease = cifs_setlease,
719#endif /* CONFIG_CIFS_EXPERIMENTAL */ 752#endif /* CONFIG_CIFS_EXPERIMENTAL */
720}; 753};
721const struct file_operations cifs_file_nobrl_ops = { 754const struct file_operations cifs_file_nobrl_ops = {
@@ -736,6 +769,7 @@ const struct file_operations cifs_file_nobrl_ops = {
736 769
737#ifdef CONFIG_CIFS_EXPERIMENTAL 770#ifdef CONFIG_CIFS_EXPERIMENTAL
738 .dir_notify = cifs_dir_notify, 771 .dir_notify = cifs_dir_notify,
772 .setlease = cifs_setlease,
739#endif /* CONFIG_CIFS_EXPERIMENTAL */ 773#endif /* CONFIG_CIFS_EXPERIMENTAL */
740}; 774};
741 775
@@ -755,6 +789,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
755 .llseek = cifs_llseek, 789 .llseek = cifs_llseek,
756#ifdef CONFIG_CIFS_EXPERIMENTAL 790#ifdef CONFIG_CIFS_EXPERIMENTAL
757 .dir_notify = cifs_dir_notify, 791 .dir_notify = cifs_dir_notify,
792 .setlease = cifs_setlease,
758#endif /* CONFIG_CIFS_EXPERIMENTAL */ 793#endif /* CONFIG_CIFS_EXPERIMENTAL */
759}; 794};
760 795
@@ -946,6 +981,12 @@ static int cifs_oplock_thread(void *dummyarg)
946 the call */ 981 the call */
947 /* mutex_lock(&inode->i_mutex);*/ 982 /* mutex_lock(&inode->i_mutex);*/
948 if (S_ISREG(inode->i_mode)) { 983 if (S_ISREG(inode->i_mode)) {
984#ifdef CONFIG_CIFS_EXPERIMENTAL
985 if (CIFS_I(inode)->clientCanCacheAll == 0)
986 break_lease(inode, FMODE_READ);
987 else if (CIFS_I(inode)->clientCanCacheRead == 0)
988 break_lease(inode, FMODE_WRITE);
989#endif
949 rc = filemap_fdatawrite(inode->i_mapping); 990 rc = filemap_fdatawrite(inode->i_mapping);
950 if (CIFS_I(inode)->clientCanCacheRead == 0) { 991 if (CIFS_I(inode)->clientCanCacheRead == 0) {
951 waitrc = filemap_fdatawait( 992 waitrc = filemap_fdatawait(
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 178f733a368f..c791e5b5a914 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -285,6 +285,7 @@ struct cifsTconInfo {
285 bool seal:1; /* transport encryption for this mounted share */ 285 bool seal:1; /* transport encryption for this mounted share */
286 bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol 286 bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol
287 for this mount even if server would support */ 287 for this mount even if server would support */
288 bool local_lease:1; /* check leases (only) on local system not remote */
288 /* BB add field for back pointer to sb struct(s)? */ 289 /* BB add field for back pointer to sb struct(s)? */
289}; 290};
290 291
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 1126f7ab4606..f51b79a67e1b 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -90,7 +90,8 @@ struct smb_vol {
90 bool nocase:1; /* request case insensitive filenames */ 90 bool nocase:1; /* request case insensitive filenames */
91 bool nobrl:1; /* disable sending byte range locks to srv */ 91 bool nobrl:1; /* disable sending byte range locks to srv */
92 bool seal:1; /* request transport encryption on share */ 92 bool seal:1; /* request transport encryption on share */
93 bool nodfs:1; 93 bool nodfs:1; /* Do not request DFS, even if available */
94 bool local_lease:1; /* check leases only on local system, not remote */
94 unsigned int rsize; 95 unsigned int rsize;
95 unsigned int wsize; 96 unsigned int wsize;
96 unsigned int sockopt; 97 unsigned int sockopt;
@@ -1264,6 +1265,10 @@ cifs_parse_mount_options(char *options, const char *devname,
1264 vol->no_psx_acl = 0; 1265 vol->no_psx_acl = 0;
1265 } else if (strnicmp(data, "noacl", 5) == 0) { 1266 } else if (strnicmp(data, "noacl", 5) == 0) {
1266 vol->no_psx_acl = 1; 1267 vol->no_psx_acl = 1;
1268#ifdef CONFIG_CIFS_EXPERIMENTAL
1269 } else if (strnicmp(data, "locallease", 6) == 0) {
1270 vol->local_lease = 1;
1271#endif
1267 } else if (strnicmp(data, "sign", 4) == 0) { 1272 } else if (strnicmp(data, "sign", 4) == 0) {
1268 vol->secFlg |= CIFSSEC_MUST_SIGN; 1273 vol->secFlg |= CIFSSEC_MUST_SIGN;
1269 } else if (strnicmp(data, "seal", 4) == 0) { 1274 } else if (strnicmp(data, "seal", 4) == 0) {
@@ -2162,6 +2167,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2162 for the retry flag is used */ 2167 for the retry flag is used */
2163 tcon->retry = volume_info.retry; 2168 tcon->retry = volume_info.retry;
2164 tcon->nocase = volume_info.nocase; 2169 tcon->nocase = volume_info.nocase;
2170 tcon->local_lease = volume_info.local_lease;
2165 if (tcon->seal != volume_info.seal) 2171 if (tcon->seal != volume_info.seal)
2166 cERROR(1, ("transport encryption setting " 2172 cERROR(1, ("transport encryption setting "
2167 "conflicts with existing tid")); 2173 "conflicts with existing tid"));