diff options
author | Jeff Layton <jlayton@redhat.com> | 2010-10-11 15:07:19 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2010-10-12 14:08:01 -0400 |
commit | d7c86ff8cd00abc730fe5d031f43dc9138b6324e (patch) | |
tree | a1f264ce2f33e3ac77a459291b9a5e45a63e3bff /fs | |
parent | a5e18bc36e9e05ce0338d370a2ce4290910e43ea (diff) |
cifs: don't use vfsmount to pin superblock for oplock breaks
Filesystems aren't really supposed to do anything with a vfsmount. It's
considered a layering violation since vfsmounts are entirely managed at
the VFS layer.
CIFS currently keeps an active reference to a vfsmount in order to
prevent the superblock vanishing before an oplock break has completed.
What we really want to do instead is to keep sb->s_active high until the
oplock break has completed. This patch borrows the scheme that NFS uses
for handling sillyrenames.
An atomic_t is added to the cifs_sb_info. When it transitions from 0 to
1, an extra reference to the superblock is taken (by bumping the
s_active value). When it transitions from 1 to 0, that reference is
dropped and a the superblock teardown may proceed if there are no more
references to it.
Also, the vfsmount pointer is removed from cifsFileInfo and from
cifs_new_fileinfo, and some bogus forward declarations are removed from
cifsfs.h.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Reviewed-by: Suresh Jayaraman <sjayaraman@suse.de>
Acked-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 1 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 18 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 6 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/cifs/dir.c | 10 | ||||
-rw-r--r-- | fs/cifs/file.c | 9 |
7 files changed, 29 insertions, 18 deletions
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 586ee3d527d2..525ba59a4105 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -48,6 +48,7 @@ struct cifs_sb_info { | |||
48 | struct nls_table *local_nls; | 48 | struct nls_table *local_nls; |
49 | unsigned int rsize; | 49 | unsigned int rsize; |
50 | unsigned int wsize; | 50 | unsigned int wsize; |
51 | atomic_t active; | ||
51 | uid_t mnt_uid; | 52 | uid_t mnt_uid; |
52 | gid_t mnt_gid; | 53 | gid_t mnt_gid; |
53 | mode_t mnt_file_mode; | 54 | mode_t mnt_file_mode; |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 3258c822328b..cbd468c880c4 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -83,6 +83,24 @@ extern mempool_t *cifs_sm_req_poolp; | |||
83 | extern mempool_t *cifs_req_poolp; | 83 | extern mempool_t *cifs_req_poolp; |
84 | extern mempool_t *cifs_mid_poolp; | 84 | extern mempool_t *cifs_mid_poolp; |
85 | 85 | ||
86 | void | ||
87 | cifs_sb_active(struct super_block *sb) | ||
88 | { | ||
89 | struct cifs_sb_info *server = CIFS_SB(sb); | ||
90 | |||
91 | if (atomic_inc_return(&server->active) == 1) | ||
92 | atomic_inc(&sb->s_active); | ||
93 | } | ||
94 | |||
95 | void | ||
96 | cifs_sb_deactive(struct super_block *sb) | ||
97 | { | ||
98 | struct cifs_sb_info *server = CIFS_SB(sb); | ||
99 | |||
100 | if (atomic_dec_and_test(&server->active)) | ||
101 | deactivate_super(sb); | ||
102 | } | ||
103 | |||
86 | static int | 104 | static int |
87 | cifs_read_super(struct super_block *sb, void *data, | 105 | cifs_read_super(struct super_block *sb, void *data, |
88 | const char *devname, int silent) | 106 | const char *devname, int silent) |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 786bdf36aebf..85544bcab517 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -42,10 +42,8 @@ extern const struct address_space_operations cifs_addr_ops; | |||
42 | extern const struct address_space_operations cifs_addr_ops_smallbuf; | 42 | extern const struct address_space_operations cifs_addr_ops_smallbuf; |
43 | 43 | ||
44 | /* Functions related to super block operations */ | 44 | /* Functions related to super block operations */ |
45 | /* extern const struct super_operations cifs_super_ops;*/ | 45 | extern void cifs_sb_active(struct super_block *sb); |
46 | extern void cifs_read_inode(struct inode *); | 46 | extern void cifs_sb_deactive(struct super_block *sb); |
47 | /*extern void cifs_delete_inode(struct inode *);*/ /* BB not needed yet */ | ||
48 | /* extern void cifs_write_inode(struct inode *); */ /* BB not needed yet */ | ||
49 | 47 | ||
50 | /* Functions related to inodes */ | 48 | /* Functions related to inodes */ |
51 | extern const struct inode_operations cifs_dir_inode_ops; | 49 | extern const struct inode_operations cifs_dir_inode_ops; |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 8289e61937a2..e2b760ef22ff 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -388,7 +388,6 @@ struct cifsFileInfo { | |||
388 | /* lock scope id (0 if none) */ | 388 | /* lock scope id (0 if none) */ |
389 | struct file *pfile; /* needed for writepage */ | 389 | struct file *pfile; /* needed for writepage */ |
390 | struct dentry *dentry; | 390 | struct dentry *dentry; |
391 | struct vfsmount *mnt; | ||
392 | struct tcon_link *tlink; | 391 | struct tcon_link *tlink; |
393 | struct mutex lock_mutex; | 392 | struct mutex lock_mutex; |
394 | struct list_head llist; /* list of byte range locks we have. */ | 393 | struct list_head llist; /* list of byte range locks we have. */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 29a2ee8ae51f..7f416abd34cf 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -107,7 +107,7 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, | |||
107 | 107 | ||
108 | extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, | 108 | extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, |
109 | __u16 fileHandle, struct file *file, | 109 | __u16 fileHandle, struct file *file, |
110 | struct vfsmount *mnt, struct tcon_link *tlink, | 110 | struct tcon_link *tlink, |
111 | unsigned int oflags, __u32 oplock); | 111 | unsigned int oflags, __u32 oplock); |
112 | extern int cifs_posix_open(char *full_path, struct inode **pinode, | 112 | extern int cifs_posix_open(char *full_path, struct inode **pinode, |
113 | struct super_block *sb, | 113 | struct super_block *sb, |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 6887c412c61a..c205ec9293ea 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -132,8 +132,7 @@ cifs_bp_rename_retry: | |||
132 | 132 | ||
133 | struct cifsFileInfo * | 133 | struct cifsFileInfo * |
134 | cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, | 134 | cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, |
135 | struct vfsmount *mnt, struct tcon_link *tlink, | 135 | struct tcon_link *tlink, unsigned int oflags, __u32 oplock) |
136 | unsigned int oflags, __u32 oplock) | ||
137 | { | 136 | { |
138 | struct dentry *dentry = file->f_path.dentry; | 137 | struct dentry *dentry = file->f_path.dentry; |
139 | struct cifsFileInfo *pCifsFile; | 138 | struct cifsFileInfo *pCifsFile; |
@@ -147,7 +146,6 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, | |||
147 | pCifsFile->pid = current->tgid; | 146 | pCifsFile->pid = current->tgid; |
148 | pCifsFile->uid = current_fsuid(); | 147 | pCifsFile->uid = current_fsuid(); |
149 | pCifsFile->dentry = dget(dentry); | 148 | pCifsFile->dentry = dget(dentry); |
150 | pCifsFile->mnt = mnt; | ||
151 | pCifsFile->pfile = file; | 149 | pCifsFile->pfile = file; |
152 | pCifsFile->invalidHandle = false; | 150 | pCifsFile->invalidHandle = false; |
153 | pCifsFile->closePend = false; | 151 | pCifsFile->closePend = false; |
@@ -485,8 +483,7 @@ cifs_create_set_dentry: | |||
485 | } | 483 | } |
486 | 484 | ||
487 | pfile_info = cifs_new_fileinfo(newinode, fileHandle, filp, | 485 | pfile_info = cifs_new_fileinfo(newinode, fileHandle, filp, |
488 | nd->path.mnt, tlink, oflags, | 486 | tlink, oflags, oplock); |
489 | oplock); | ||
490 | if (pfile_info == NULL) { | 487 | if (pfile_info == NULL) { |
491 | fput(filp); | 488 | fput(filp); |
492 | CIFSSMBClose(xid, tcon, fileHandle); | 489 | CIFSSMBClose(xid, tcon, fileHandle); |
@@ -760,8 +757,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
760 | } | 757 | } |
761 | 758 | ||
762 | cfile = cifs_new_fileinfo(newInode, fileHandle, filp, | 759 | cfile = cifs_new_fileinfo(newInode, fileHandle, filp, |
763 | nd->path.mnt, tlink, | 760 | tlink, nd->intent.open.flags, |
764 | nd->intent.open.flags, | ||
765 | oplock); | 761 | oplock); |
766 | if (cfile == NULL) { | 762 | if (cfile == NULL) { |
767 | fput(filp); | 763 | fput(filp); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c302b9c52644..fd78a355f634 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -282,7 +282,6 @@ int cifs_open(struct inode *inode, struct file *file) | |||
282 | } | 282 | } |
283 | 283 | ||
284 | pCifsFile = cifs_new_fileinfo(inode, netfid, file, | 284 | pCifsFile = cifs_new_fileinfo(inode, netfid, file, |
285 | file->f_path.mnt, | ||
286 | tlink, oflags, oplock); | 285 | tlink, oflags, oplock); |
287 | if (pCifsFile == NULL) { | 286 | if (pCifsFile == NULL) { |
288 | CIFSSMBClose(xid, tcon, netfid); | 287 | CIFSSMBClose(xid, tcon, netfid); |
@@ -375,8 +374,8 @@ int cifs_open(struct inode *inode, struct file *file) | |||
375 | if (rc != 0) | 374 | if (rc != 0) |
376 | goto out; | 375 | goto out; |
377 | 376 | ||
378 | pCifsFile = cifs_new_fileinfo(inode, netfid, file, file->f_path.mnt, | 377 | pCifsFile = cifs_new_fileinfo(inode, netfid, file, tlink, |
379 | tlink, file->f_flags, oplock); | 378 | file->f_flags, oplock); |
380 | if (pCifsFile == NULL) { | 379 | if (pCifsFile == NULL) { |
381 | rc = -ENOMEM; | 380 | rc = -ENOMEM; |
382 | goto out; | 381 | goto out; |
@@ -2381,14 +2380,14 @@ void cifs_oplock_break(struct work_struct *work) | |||
2381 | 2380 | ||
2382 | void cifs_oplock_break_get(struct cifsFileInfo *cfile) | 2381 | void cifs_oplock_break_get(struct cifsFileInfo *cfile) |
2383 | { | 2382 | { |
2384 | mntget(cfile->mnt); | 2383 | cifs_sb_active(cfile->dentry->d_sb); |
2385 | cifsFileInfo_get(cfile); | 2384 | cifsFileInfo_get(cfile); |
2386 | } | 2385 | } |
2387 | 2386 | ||
2388 | void cifs_oplock_break_put(struct cifsFileInfo *cfile) | 2387 | void cifs_oplock_break_put(struct cifsFileInfo *cfile) |
2389 | { | 2388 | { |
2390 | mntput(cfile->mnt); | ||
2391 | cifsFileInfo_put(cfile); | 2389 | cifsFileInfo_put(cfile); |
2390 | cifs_sb_deactive(cfile->dentry->d_sb); | ||
2392 | } | 2391 | } |
2393 | 2392 | ||
2394 | const struct address_space_operations cifs_addr_ops = { | 2393 | const struct address_space_operations cifs_addr_ops = { |