[CIFS] Migrate from prefixpath logic

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.

Reviewed-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>

Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Steve French 2011-05-27 03:50:55 +00:00
Родитель 641a58d66d
Коммит f87d39d951
7 изменённых файлов: 189 добавлений и 148 удалений

Просмотреть файл

@ -56,8 +56,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;

Просмотреть файл

@ -415,8 +415,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)
@ -530,6 +528,100 @@ 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, *alias;
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;
}
alias = d_materialise_unique(dchild, inode);
if (alias != NULL) {
dput(dchild);
if (IS_ERR(alias)) {
dput(dparent);
dparent = NULL;
goto out;
}
dchild = alias;
}
}
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);
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)
@ -585,7 +677,10 @@ 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)
goto out_super;
cFYI(1, "dentry root is: %p", root);
goto out;
out_super:

Просмотреть файл

@ -155,6 +155,61 @@ 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;
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;
@ -517,6 +572,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

Просмотреть файл

@ -57,8 +57,9 @@ extern int init_cifs_idmap(void);
extern void exit_cifs_idmap(void);
extern void cifs_destroy_idmaptrees(void);
extern char *build_path_from_dentry(struct dentry *);
extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
struct cifsTconInfo *tcon);
extern char *cifs_build_path_to_root(struct smb_vol *vol,
struct cifs_sb_info *cifs_sb,
struct cifsTconInfo *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,

Просмотреть файл

@ -57,61 +57,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;
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)
@ -2569,12 +2514,6 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *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;
@ -2619,26 +2558,6 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *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)
{
@ -2659,18 +2578,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;
@ -2834,24 +2741,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;
}
@ -3049,10 +2945,6 @@ try_mount_again:
CIFSSMBQFSAttributeInfo(xid, tcon);
}
/* 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");
@ -3082,10 +2974,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;
@ -3111,10 +3003,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);
@ -3340,7 +3228,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);
@ -3357,11 +3244,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;
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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 cifsTconInfo *tcon)
char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
struct cifsTconInfo *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;
}
@ -884,19 +884,13 @@ struct inode *cifs_root_iget(struct super_block *sb)
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct inode *inode = NULL;
long rc;
char *full_path;
struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
full_path = cifs_build_path_to_root(cifs_sb, tcon);
if (full_path == NULL)
return ERR_PTR(-ENOMEM);
xid = GetXid();
if (tcon->unix_ext)
rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
else
rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
xid, NULL);
rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
if (!inode) {
inode = ERR_PTR(rc);
@ -922,7 +916,6 @@ struct inode *cifs_root_iget(struct super_block *sb)
}
out:
kfree(full_path);
/* can not call macro FreeXid here since in a void func
* TODO: This is no longer true
*/