aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2011-05-26 15:35:47 -0400
committerSteve French <sfrench@us.ibm.com>2011-05-26 23:53:23 -0400
commit25c7f41e9234f60af30e086278f1de7974f8816f (patch)
tree41cb4da532da30418da2d33e5376ddbf9f65958a /fs/cifs
parentf87d39d951329cd8f462bf9007d334122c0599d0 (diff)
CIFS: Migrate to shared superblock model
Add cifs_match_super to use in sget to share superblock between mounts that have the same //server/sharename, credentials and mount options. It helps us to improve performance on work with future SMB2.1 leases. Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsfs.c19
-rw-r--r--fs/cifs/cifsglob.h19
-rw-r--r--fs/cifs/connect.c102
3 files changed, 139 insertions, 1 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 46fdd55cf427..360fe2ec2a19 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -630,6 +630,7 @@ cifs_do_mount(struct file_system_type *fs_type,
630 struct super_block *sb; 630 struct super_block *sb;
631 struct cifs_sb_info *cifs_sb; 631 struct cifs_sb_info *cifs_sb;
632 struct smb_vol *volume_info; 632 struct smb_vol *volume_info;
633 struct cifs_mnt_data mnt_data;
633 struct dentry *root; 634 struct dentry *root;
634 635
635 cFYI(1, "Devname: %s flags: %d ", dev_name, flags); 636 cFYI(1, "Devname: %s flags: %d ", dev_name, flags);
@@ -646,12 +647,21 @@ cifs_do_mount(struct file_system_type *fs_type,
646 647
647 cifs_setup_cifs_sb(volume_info, cifs_sb); 648 cifs_setup_cifs_sb(volume_info, cifs_sb);
648 649
649 sb = sget(fs_type, NULL, set_anon_super, NULL); 650 mnt_data.vol = volume_info;
651 mnt_data.cifs_sb = cifs_sb;
652 mnt_data.flags = flags;
653
654 sb = sget(fs_type, cifs_match_super, set_anon_super, &mnt_data);
650 if (IS_ERR(sb)) { 655 if (IS_ERR(sb)) {
651 root = ERR_CAST(sb); 656 root = ERR_CAST(sb);
652 goto out_cifs_sb; 657 goto out_cifs_sb;
653 } 658 }
654 659
660 if (sb->s_fs_info) {
661 cFYI(1, "Use existing superblock");
662 goto out_shared;
663 }
664
655 /* 665 /*
656 * Copy mount params for use in submounts. Better to do 666 * Copy mount params for use in submounts. Better to do
657 * the copy here and deal with the error before cleanup gets 667 * the copy here and deal with the error before cleanup gets
@@ -680,9 +690,16 @@ cifs_do_mount(struct file_system_type *fs_type,
680 root = cifs_get_root(volume_info, sb); 690 root = cifs_get_root(volume_info, sb);
681 if (root == NULL) 691 if (root == NULL)
682 goto out_super; 692 goto out_super;
693
683 cFYI(1, "dentry root is: %p", root); 694 cFYI(1, "dentry root is: %p", root);
684 goto out; 695 goto out;
685 696
697out_shared:
698 root = cifs_get_root(volume_info, sb);
699 if (root)
700 cFYI(1, "dentry root is: %p", root);
701 goto out;
702
686out_super: 703out_super:
687 kfree(cifs_sb->mountdata); 704 kfree(cifs_sb->mountdata);
688 deactivate_locked_super(sb); 705 deactivate_locked_super(sb);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 68ec457f8476..ca0c3789206e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -210,6 +210,25 @@ struct smb_vol {
210 struct nls_table *local_nls; 210 struct nls_table *local_nls;
211}; 211};
212 212
213#define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \
214 CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | \
215 CIFS_MOUNT_NO_XATTR | CIFS_MOUNT_MAP_SPECIAL_CHR | \
216 CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL | \
217 CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | \
218 CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \
219 CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC | \
220 CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \
221 CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO)
222
223#define CIFS_MS_MASK (MS_RDONLY | MS_MANDLOCK | MS_NOEXEC | MS_NOSUID | \
224 MS_NODEV | MS_SYNCHRONOUS)
225
226struct cifs_mnt_data {
227 struct cifs_sb_info *cifs_sb;
228 struct smb_vol *vol;
229 int flags;
230};
231
213struct TCP_Server_Info { 232struct TCP_Server_Info {
214 struct list_head tcp_ses_list; 233 struct list_head tcp_ses_list;
215 struct list_head smb_ses_list; 234 struct list_head smb_ses_list;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 495688115988..261ca81d5e49 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2146,6 +2146,100 @@ cifs_put_tlink(struct tcon_link *tlink)
2146 return; 2146 return;
2147} 2147}
2148 2148
2149static inline struct tcon_link *
2150cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb);
2151
2152static int
2153compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
2154{
2155 struct cifs_sb_info *old = CIFS_SB(sb);
2156 struct cifs_sb_info *new = mnt_data->cifs_sb;
2157
2158 if ((sb->s_flags & CIFS_MS_MASK) != (mnt_data->flags & CIFS_MS_MASK))
2159 return 0;
2160
2161 if ((old->mnt_cifs_flags & CIFS_MOUNT_MASK) !=
2162 (new->mnt_cifs_flags & CIFS_MOUNT_MASK))
2163 return 0;
2164
2165 if (old->rsize != new->rsize)
2166 return 0;
2167
2168 /*
2169 * We want to share sb only if we don't specify wsize or specified wsize
2170 * is greater or equal than existing one.
2171 */
2172 if (new->wsize && new->wsize < old->wsize)
2173 return 0;
2174
2175 if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid)
2176 return 0;
2177
2178 if (old->mnt_file_mode != new->mnt_file_mode ||
2179 old->mnt_dir_mode != new->mnt_dir_mode)
2180 return 0;
2181
2182 if (strcmp(old->local_nls->charset, new->local_nls->charset))
2183 return 0;
2184
2185 if (old->actimeo != new->actimeo)
2186 return 0;
2187
2188 return 1;
2189}
2190
2191int
2192cifs_match_super(struct super_block *sb, void *data)
2193{
2194 struct cifs_mnt_data *mnt_data = (struct cifs_mnt_data *)data;
2195 struct smb_vol *volume_info;
2196 struct cifs_sb_info *cifs_sb;
2197 struct TCP_Server_Info *tcp_srv;
2198 struct cifsSesInfo *ses;
2199 struct cifsTconInfo *tcon;
2200 struct tcon_link *tlink;
2201 struct sockaddr_storage addr;
2202 int rc = 0;
2203
2204 memset(&addr, 0, sizeof(struct sockaddr_storage));
2205
2206 spin_lock(&cifs_tcp_ses_lock);
2207 cifs_sb = CIFS_SB(sb);
2208 tlink = cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
2209 if (IS_ERR(tlink)) {
2210 spin_unlock(&cifs_tcp_ses_lock);
2211 return rc;
2212 }
2213 tcon = tlink_tcon(tlink);
2214 ses = tcon->ses;
2215 tcp_srv = ses->server;
2216
2217 volume_info = mnt_data->vol;
2218
2219 if (!volume_info->UNCip || !volume_info->UNC)
2220 goto out;
2221
2222 rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
2223 volume_info->UNCip,
2224 strlen(volume_info->UNCip),
2225 volume_info->port);
2226 if (!rc)
2227 goto out;
2228
2229 if (!match_server(tcp_srv, (struct sockaddr *)&addr, volume_info) ||
2230 !match_session(ses, volume_info) ||
2231 !match_tcon(tcon, volume_info->UNC)) {
2232 rc = 0;
2233 goto out;
2234 }
2235
2236 rc = compare_mount_options(sb, mnt_data);
2237out:
2238 cifs_put_tlink(tlink);
2239 spin_unlock(&cifs_tcp_ses_lock);
2240 return rc;
2241}
2242
2149int 2243int
2150get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, 2244get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
2151 const struct nls_table *nls_codepage, unsigned int *pnum_referrals, 2245 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
@@ -2578,6 +2672,14 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
2578 /* Windows ME may prefer this */ 2672 /* Windows ME may prefer this */
2579 cFYI(1, "readsize set to minimum: 2048"); 2673 cFYI(1, "readsize set to minimum: 2048");
2580 } 2674 }
2675
2676 /*
2677 * Temporarily set wsize for matching superblock. If we end up using
2678 * new sb then cifs_negotiate_wsize will later negotiate it downward
2679 * if needed.
2680 */
2681 cifs_sb->wsize = pvolume_info->wsize;
2682
2581 cifs_sb->mnt_uid = pvolume_info->linux_uid; 2683 cifs_sb->mnt_uid = pvolume_info->linux_uid;
2582 cifs_sb->mnt_gid = pvolume_info->linux_gid; 2684 cifs_sb->mnt_gid = pvolume_info->linux_gid;
2583 cifs_sb->mnt_file_mode = pvolume_info->file_mode; 2685 cifs_sb->mnt_file_mode = pvolume_info->file_mode;