]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
[CIFS] Fix oops when slow oplock process races with unmount
authorSteve French <sfrench@us.ibm.com>
Tue, 15 Apr 2008 18:40:48 +0000 (18:40 +0000)
committerSteve French <sfrench@us.ibm.com>
Tue, 15 Apr 2008 18:40:48 +0000 (18:40 +0000)
If a tcon is being freed in call tconInfoFree, clean up any entries that may
exist in global oplock queue as the tcon structure hanging off of those entries
will be invalid and can cause oops while accesing any elements in the
tcon structure.

Signed-off-by: Shirish Pargaonkar <shirishp@us.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/transport.c

index 7e5e0e78cd72c1c051ef5e23957de768687a664d..0c83da4a7dabe10017ab31d4de41002bbc78d318 100644 (file)
@@ -84,6 +84,7 @@ extern __u16 GetNextMid(struct TCP_Server_Info *server);
 extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16,
                                                 struct cifsTconInfo *);
 extern void DeleteOplockQEntry(struct oplock_q_entry *);
+extern void DeleteTconOplockQEntries(struct cifsTconInfo *);
 extern struct timespec cifs_NTtimeToUnix(u64 utc_nanoseconds_since_1601);
 extern u64 cifs_UnixTimeToNT(struct timespec);
 extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
index 8dbfa97cd18ca6ae60ba6621e8e9214cb7a1641d..e171067301689dee90ed97de96fc2fcb7eb3f518 100644 (file)
@@ -3527,6 +3527,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
                        FreeXid(xid);
                        return 0;
                }
+               DeleteTconOplockQEntries(cifs_sb->tcon);
                tconInfoFree(cifs_sb->tcon);
                if ((ses) && (ses->server)) {
                        /* save off task so we do not refer to ses later */
index 3612d6c0a0bbc1a4c9f64c2ce0f674517ce86d72..000ac509c98a32e884322149e88b53e4bdb2a4c1 100644 (file)
@@ -142,6 +142,24 @@ void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
        kmem_cache_free(cifs_oplock_cachep, oplockEntry);
 }
 
+
+void DeleteTconOplockQEntries(struct cifsTconInfo *tcon)
+{
+       struct oplock_q_entry *temp;
+
+       if (tcon == NULL)
+               return;
+
+       spin_lock(&GlobalMid_Lock);
+       list_for_each_entry(temp, &GlobalOplock_Q, qhead) {
+               if ((temp->tcon) && (temp->tcon == tcon)) {
+                       list_del(&temp->qhead);
+                       kmem_cache_free(cifs_oplock_cachep, temp);
+               }
+       }
+       spin_unlock(&GlobalMid_Lock);
+}
+
 int
 smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
         unsigned int smb_buf_length, struct sockaddr *sin)