Commit 5d941ca6 authored by Steve French's avatar Steve French

[CIFS] Fix oops when slow oplock process races with unmount

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: default avatarShirish Pargaonkar <shirishp@us.ibm.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent e48d199b
...@@ -84,6 +84,7 @@ extern __u16 GetNextMid(struct TCP_Server_Info *server); ...@@ -84,6 +84,7 @@ extern __u16 GetNextMid(struct TCP_Server_Info *server);
extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16, extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16,
struct cifsTconInfo *); struct cifsTconInfo *);
extern void DeleteOplockQEntry(struct oplock_q_entry *); extern void DeleteOplockQEntry(struct oplock_q_entry *);
extern void DeleteTconOplockQEntries(struct cifsTconInfo *);
extern struct timespec cifs_NTtimeToUnix(u64 utc_nanoseconds_since_1601); extern struct timespec cifs_NTtimeToUnix(u64 utc_nanoseconds_since_1601);
extern u64 cifs_UnixTimeToNT(struct timespec); extern u64 cifs_UnixTimeToNT(struct timespec);
extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time); extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
......
...@@ -3527,6 +3527,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) ...@@ -3527,6 +3527,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
FreeXid(xid); FreeXid(xid);
return 0; return 0;
} }
DeleteTconOplockQEntries(cifs_sb->tcon);
tconInfoFree(cifs_sb->tcon); tconInfoFree(cifs_sb->tcon);
if ((ses) && (ses->server)) { if ((ses) && (ses->server)) {
/* save off task so we do not refer to ses later */ /* save off task so we do not refer to ses later */
......
...@@ -142,6 +142,24 @@ void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry) ...@@ -142,6 +142,24 @@ void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
kmem_cache_free(cifs_oplock_cachep, 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 int
smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
unsigned int smb_buf_length, struct sockaddr *sin) unsigned int smb_buf_length, struct sockaddr *sin)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment