diff options
author | Pavel Shilovsky <piastry@etersoft.ru> | 2011-05-26 15:35:47 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2011-05-26 23:53:23 -0400 |
commit | 25c7f41e9234f60af30e086278f1de7974f8816f (patch) | |
tree | 41cb4da532da30418da2d33e5376ddbf9f65958a /fs/cifs | |
parent | f87d39d951329cd8f462bf9007d334122c0599d0 (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.c | 19 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 19 | ||||
-rw-r--r-- | fs/cifs/connect.c | 102 |
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 | ||
697 | out_shared: | ||
698 | root = cifs_get_root(volume_info, sb); | ||
699 | if (root) | ||
700 | cFYI(1, "dentry root is: %p", root); | ||
701 | goto out; | ||
702 | |||
686 | out_super: | 703 | out_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 | |||
226 | struct cifs_mnt_data { | ||
227 | struct cifs_sb_info *cifs_sb; | ||
228 | struct smb_vol *vol; | ||
229 | int flags; | ||
230 | }; | ||
231 | |||
213 | struct TCP_Server_Info { | 232 | struct 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 | ||
2149 | static inline struct tcon_link * | ||
2150 | cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb); | ||
2151 | |||
2152 | static int | ||
2153 | compare_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 | |||
2191 | int | ||
2192 | cifs_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); | ||
2237 | out: | ||
2238 | cifs_put_tlink(tlink); | ||
2239 | spin_unlock(&cifs_tcp_ses_lock); | ||
2240 | return rc; | ||
2241 | } | ||
2242 | |||
2149 | int | 2243 | int |
2150 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, | 2244 | get_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; |