[linux-cifs-client] Re: [RFC] patch to add support for leases to
cifs
J. Bruce Fields
bfields at fieldses.org
Thu Oct 23 18:49:15 GMT 2008
On Wed, Oct 22, 2008 at 05:47:46PM -0400, J. Bruce Fields wrote:
> 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.
More annoying: if there's a local lease, and someone local breaks it,
then I think they're going to block in break_lease() up to the time
given by that sysctl, before they even call into the filesystem.
So a little better coordination with the filesystem is going to be
needed before we get lease breaking completely right.
--b.
>
> --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
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the linux-cifs-client
mailing list