diff options
-rw-r--r-- | fs/cifs/cifsfs.c | 88 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 8 | ||||
-rw-r--r-- | fs/cifs/connect.c | 89 |
3 files changed, 114 insertions, 71 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 493b74ca564..131afadce0e 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -104,19 +104,16 @@ cifs_sb_deactive(struct super_block *sb) } static int -cifs_read_super(struct super_block *sb, void *data, - const char *devname, int silent) +cifs_read_super(struct super_block *sb, struct cifs_sb_info *cifs_sb, + void *data, struct smb_vol *volume_info, const char *devname, + int silent) { struct inode *inode; - struct cifs_sb_info *cifs_sb; int rc = 0; /* BB should we make this contingent on mount parm? */ sb->s_flags |= MS_NODIRATIME | MS_NOATIME; - sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); - cifs_sb = CIFS_SB(sb); - if (cifs_sb == NULL) - return -ENOMEM; + sb->s_fs_info = cifs_sb; spin_lock_init(&cifs_sb->tlink_tree_lock); cifs_sb->tlink_tree = RB_ROOT; @@ -128,22 +125,10 @@ cifs_read_super(struct super_block *sb, void *data, } cifs_sb->bdi.ra_pages = default_backing_dev_info.ra_pages; - /* - * Copy mount params to sb for use in submounts. Better to do - * the copy here and deal with the error before cleanup gets - * complicated post-mount. - */ - if (data) { - cifs_sb->mountdata = kstrndup(data, PAGE_SIZE, GFP_KERNEL); - if (cifs_sb->mountdata == NULL) { - bdi_destroy(&cifs_sb->bdi); - kfree(sb->s_fs_info); - sb->s_fs_info = NULL; - return -ENOMEM; - } - } + if (data) + cifs_sb->mountdata = data; - rc = cifs_mount(sb, cifs_sb, devname); + rc = cifs_mount(sb, cifs_sb, volume_info, devname); if (rc) { if (!silent) @@ -561,27 +546,68 @@ static const struct super_operations cifs_super_ops = { static struct dentry * cifs_do_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) + int flags, const char *dev_name, void *data) { int rc; struct super_block *sb; - - sb = sget(fs_type, NULL, set_anon_super, NULL); + struct cifs_sb_info *cifs_sb; + struct smb_vol *volume_info; + struct dentry *root; + char *copied_data = NULL; cFYI(1, "Devname: %s flags: %d ", dev_name, flags); - if (IS_ERR(sb)) - return ERR_CAST(sb); + rc = cifs_setup_volume_info(&volume_info, (char *)data, dev_name); + if (rc) + return ERR_PTR(rc); + + cifs_sb = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL); + if (cifs_sb == NULL) { + root = ERR_PTR(-ENOMEM); + goto out; + } + + cifs_setup_cifs_sb(volume_info, cifs_sb); + + sb = sget(fs_type, NULL, set_anon_super, NULL); + if (IS_ERR(sb)) { + kfree(cifs_sb); + root = ERR_CAST(sb); + goto out; + } sb->s_flags = flags; - rc = cifs_read_super(sb, data, dev_name, flags & MS_SILENT ? 1 : 0); + /* + * Copy mount params for use in submounts. Better to do + * the copy here and deal with the error before cleanup gets + * complicated post-mount. + */ + copied_data = kstrndup(data, PAGE_SIZE, GFP_KERNEL); + if (copied_data == NULL) { + root = ERR_PTR(-ENOMEM); + goto err_out; + } + + rc = cifs_read_super(sb, cifs_sb, copied_data, volume_info, dev_name, + flags & MS_SILENT ? 1 : 0); if (rc) { - deactivate_locked_super(sb); - return ERR_PTR(rc); + root = ERR_PTR(rc); + goto err_out; } + sb->s_flags |= MS_ACTIVE; - return dget(sb->s_root); + + root = dget(sb->s_root); +out: + cifs_cleanup_volume_info(&volume_info); + return root; + +err_out: + kfree(cifs_sb); + deactivate_locked_super(sb); + cifs_cleanup_volume_info(&volume_info); + return root; } static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 3738a322cbe..fdc0dc2c083 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -150,8 +150,14 @@ extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, const char *); +extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, + struct cifs_sb_info *cifs_sb); +extern int cifs_match_super(struct super_block *, void *); +extern void cifs_cleanup_volume_info(struct smb_vol **pvolume_info); +extern int cifs_setup_volume_info(struct smb_vol **pvolume_info, + char *mount_data, const char *devname); extern int cifs_mount(struct super_block *, struct cifs_sb_info *, - const char *); + struct smb_vol *, const char *); extern int cifs_umount(struct super_block *, struct cifs_sb_info *); extern void cifs_dfs_release_automount_timer(void); void cifs_proc_init(void); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 37b8ead2f60..273cf42b291 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2614,8 +2614,8 @@ convert_delimiter(char *path, char delim) } } -static void setup_cifs_sb(struct smb_vol *pvolume_info, - struct cifs_sb_info *cifs_sb) +void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, + struct cifs_sb_info *cifs_sb) { INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks); @@ -2671,6 +2671,7 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); cifs_sb->actimeo = pvolume_info->actimeo; + cifs_sb->local_nls = pvolume_info->local_nls; if (pvolume_info->noperm) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; @@ -2747,8 +2748,8 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon, return rc; } -static void -cleanup_volume_info(struct smb_vol **pvolume_info) +void +cifs_cleanup_volume_info(struct smb_vol **pvolume_info) { struct smb_vol *volume_info; @@ -2854,40 +2855,13 @@ expand_dfs_referral(int xid, struct cifsSesInfo *pSesInfo, } #endif -int -cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, - const char *devname) +int cifs_setup_volume_info(struct smb_vol **pvolume_info, char *mount_data, + const char *devname) { - int rc; - int xid; struct smb_vol *volume_info; - struct cifsSesInfo *pSesInfo; - struct cifsTconInfo *tcon; - struct TCP_Server_Info *srvTcp; - char *full_path; - struct tcon_link *tlink; -#ifdef CONFIG_CIFS_DFS_UPCALL - int referral_walks_count = 0; -try_mount_again: - /* cleanup activities if we're chasing a referral */ - if (referral_walks_count) { - if (tcon) - cifs_put_tcon(tcon); - else if (pSesInfo) - cifs_put_smb_ses(pSesInfo); - - cleanup_volume_info(&volume_info); - FreeXid(xid); - } -#endif - rc = 0; - tcon = NULL; - pSesInfo = NULL; - srvTcp = NULL; - full_path = NULL; - tlink = NULL; + int rc = 0; - xid = GetXid(); + *pvolume_info = NULL; volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL); if (!volume_info) { @@ -2895,7 +2869,7 @@ try_mount_again: goto out; } - if (cifs_parse_mount_options(cifs_sb->mountdata, devname, + if (cifs_parse_mount_options(mount_data, devname, volume_info)) { rc = -EINVAL; goto out; @@ -2928,7 +2902,46 @@ try_mount_again: goto out; } } - cifs_sb->local_nls = volume_info->local_nls; + + *pvolume_info = volume_info; + return rc; +out: + cifs_cleanup_volume_info(&volume_info); + return rc; +} + +int +cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, + struct smb_vol *volume_info, const char *devname) +{ + int rc = 0; + int xid; + struct cifsSesInfo *pSesInfo; + struct cifsTconInfo *tcon; + struct TCP_Server_Info *srvTcp; + char *full_path; + struct tcon_link *tlink; +#ifdef CONFIG_CIFS_DFS_UPCALL + int referral_walks_count = 0; +try_mount_again: + /* cleanup activities if we're chasing a referral */ + if (referral_walks_count) { + if (tcon) + cifs_put_tcon(tcon); + else if (pSesInfo) + cifs_put_smb_ses(pSesInfo); + + cifs_cleanup_volume_info(&volume_info); + FreeXid(xid); + } +#endif + tcon = NULL; + pSesInfo = NULL; + srvTcp = NULL; + full_path = NULL; + tlink = NULL; + + xid = GetXid(); /* get a reference to a tcp session */ srvTcp = cifs_get_tcp_session(volume_info); @@ -2945,7 +2958,6 @@ try_mount_again: goto mount_fail_check; } - setup_cifs_sb(volume_info, cifs_sb); if (pSesInfo->capabilities & CAP_LARGE_FILES) sb->s_maxbytes = MAX_LFS_FILESIZE; else @@ -3101,7 +3113,6 @@ mount_fail_check: password will be freed at unmount time) */ out: /* zero out password before freeing */ - cleanup_volume_info(&volume_info); FreeXid(xid); return rc; } |