diff options
author | Jeff Layton <jlayton@redhat.com> | 2009-09-21 06:47:50 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2009-09-24 14:33:18 -0400 |
commit | 3bc303c254335dbd7c7012cc1760b12f1d5514d3 (patch) | |
tree | 7da17fbfd697216d9ed0ccd64ea9c03aaf3d52c1 /fs/cifs/dir.c | |
parent | 48541bd3dd4739b4d574b44ea47660c88d833677 (diff) |
cifs: convert oplock breaks to use slow_work facility (try #4)
This is the fourth respin of the patch to convert oplock breaks to
use the slow_work facility.
A customer of ours was testing a backport of one of the earlier
patchsets, and hit a "Busy inodes after umount..." problem. An oplock
break job had raced with a umount, and the superblock got torn down and
its memory reused. When the oplock break job tried to dereference the
inode->i_sb, the kernel oopsed.
This patchset has the oplock break job hold an inode and vfsmount
reference until the oplock break completes. With this, there should be
no need to take a tcon reference (the vfsmount implicitly holds one
already).
Currently, when an oplock break comes in there's a chance that the
oplock break job won't occur if the allocation of the oplock_q_entry
fails. There are also some rather nasty races in the allocation and
handling these structs.
Rather than allocating oplock queue entries when an oplock break comes
in, add a few extra fields to the cifsFileInfo struct. Get rid of the
dedicated cifs_oplock_thread as well and queue the oplock break job to
the slow_work thread pool.
This approach also has the advantage that the oplock break jobs can
potentially run in parallel rather than be serialized like they are
today.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/dir.c')
-rw-r--r-- | fs/cifs/dir.c | 25 |
1 files changed, 14 insertions, 11 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 36435502b5e8..9a5df7a84698 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/stat.h> | 24 | #include <linux/stat.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/namei.h> | 26 | #include <linux/namei.h> |
27 | #include <linux/mount.h> | ||
27 | #include "cifsfs.h" | 28 | #include "cifsfs.h" |
28 | #include "cifspdu.h" | 29 | #include "cifspdu.h" |
29 | #include "cifsglob.h" | 30 | #include "cifsglob.h" |
@@ -131,11 +132,12 @@ cifs_bp_rename_retry: | |||
131 | 132 | ||
132 | static void | 133 | static void |
133 | cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, | 134 | cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, |
134 | struct cifsTconInfo *tcon, bool write_only) | 135 | struct vfsmount *mnt, bool write_only) |
135 | { | 136 | { |
136 | int oplock = 0; | 137 | int oplock = 0; |
137 | struct cifsFileInfo *pCifsFile; | 138 | struct cifsFileInfo *pCifsFile; |
138 | struct cifsInodeInfo *pCifsInode; | 139 | struct cifsInodeInfo *pCifsInode; |
140 | struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb); | ||
139 | 141 | ||
140 | pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 142 | pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); |
141 | 143 | ||
@@ -148,17 +150,19 @@ cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, | |||
148 | pCifsFile->netfid = fileHandle; | 150 | pCifsFile->netfid = fileHandle; |
149 | pCifsFile->pid = current->tgid; | 151 | pCifsFile->pid = current->tgid; |
150 | pCifsFile->pInode = igrab(newinode); | 152 | pCifsFile->pInode = igrab(newinode); |
153 | pCifsFile->mnt = mnt; | ||
151 | pCifsFile->invalidHandle = false; | 154 | pCifsFile->invalidHandle = false; |
152 | pCifsFile->closePend = false; | 155 | pCifsFile->closePend = false; |
153 | mutex_init(&pCifsFile->fh_mutex); | 156 | mutex_init(&pCifsFile->fh_mutex); |
154 | mutex_init(&pCifsFile->lock_mutex); | 157 | mutex_init(&pCifsFile->lock_mutex); |
155 | INIT_LIST_HEAD(&pCifsFile->llist); | 158 | INIT_LIST_HEAD(&pCifsFile->llist); |
156 | atomic_set(&pCifsFile->count, 1); | 159 | atomic_set(&pCifsFile->count, 1); |
160 | slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops); | ||
157 | 161 | ||
158 | /* set the following in open now | 162 | /* set the following in open now |
159 | pCifsFile->pfile = file; */ | 163 | pCifsFile->pfile = file; */ |
160 | write_lock(&GlobalSMBSeslock); | 164 | write_lock(&GlobalSMBSeslock); |
161 | list_add(&pCifsFile->tlist, &tcon->openFileList); | 165 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); |
162 | pCifsInode = CIFS_I(newinode); | 166 | pCifsInode = CIFS_I(newinode); |
163 | if (pCifsInode) { | 167 | if (pCifsInode) { |
164 | /* if readable file instance put first in list*/ | 168 | /* if readable file instance put first in list*/ |
@@ -179,14 +183,14 @@ cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, | |||
179 | } | 183 | } |
180 | 184 | ||
181 | int cifs_posix_open(char *full_path, struct inode **pinode, | 185 | int cifs_posix_open(char *full_path, struct inode **pinode, |
182 | struct super_block *sb, int mode, int oflags, | 186 | struct vfsmount *mnt, int mode, int oflags, |
183 | __u32 *poplock, __u16 *pnetfid, int xid) | 187 | __u32 *poplock, __u16 *pnetfid, int xid) |
184 | { | 188 | { |
185 | int rc; | 189 | int rc; |
186 | bool write_only = false; | 190 | bool write_only = false; |
187 | FILE_UNIX_BASIC_INFO *presp_data; | 191 | FILE_UNIX_BASIC_INFO *presp_data; |
188 | __u32 posix_flags = 0; | 192 | __u32 posix_flags = 0; |
189 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 193 | struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb); |
190 | struct cifs_fattr fattr; | 194 | struct cifs_fattr fattr; |
191 | 195 | ||
192 | cFYI(1, ("posix open %s", full_path)); | 196 | cFYI(1, ("posix open %s", full_path)); |
@@ -243,7 +247,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
243 | 247 | ||
244 | /* get new inode and set it up */ | 248 | /* get new inode and set it up */ |
245 | if (*pinode == NULL) { | 249 | if (*pinode == NULL) { |
246 | *pinode = cifs_iget(sb, &fattr); | 250 | *pinode = cifs_iget(mnt->mnt_sb, &fattr); |
247 | if (!*pinode) { | 251 | if (!*pinode) { |
248 | rc = -ENOMEM; | 252 | rc = -ENOMEM; |
249 | goto posix_open_ret; | 253 | goto posix_open_ret; |
@@ -252,7 +256,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
252 | cifs_fattr_to_inode(*pinode, &fattr); | 256 | cifs_fattr_to_inode(*pinode, &fattr); |
253 | } | 257 | } |
254 | 258 | ||
255 | cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only); | 259 | cifs_fill_fileinfo(*pinode, *pnetfid, mnt, write_only); |
256 | 260 | ||
257 | posix_open_ret: | 261 | posix_open_ret: |
258 | kfree(presp_data); | 262 | kfree(presp_data); |
@@ -322,7 +326,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
322 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && | 326 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && |
323 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 327 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
324 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 328 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
325 | rc = cifs_posix_open(full_path, &newinode, inode->i_sb, | 329 | rc = cifs_posix_open(full_path, &newinode, nd->path.mnt, |
326 | mode, oflags, &oplock, &fileHandle, xid); | 330 | mode, oflags, &oplock, &fileHandle, xid); |
327 | /* EIO could indicate that (posix open) operation is not | 331 | /* EIO could indicate that (posix open) operation is not |
328 | supported, despite what server claimed in capability | 332 | supported, despite what server claimed in capability |
@@ -469,8 +473,8 @@ cifs_create_set_dentry: | |||
469 | /* mknod case - do not leave file open */ | 473 | /* mknod case - do not leave file open */ |
470 | CIFSSMBClose(xid, tcon, fileHandle); | 474 | CIFSSMBClose(xid, tcon, fileHandle); |
471 | } else if (!(posix_create) && (newinode)) { | 475 | } else if (!(posix_create) && (newinode)) { |
472 | cifs_fill_fileinfo(newinode, fileHandle, | 476 | cifs_fill_fileinfo(newinode, fileHandle, nd->path.mnt, |
473 | cifs_sb->tcon, write_only); | 477 | write_only); |
474 | } | 478 | } |
475 | cifs_create_out: | 479 | cifs_create_out: |
476 | kfree(buf); | 480 | kfree(buf); |
@@ -682,8 +686,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
682 | if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && | 686 | if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && |
683 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && | 687 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && |
684 | (nd->intent.open.flags & O_CREAT)) { | 688 | (nd->intent.open.flags & O_CREAT)) { |
685 | rc = cifs_posix_open(full_path, &newInode, | 689 | rc = cifs_posix_open(full_path, &newInode, nd->path.mnt, |
686 | parent_dir_inode->i_sb, | ||
687 | nd->intent.open.create_mode, | 690 | nd->intent.open.create_mode, |
688 | nd->intent.open.flags, &oplock, | 691 | nd->intent.open.flags, &oplock, |
689 | &fileHandle, xid); | 692 | &fileHandle, xid); |