[linux-cifs-client] Re: [RFC] patch to add support for leases to
cifs
J. Bruce Fields
bfields at fieldses.org
Wed Oct 22 21:47:46 GMT 2008
On Wed, Oct 22, 2008 at 03:31:06PM -0500, Steve French wrote:
> Oplock is a guarantee that no one else is changing (or reading) a
> file. The notification that a file is now changing is different (that
> is SMB change notify), Oplock is a guarantee that you are the only
> writer (or reader/writer) of the file - so if the server wants to
> revoke that (oplock break) - and with the patch we call break_lease
> and don't return on the oplock break until break_lease returns, and
> __break_lease in fs/locks.c looks synchronous - break_lease async?
Ah! Yes, you're right. nfsd always calls break_lease with
O_NONBLOCK....
Makes sense to me, then.
> By the way, the server also gives up on the client if it does not
> respond (but this is a long time - more than 20 seconds for most
> servers) - presumably by flushing the dirty pages, the issues the
> oplock break response.
So it's a little irritating that the server's timeout may not agree with
the local timeout set by that sysctl. I suppose the lease timeout
should really be a characteristic of the filesystem rather than a global
thing.
--b.
>
> Following is an updated patch to add support for mount option to
> disable the check for oplock (since not all server support oplock):
>
> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
> index c6aad77..76919c2 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)
> return generic_file_llseek_unlocked(file, offset, origin);
> }
>
> +#ifdef CONFIG_CIFS_EXPERIMENTAL
> +static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
> +{
> + /* note that this is called by vfs setlease with the BKL held
> + although I doubt that BKL is needed here in cifs */
> + struct inode *inode = file->f_path.dentry->d_inode;
> +
> + if (!(S_ISREG(inode->i_mode)))
> + return -EINVAL;
> +
> + /* check if file is oplocked */
> + if (((arg == F_RDLCK) &&
> + (CIFS_I(inode)->clientCanCacheRead)) ||
> + ((arg == F_WRLCK) &&
> + (CIFS_I(inode)->clientCanCacheAll)))
> + return generic_setlease(file, arg, lease);
> + else if (CIFS_SB(inode->i_sb)->tcon->local_lease &&
> + !CIFS_I(inode)->clientCanCacheRead)
> + /* If the server claims to support oplock on this
> + file, then we still need to check oplock even
> + if the local_lease mount option is set, but there
> + are servers which do not support oplock for which
> + this mount option may be useful if the user
> + knows that the file won't be changed on the server
> + by anyone else */
> + return generic_setlease(file, arg, lease);
> + else
> + return -EAGAIN;
> +}
> +#endif
> +
> struct file_system_type cifs_fs_type = {
> .owner = THIS_MODULE,
> .name = "cifs",
> @@ -696,6 +727,7 @@ const struct file_operations cifs_file_ops = {
>
> #ifdef CONFIG_CIFS_EXPERIMENTAL
> .dir_notify = cifs_dir_notify,
> + .setlease = cifs_setlease,
> #endif /* CONFIG_CIFS_EXPERIMENTAL */
> };
>
> @@ -716,6 +748,7 @@ const struct file_operations cifs_file_direct_ops = {
> .llseek = cifs_llseek,
> #ifdef CONFIG_CIFS_EXPERIMENTAL
> .dir_notify = cifs_dir_notify,
> + .setlease = cifs_setlease,
> #endif /* CONFIG_CIFS_EXPERIMENTAL */
> };
> const struct file_operations cifs_file_nobrl_ops = {
> @@ -736,6 +769,7 @@ const struct file_operations cifs_file_nobrl_ops = {
>
> #ifdef CONFIG_CIFS_EXPERIMENTAL
> .dir_notify = cifs_dir_notify,
> + .setlease = cifs_setlease,
> #endif /* CONFIG_CIFS_EXPERIMENTAL */
> };
>
> @@ -755,6 +789,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
> .llseek = cifs_llseek,
> #ifdef CONFIG_CIFS_EXPERIMENTAL
> .dir_notify = cifs_dir_notify,
> + .setlease = cifs_setlease,
> #endif /* CONFIG_CIFS_EXPERIMENTAL */
> };
>
> @@ -946,6 +981,12 @@ static int cifs_oplock_thread(void *dummyarg)
> the call */
> /* mutex_lock(&inode->i_mutex);*/
> if (S_ISREG(inode->i_mode)) {
> +#ifdef CONFIG_CIFS_EXPERIMENTAL
> + if (CIFS_I(inode)->clientCanCacheAll == 0)
> + break_lease(inode, FMODE_READ);
> + else if (CIFS_I(inode)->clientCanCacheRead == 0)
> + break_lease(inode, FMODE_WRITE);
> +#endif
> rc = filemap_fdatawrite(inode->i_mapping);
> if (CIFS_I(inode)->clientCanCacheRead == 0) {
> waitrc = filemap_fdatawait(
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index 178f733..c791e5b 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -285,6 +285,7 @@ struct cifsTconInfo {
> bool seal:1; /* transport encryption for this mounted share */
> bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol
> for this mount even if server would support */
> + bool local_lease:1; /* check leases (only) on local system not remote */
> /* BB add field for back pointer to sb struct(s)? */
> };
>
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 1126f7a..17058c5 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -90,7 +90,8 @@ struct smb_vol {
> bool nocase:1; /* request case insensitive filenames */
> bool nobrl:1; /* disable sending byte range locks to srv */
> bool seal:1; /* request transport encryption on share */
> - bool nodfs:1;
> + bool nodfs:1; /* Do not request DFS, even if available */
> + bool local_lease:1; /* check leases only on local system, not remote */
> unsigned int rsize;
> unsigned int wsize;
> unsigned int sockopt;
> @@ -1264,6 +1265,8 @@ cifs_parse_mount_options(char *options, const
> char *devname,
> vol->no_psx_acl = 0;
> } else if (strnicmp(data, "noacl", 5) == 0) {
> vol->no_psx_acl = 1;
> + } else if (strnicmp(data, "locallease", 6) == 0) {
> + vol->local_lease = 1;
> } else if (strnicmp(data, "sign", 4) == 0) {
> vol->secFlg |= CIFSSEC_MUST_SIGN;
> } else if (strnicmp(data, "seal", 4) == 0) {
> @@ -2162,6 +2165,7 @@ cifs_mount(struct super_block *sb, struct
> cifs_sb_info *cifs_sb,
> for the retry flag is used */
> tcon->retry = volume_info.retry;
> tcon->nocase = volume_info.nocase;
> + tcon->local_lease = volume_info.local_lease;
> if (tcon->seal != volume_info.seal)
> cERROR(1, ("transport encryption setting "
> "conflicts with existing tid"));
>
> On Wed, Oct 22, 2008 at 3:19 PM, J. Bruce Fields <bfields at fieldses.org> wrote:
> > What guarantees that no other client can modify the file as long as the
> > lease is held?
> >
> > It's not enough to break the lease as soon as you notice the file
> > changes--the holder of the lease has up to 45 seconds (configurable with
> > /proc/sys/fs/lease-break-time) to return the lease before the kernel
> > forcibly revokes it.
> >
> > --b.
>
>
>
> --
> Thanks,
>
> Steve
More information about the linux-cifs-client
mailing list