summaryrefslogtreecommitdiff
path: root/fs/cifs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2013-10-03 12:53:37 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2013-10-24 23:43:27 -0400
commit2e32cf5ef2683a196df24ccd2cd2b4ed735ad9d3 (patch)
tree14861a1a6e31bec8e6d46cc8facf02b71760b92d /fs/cifs
parentbaa40671d3e3b590a33b2c0e022db61cbebf5c00 (diff)
downloadlwn-2e32cf5ef2683a196df24ccd2cd2b4ed735ad9d3.tar.gz
lwn-2e32cf5ef2683a196df24ccd2cd2b4ed735ad9d3.zip
cifs: rcu-delay unload_nls() and freeing sbi
makes ->d_hash(), ->d_compare() and ->permission() safety in RCU mode independent from vfsmount_lock. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifs_fs_sb.h1
-rw-r--r--fs/cifs/connect.c10
2 files changed, 9 insertions, 2 deletions
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 37e4a72a7d1c..9409fa10bd5c 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -65,5 +65,6 @@ struct cifs_sb_info {
char *mountdata; /* options received at mount time or via DFS refs */
struct backing_dev_info bdi;
struct delayed_work prune_tlinks;
+ struct rcu_head rcu;
};
#endif /* _CIFS_FS_SB_H */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a279ffc0bc29..886db8b41e35 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3755,6 +3755,13 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
return rc;
}
+static void delayed_free(struct rcu_head *p)
+{
+ struct cifs_sb_info *sbi = container_of(p, struct cifs_sb_info, rcu);
+ unload_nls(sbi->local_nls);
+ kfree(sbi);
+}
+
void
cifs_umount(struct cifs_sb_info *cifs_sb)
{
@@ -3779,8 +3786,7 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
bdi_destroy(&cifs_sb->bdi);
kfree(cifs_sb->mountdata);
- unload_nls(cifs_sb->local_nls);
- kfree(cifs_sb);
+ call_rcu(&cifs_sb->rcu, delayed_free);
}
int