From patchwork Fri Apr 15 07:01:55 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Shilovsky X-Patchwork-Id: 710231 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3F72cWd013929 for ; Fri, 15 Apr 2011 07:02:40 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755257Ab1DOHCj (ORCPT ); Fri, 15 Apr 2011 03:02:39 -0400 Received: from mail-bw0-f46.google.com ([209.85.214.46]:37092 "EHLO mail-bw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755201Ab1DOHCi (ORCPT ); Fri, 15 Apr 2011 03:02:38 -0400 Received: by bwz15 with SMTP id 15so1965717bwz.19 for ; Fri, 15 Apr 2011 00:02:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:from:to:subject:date:message-id:x-mailer :in-reply-to:references; bh=krFIFoxq4ijm2sEb45ux2Nszz5W1uvsBieCM7yVML1E=; b=irHW5s29joh1UG5OmsyYYwPsoFAx1ZNwR6TjGsYopHMFT58c+wur1sXaqCFNOrgp2z rlonzkYV45oSUaP1M6z/skuhL7vawHu6qaxb35UmUaakmkwXj8feIWZCfFUYsAGtjgLm gzOw5S4qKwGNzq3a6prTithkxczLveYwHTskY= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:subject:date:message-id:x-mailer:in-reply-to :references; b=uaF1+e4+gaWPL402E06b5WLxUEhQ0yP0QwlyUE2LGKl0gfGmzspqMfhSq7TsldmU7s /K10MSUN4v7mNy1DZwBdQzEa4J+pwWBLM8x4QHhbZANr54+xJ6j7rpef04n2BDXuuznO HERSoEwjZ7eYjJis6SWqr+0MHssz9JmMG3uL0= Received: by 10.204.82.74 with SMTP id a10mr1340625bkl.96.1302850956977; Fri, 15 Apr 2011 00:02:36 -0700 (PDT) Received: from localhost.localdomain (PPPoE-78-29-118-4.san.ru [78.29.118.4]) by mx.google.com with ESMTPS id a23sm1354767bkc.16.2011.04.15.00.02.35 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 15 Apr 2011 00:02:36 -0700 (PDT) From: Pavel Shilovsky To: linux-cifs@vger.kernel.org Subject: [PATCH 3/4] CIFS: Migrate from prefixpath logic Date: Fri, 15 Apr 2011 11:01:55 +0400 Message-Id: <1302850916-13947-2-git-send-email-piastry@etersoft.ru> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1302850916-13947-1-git-send-email-piastry@etersoft.ru> References: <1302850916-13947-1-git-send-email-piastry@etersoft.ru> Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Fri, 15 Apr 2011 07:02:40 +0000 (UTC) Now we point superblock to a server share root and set a root dentry appropriately. This let us share superblock between mounts like //server/sharename/foo/bar and //server/sharename/foo further. Signed-off-by: Pavel Shilovsky --- fs/cifs/cifs_fs_sb.h | 2 - fs/cifs/cifsfs.c | 95 +++++++++++++++++++++++++++++++++++- fs/cifs/cifsglob.h | 76 +++++++++++++++++++++++++++++ fs/cifs/cifsproto.h | 5 +- fs/cifs/connect.c | 129 ++------------------------------------------------ fs/cifs/dir.c | 7 +-- fs/cifs/inode.c | 15 +++--- 7 files changed, 186 insertions(+), 143 deletions(-) diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index adecd36..a18ba37 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -58,8 +58,6 @@ struct cifs_sb_info { mode_t mnt_file_mode; mode_t mnt_dir_mode; unsigned int mnt_cifs_flags; - int prepathlen; - char *prepath; /* relative path under the share to mount to */ char *mountdata; /* options received at mount time or via DFS refs */ struct backing_dev_info bdi; struct delayed_work prune_tlinks; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 3227db6..44394c8 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -434,8 +434,6 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) seq_printf(s, ",nocase"); if (tcon->retry) seq_printf(s, ",hard"); - if (cifs_sb->prepath) - seq_printf(s, ",prepath=%s", cifs_sb->prepath); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) seq_printf(s, ",posixpaths"); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) @@ -549,6 +547,92 @@ static const struct super_operations cifs_super_ops = { #endif }; +/* + * Get root dentry from superblock according to prefix path mount option. + * Return dentry with refcount + 1 on success and NULL otherwise. + */ +static struct dentry * +cifs_get_root(struct smb_vol *vol, struct super_block *sb) +{ + int xid, rc; + struct inode *inode; + struct qstr name; + struct dentry *dparent = NULL, *dchild = NULL; + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + unsigned int i, full_len, len; + char *full_path = NULL, *pstart; + char sep; + + full_path = cifs_build_path_to_root(vol, cifs_sb, + cifs_sb_master_tcon(cifs_sb)); + if (full_path == NULL) + return NULL; + + cFYI(1, "Get root dentry for %s", full_path); + + xid = GetXid(); + sep = CIFS_DIR_SEP(cifs_sb); + dparent = dget(sb->s_root); + full_len = strlen(full_path); + full_path[full_len] = sep; + pstart = full_path + 1; + + for (i = 1, len = 0; i <= full_len; i++) { + if (full_path[i] != sep || !len) { + len++; + continue; + } + + full_path[i] = 0; + cFYI(1, "get dentry for %s", pstart); + + name.name = pstart; + name.len = len; + name.hash = full_name_hash(pstart, len); + dchild = d_lookup(dparent, &name); + if (dchild == NULL) { + cFYI(1, "not exists"); + dchild = d_alloc(dparent, &name); + if (dchild == NULL) { + dput(dparent); + dparent = NULL; + goto out; + } + } + + cFYI(1, "get inode"); + if (dchild->d_inode == NULL) { + cFYI(1, "not exists"); + inode = NULL; + if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) + rc = cifs_get_inode_info_unix(&inode, full_path, + sb, xid); + else + rc = cifs_get_inode_info(&inode, full_path, + NULL, sb, xid, NULL); + if (rc) { + dput(dchild); + dput(dparent); + dparent = NULL; + goto out; + } + d_add(dchild, inode); + } + cFYI(1, "parent %p, child %p", dparent, dchild); + + dput(dparent); + dparent = dchild; + len = 0; + pstart = full_path + i + 1; + full_path[i] = sep; + } +out: + _FreeXid(xid); + full_path[full_len] = 0; + kfree(full_path); + return dparent; +} + static struct dentry * cifs_do_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) @@ -603,7 +687,12 @@ cifs_do_mount(struct file_system_type *fs_type, sb->s_flags |= MS_ACTIVE; - root = dget(sb->s_root); + root = cifs_get_root(volume_info, sb); + if (root == NULL) { + kfree(copied_data); + goto err_out; + } + cFYI(1, "dentry root is: %p", root); out: cifs_cleanup_volume_info(&volume_info); return root; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index ccbac61..38754f0 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -158,6 +158,62 @@ struct cifs_cred { ***************************************************************** */ +struct smb_vol { + char *username; + char *password; + char *domainname; + char *UNC; + char *UNCip; + char *iocharset; /* local code page for mapping to and from Unicode */ + char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ + char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ + uid_t cred_uid; + uid_t linux_uid; + gid_t linux_gid; + mode_t file_mode; + mode_t dir_mode; + unsigned secFlg; + bool retry:1; + bool intr:1; + bool setuids:1; + bool override_uid:1; + bool override_gid:1; + bool dynperm:1; + bool noperm:1; + bool no_psx_acl:1; /* set if posix acl support should be disabled */ + bool cifs_acl:1; + bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ + bool server_ino:1; /* use inode numbers from server ie UniqueId */ + bool direct_io:1; + bool strict_io:1; /* strict cache behavior */ + bool remap:1; /* set to remap seven reserved chars in filenames */ + bool posix_paths:1; /* unset to not ask for posix pathnames. */ + bool no_linux_ext:1; + bool sfu_emul:1; + bool nullauth:1; /* attempt to authenticate with null user */ + bool nocase:1; /* request case insensitive filenames */ + bool nobrl:1; /* disable sending byte range locks to srv */ + bool mand_lock:1; /* send mandatory not posix byte range lock reqs */ + bool seal:1; /* request transport encryption on share */ + bool nodfs:1; /* Do not request DFS, even if available */ + bool local_lease:1; /* check leases only on local system, not remote */ + bool noblocksnd:1; + bool noautotune:1; + bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ + bool fsc:1; /* enable fscache */ + bool mfsymlinks:1; /* use Minshall+French Symlinks */ + bool multiuser:1; + bool use_smb2:1; /* force smb2 use on mount instead of cifs */ + unsigned int rsize; + unsigned int wsize; + bool sockopt_tcp_nodelay:1; + unsigned short int port; + unsigned long actimeo; /* attribute cache timeout (jiffies) */ + char *prepath; + struct sockaddr_storage srcaddr; /* allow binding to a local IP */ + struct nls_table *local_nls; +}; + struct TCP_Server_Info { struct list_head tcp_ses_list; struct list_head smb_ses_list; @@ -549,6 +605,26 @@ static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) return '\\'; } +static inline void +convert_delimiter(char *path, char delim) +{ + int i; + char old_delim; + + if (path == NULL) + return; + + if (delim == '/') + old_delim = '\\'; + else + old_delim = '/'; + + for (i = 0; path[i] != '\0'; i++) { + if (path[i] == old_delim) + path[i] = delim; + } +} + #ifdef CONFIG_CIFS_STATS #define cifs_stats_inc atomic_inc diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index ffd16c8..7d94567 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -54,8 +54,9 @@ do { \ __func__, curr_xid, (int)rc); \ } while (0) extern char *build_path_from_dentry(struct dentry *); -extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, - struct cifs_tcon *tcon); +extern char *cifs_build_path_to_root(struct smb_vol *vol, + struct cifs_sb_info *cifs_sb, + struct cifs_tcon *tcon); extern char *build_wildcard_path_from_dentry(struct dentry *direntry); extern char *cifs_compose_mount_options(const char *sb_mountdata, const char *fullpath, const struct dfs_info3_param *ref, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0b41f75..abd5775 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -60,62 +60,6 @@ extern mempool_t *cifs_req_poolp; -struct smb_vol { - char *username; - char *password; - char *domainname; - char *UNC; - char *UNCip; - char *iocharset; /* local code page for mapping to and from Unicode */ - char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ - char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ - uid_t cred_uid; - uid_t linux_uid; - gid_t linux_gid; - mode_t file_mode; - mode_t dir_mode; - unsigned secFlg; - bool retry:1; - bool intr:1; - bool setuids:1; - bool override_uid:1; - bool override_gid:1; - bool dynperm:1; - bool noperm:1; - bool no_psx_acl:1; /* set if posix acl support should be disabled */ - bool cifs_acl:1; - bool no_xattr:1; /* set if xattr (EA) support should be disabled*/ - bool server_ino:1; /* use inode numbers from server ie UniqueId */ - bool direct_io:1; - bool strict_io:1; /* strict cache behavior */ - bool remap:1; /* set to remap seven reserved chars in filenames */ - bool posix_paths:1; /* unset to not ask for posix pathnames. */ - bool no_linux_ext:1; - bool sfu_emul:1; - bool nullauth:1; /* attempt to authenticate with null user */ - bool nocase:1; /* request case insensitive filenames */ - bool nobrl:1; /* disable sending byte range locks to srv */ - bool mand_lock:1; /* send mandatory not posix byte range lock reqs */ - bool seal:1; /* request transport encryption on share */ - bool nodfs:1; /* Do not request DFS, even if available */ - bool local_lease:1; /* check leases only on local system, not remote */ - bool noblocksnd:1; - bool noautotune:1; - bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ - bool fsc:1; /* enable fscache */ - bool mfsymlinks:1; /* use Minshall+French Symlinks */ - bool multiuser:1; - bool use_smb2:1; /* force smb2 use on mount instead of cifs */ - unsigned int rsize; - unsigned int wsize; - bool sockopt_tcp_nodelay:1; - unsigned short int port; - unsigned long actimeo; /* attribute cache timeout (jiffies) */ - char *prepath; - struct sockaddr_storage srcaddr; /* allow binding to a local IP */ - struct nls_table *local_nls; -}; - /* FIXME: should these be tunable? */ #define TLINK_ERROR_EXPIRE (1 * HZ) #define TLINK_IDLE_EXPIRE (600 * HZ) @@ -2560,12 +2504,6 @@ void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon, CIFS_MOUNT_POSIX_PATHS; } - /* We might be setting the path sep back to a different - form if we are reconnecting and the server switched its - posix path capability for this share */ - if (sb && (CIFS_SB(sb)->prepathlen > 0)) - CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb)); - if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) { if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) { CIFS_SB(sb)->rsize = 127 * 1024; @@ -2606,26 +2544,6 @@ void reset_cifs_unix_caps(int xid, struct cifs_tcon *tcon, } } -static void -convert_delimiter(char *path, char delim) -{ - int i; - char old_delim; - - if (path == NULL) - return; - - if (delim == '/') - old_delim = '\\'; - else - old_delim = '/'; - - for (i = 0; path[i] != '\0'; i++) { - if (path[i] == old_delim) - path[i] = delim; - } -} - void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, struct cifs_sb_info *cifs_sb) { @@ -2663,18 +2581,6 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, /* Windows ME may prefer this */ cFYI(1, "readsize set to minimum: 2048"); } - /* calculate prepath */ - cifs_sb->prepath = pvolume_info->prepath; - if (cifs_sb->prepath) { - cifs_sb->prepathlen = strlen(cifs_sb->prepath); - /* we can not convert the / to \ in the path - separators in the prefixpath yet because we do not - know (until reset_cifs_unix_caps is called later) - whether POSIX PATH CAP is available. We normalize - the / to \ after reset_cifs_unix_caps is called */ - pvolume_info->prepath = NULL; - } else - cifs_sb->prepathlen = 0; cifs_sb->mnt_uid = pvolume_info->linux_uid; cifs_sb->mnt_gid = pvolume_info->linux_gid; cifs_sb->mnt_file_mode = pvolume_info->file_mode; @@ -2786,24 +2692,13 @@ build_unc_path_to_root(const struct smb_vol *volume_info, char *full_path; int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1); - full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL); + full_path = kmalloc(unc_len + 1, GFP_KERNEL); if (full_path == NULL) return ERR_PTR(-ENOMEM); strncpy(full_path, volume_info->UNC, unc_len); - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { - int i; - for (i = 0; i < unc_len; i++) { - if (full_path[i] == '\\') - full_path[i] = '/'; - } - } - - if (cifs_sb->prepathlen) - strncpy(full_path + unc_len, cifs_sb->prepath, - cifs_sb->prepathlen); - - full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */ + full_path[unc_len] = 0; /* add trailing null */ + convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb)); return full_path; } @@ -2995,10 +2890,6 @@ try_mount_again: else tcon->unix_ext = 0; /* server does not support them */ - /* convert forward to back slashes in prepath here if needed */ - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) - convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb)); - if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) { cifs_sb->rsize = 1024 * 127; cFYI(DBG2, "no very large read support, rsize now 127K"); @@ -3029,10 +2920,10 @@ remote_path_check: } #endif - /* check if a whole path (including prepath) is not remote */ + /* check if a whole path is not remote */ if (!rc && tcon) { /* build_path_to_root works only when we have a valid tcon */ - full_path = cifs_build_path_to_root(cifs_sb, tcon); + full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon); if (full_path == NULL) { rc = -ENOMEM; goto mount_fail_check; @@ -3058,10 +2949,6 @@ remote_path_check: rc = -ELOOP; goto mount_fail_check; } - /* convert forward to back slashes in prepath here if needed */ - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) - convert_delimiter(cifs_sb->prepath, - CIFS_DIR_SEP(cifs_sb)); rc = expand_dfs_referral(xid, pSesInfo, volume_info, cifs_sb, true); @@ -3287,7 +3174,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) struct rb_root *root = &cifs_sb->tlink_tree; struct rb_node *node; struct tcon_link *tlink; - char *tmp; cancel_delayed_work_sync(&cifs_sb->prune_tlinks); @@ -3304,11 +3190,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) } spin_unlock(&cifs_sb->tlink_tree_lock); - tmp = cifs_sb->prepath; - cifs_sb->prepathlen = 0; - cifs_sb->prepath = NULL; - kfree(tmp); - return 0; } diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index ab74179..2be52f7 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -50,7 +50,6 @@ build_path_from_dentry(struct dentry *direntry) { struct dentry *temp; int namelen; - int pplen; int dfsplen; char *full_path; char dirsep; @@ -63,13 +62,12 @@ build_path_from_dentry(struct dentry *direntry) when the server crashed */ dirsep = CIFS_DIR_SEP(cifs_sb); - pplen = cifs_sb->prepathlen; if (tcon->Flags & SMB_SHARE_IS_IN_DFS) dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); else dfsplen = 0; cifs_bp_rename_retry: - namelen = pplen + dfsplen; + namelen = dfsplen; for (temp = direntry; !IS_ROOT(temp);) { namelen += (1 + temp->d_name.len); temp = temp->d_parent; @@ -100,7 +98,7 @@ cifs_bp_rename_retry: return NULL; } } - if (namelen != pplen + dfsplen) { + if (namelen != dfsplen) { cERROR(1, "did not end path lookup where expected namelen is %d", namelen); /* presumably this is only possible if racing with a rename @@ -126,7 +124,6 @@ cifs_bp_rename_retry: } } } - strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen); return full_path; } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index adb6324..a42edde 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -735,10 +735,10 @@ static const struct inode_operations cifs_ipc_inode_ops = { .lookup = cifs_lookup, }; -char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, - struct cifs_tcon *tcon) +char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, + struct cifs_tcon *tcon) { - int pplen = cifs_sb->prepathlen; + int pplen = vol->prepath ? strlen(vol->prepath) : 0; int dfsplen; char *full_path = NULL; @@ -772,7 +772,7 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, } } } - strncpy(full_path + dfsplen, cifs_sb->prepath, pplen); + strncpy(full_path + dfsplen, vol->prepath, pplen); full_path[dfsplen + pplen] = 0; /* add trailing null */ return full_path; } @@ -887,16 +887,17 @@ struct inode *cifs_root_iget(struct super_block *sb) char *full_path; struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); - full_path = cifs_build_path_to_root(cifs_sb, tcon); + full_path = kmalloc(1, GFP_KERNEL); if (full_path == NULL) return ERR_PTR(-ENOMEM); + full_path[0] = 0; xid = GetXid(); if (tcon->unix_ext) rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); else - rc = cifs_get_inode_info(&inode, full_path, NULL, sb, - xid, NULL); + rc = cifs_get_inode_info(&inode, full_path, NULL, sb, xid, + NULL); if (!inode) { inode = ERR_PTR(rc);