[linux-cifs-client] [PATCH 4/5] cifs: take reference to inode for oplock breaks
Shirish Pargaonkar
shirishpargaonkar at gmail.com
Mon Aug 31 09:17:15 MDT 2009
On Mon, Aug 31, 2009 at 9:41 AM, Jeff Layton<jlayton at redhat.com> wrote:
> On Fri, 28 Aug 2009 14:53:19 -0500
> Shirish Pargaonkar <shirishpargaonkar at gmail.com> wrote:
>
>> On Tue, Aug 18, 2009 at 1:07 PM, Jeff Layton<jlayton at redhat.com> wrote:
>> > When an oplock break comes in, cifs needs to do things like write out
>> > dirty data for it. It doesn't hold a reference to that inode in this
>> > case however. Get an active reference to the inode when an oplock break
>> > comes in. If we don't get a reference, we still need to create an oplock
>> > queue entry so that the oplock release call gets done, but we'll want to
>> > skip writeback in that case.
>> >
>> > Signed-off-by: Jeff Layton <jlayton at redhat.com>
>> > ---
>> > fs/cifs/cifsfs.c | 26 ++++++++++----------------
>> > fs/cifs/misc.c | 4 +++-
>> > 2 files changed, 13 insertions(+), 17 deletions(-)
>> >
>> > diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
>> > index 2fcc722..647c5bc 100644
>> > --- a/fs/cifs/cifsfs.c
>> > +++ b/fs/cifs/cifsfs.c
>> > @@ -993,13 +993,8 @@ static int cifs_oplock_thread(void *dummyarg)
>> > cFYI(1, ("found oplock item to write out"));
>> > tcon = oplock->tcon;
>> > inode = oplock->pinode;
>> > - /* can not grab inode sem here since it would
>> > - deadlock when oplock received on delete
>> > - since vfs_unlink holds the i_mutex across
>> > - the call */
>> > - /* mutex_lock(&inode->i_mutex);*/
>> > - cifsi = CIFS_I(inode);
>> > - if (S_ISREG(inode->i_mode)) {
>> > + if (inode && S_ISREG(inode->i_mode)) {
>> > + cifsi = CIFS_I(inode);
>> > #ifdef CONFIG_CIFS_EXPERIMENTAL
>> > if (cifsi->clientCanCacheAll == 0)
>> > break_lease(inode, FMODE_READ);
>> > @@ -1010,17 +1005,16 @@ static int cifs_oplock_thread(void *dummyarg)
>> > if (cifsi->clientCanCacheRead == 0) {
>> > waitrc = filemap_fdatawait(
>> > inode->i_mapping);
>> > + if (rc == 0)
>> > + rc = waitrc;
>> > invalidate_remote_inode(inode);
>> > }
>> > - if (rc == 0)
>> > - rc = waitrc;
>> > - } else
>> > - rc = 0;
>> > - /* mutex_unlock(&inode->i_mutex);*/
>> > - if (rc)
>> > - cifsi->write_behind_rc = rc;
>> > - cFYI(1, ("Oplock flush inode %p rc %d",
>> > - inode, rc));
>> > + if (rc)
>> > + cifsi->write_behind_rc = rc;
>> > + cFYI(1, ("Oplock flush inode %p rc %d",
>> > + inode, rc));
>> > + }
>> > + iput(inode);
>> >
>> > /*
>> > * releasing stale oplock after recent reconnect
>> > diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
>> > index 7221af9..3bf3a52 100644
>> > --- a/fs/cifs/misc.c
>> > +++ b/fs/cifs/misc.c
>> > @@ -502,6 +502,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv,
>> > struct cifsInodeInfo *pCifsInode;
>> > struct cifsFileInfo *netfile;
>> > struct oplock_q_entry *oplock;
>> > + struct inode *inode;
>> >
>> > cFYI(1, ("Checking for oplock break or dnotify response"));
>> > if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
>> > @@ -600,6 +601,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv,
>> > pCifsInode->clientCanCacheAll = false;
>> > if (pSMB->OplockLevel == 0)
>> > pCifsInode->clientCanCacheRead = false;
>> > + inode = igrab(netfile->pInode);
>> >
>> > if (!oplock) {
>> > cERROR(1, ("Unable to allocate "
>> > @@ -608,7 +610,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv,
>> > }
>> >
>> > oplock->tcon = tcon;
>> > - oplock->pinode = netfile->pInode;
>> > + oplock->pinode = inode;
>> > oplock->netfid = netfile->netfid;
>> > spin_lock(&cifs_oplock_lock);
>> > list_add_tail(&oplock->qhead,
>> > --
>> > 1.6.0.6
>> >
>
> Just found a bug with this patch. It takes an inode reference even if
> an oplock queue entry couldn't be allocated. The fix is simple (just
> move the igrab to later in the function). Replacement patch is attached.
>
> --
> Jeff Layton <jlayton at redhat.com>
>
Acked-by: Shirish Pargaonkar <shirishpargaonkar at gmail.com>
More information about the linux-cifs-client
mailing list