Commit 0d995b2b authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  [CIFS] Fix mem leak on dfs referral
  [CIFS] file create with acl support enabled is slow
  [CIFS] Fix mtime on cp -p when file data cached but written out too late
  [CIFS] Fix build problem
  [CIFS] cifs: replace remaining __FUNCTION__ occurrences
  [CIFS]  DFS patch that connects inode with dfs handling ops
parents 130eb465 04b6e6ec
...@@ -74,7 +74,7 @@ static char *cifs_get_share_name(const char *node_name) ...@@ -74,7 +74,7 @@ static char *cifs_get_share_name(const char *node_name)
pSep = memchr(UNC+2, '\\', len-2); pSep = memchr(UNC+2, '\\', len-2);
if (!pSep) { if (!pSep) {
cERROR(1, ("%s: no server name end in node name: %s", cERROR(1, ("%s: no server name end in node name: %s",
__FUNCTION__, node_name)); __func__, node_name));
kfree(UNC); kfree(UNC);
return NULL; return NULL;
} }
...@@ -84,7 +84,7 @@ static char *cifs_get_share_name(const char *node_name) ...@@ -84,7 +84,7 @@ static char *cifs_get_share_name(const char *node_name)
pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC)); pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
if (!pSep) { if (!pSep) {
cERROR(1, ("%s:2 cant find share name in node name: %s", cERROR(1, ("%s:2 cant find share name in node name: %s",
__FUNCTION__, node_name)); __func__, node_name));
kfree(UNC); kfree(UNC);
return NULL; return NULL;
} }
...@@ -127,7 +127,7 @@ static char *compose_mount_options(const char *sb_mountdata, ...@@ -127,7 +127,7 @@ static char *compose_mount_options(const char *sb_mountdata,
rc = dns_resolve_server_name_to_ip(*devname, &srvIP); rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
if (rc != 0) { if (rc != 0) {
cERROR(1, ("%s: Failed to resolve server part of %s to IP", cERROR(1, ("%s: Failed to resolve server part of %s to IP",
__FUNCTION__, *devname)); __func__, *devname));
mountdata = ERR_PTR(rc); mountdata = ERR_PTR(rc);
goto compose_mount_options_out; goto compose_mount_options_out;
} }
...@@ -181,8 +181,8 @@ static char *compose_mount_options(const char *sb_mountdata, ...@@ -181,8 +181,8 @@ static char *compose_mount_options(const char *sb_mountdata,
} }
} }
/*cFYI(1,("%s: parent mountdata: %s", __FUNCTION__,sb_mountdata));*/ /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
/*cFYI(1, ("%s: submount mountdata: %s", __FUNCTION__, mountdata ));*/ /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/
compose_mount_options_out: compose_mount_options_out:
kfree(srvIP); kfree(srvIP);
...@@ -302,7 +302,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) ...@@ -302,7 +302,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
int rc = 0; int rc = 0;
struct vfsmount *mnt = ERR_PTR(-ENOENT); struct vfsmount *mnt = ERR_PTR(-ENOENT);
cFYI(1, ("in %s", __FUNCTION__)); cFYI(1, ("in %s", __func__));
BUG_ON(IS_ROOT(dentry)); BUG_ON(IS_ROOT(dentry));
xid = GetXid(); xid = GetXid();
...@@ -336,7 +336,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) ...@@ -336,7 +336,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
len = strlen(referrals[i].node_name); len = strlen(referrals[i].node_name);
if (len < 2) { if (len < 2) {
cERROR(1, ("%s: Net Address path too short: %s", cERROR(1, ("%s: Net Address path too short: %s",
__FUNCTION__, referrals[i].node_name)); __func__, referrals[i].node_name));
rc = -EINVAL; rc = -EINVAL;
goto out_err; goto out_err;
} }
...@@ -344,7 +344,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) ...@@ -344,7 +344,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
nd->path.dentry, nd->path.dentry,
referrals[i].node_name); referrals[i].node_name);
cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
__FUNCTION__, __func__,
referrals[i].node_name, mnt)); referrals[i].node_name, mnt));
/* complete mount procedure if we accured submount */ /* complete mount procedure if we accured submount */
...@@ -365,7 +365,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) ...@@ -365,7 +365,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
FreeXid(xid); FreeXid(xid);
free_dfs_info_array(referrals, num_referrals); free_dfs_info_array(referrals, num_referrals);
kfree(full_path); kfree(full_path);
cFYI(1, ("leaving %s" , __FUNCTION__)); cFYI(1, ("leaving %s" , __func__));
return ERR_PTR(rc); return ERR_PTR(rc);
out_err: out_err:
path_put(&nd->path); path_put(&nd->path);
......
/* /*
* fs/cifs/cifsacl.c * fs/cifs/cifsacl.c
* *
* Copyright (C) International Business Machines Corp., 2007 * Copyright (C) International Business Machines Corp., 2007,2008
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* Contains the routines for mapping CIFS/NTFS ACLs * Contains the routines for mapping CIFS/NTFS ACLs
...@@ -556,9 +556,9 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, ...@@ -556,9 +556,9 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
/* Retrieve an ACL from the server */ /* Retrieve an ACL from the server */
static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
const char *path) const char *path, const __u16 *pfid)
{ {
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file = NULL;
int unlock_file = FALSE; int unlock_file = FALSE;
int xid; int xid;
int rc = -EIO; int rc = -EIO;
...@@ -573,7 +573,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, ...@@ -573,7 +573,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
return NULL; return NULL;
xid = GetXid(); xid = GetXid();
if (pfid == NULL)
open_file = find_readable_file(CIFS_I(inode)); open_file = find_readable_file(CIFS_I(inode));
else
fid = *pfid;
sb = inode->i_sb; sb = inode->i_sb;
if (sb == NULL) { if (sb == NULL) {
FreeXid(xid); FreeXid(xid);
...@@ -584,7 +588,7 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, ...@@ -584,7 +588,7 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
if (open_file) { if (open_file) {
unlock_file = TRUE; unlock_file = TRUE;
fid = open_file->netfid; fid = open_file->netfid;
} else { } else if (pfid == NULL) {
int oplock = FALSE; int oplock = FALSE;
/* open file */ /* open file */
rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
...@@ -600,10 +604,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode, ...@@ -600,10 +604,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen)); cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
if (unlock_file == TRUE) if (unlock_file == TRUE) /* find_readable_file increments ref count */
atomic_dec(&open_file->wrtPending); atomic_dec(&open_file->wrtPending);
else else if (pfid == NULL) /* if opened above we have to close the handle */
CIFSSMBClose(xid, cifs_sb->tcon, fid); CIFSSMBClose(xid, cifs_sb->tcon, fid);
/* else handle was passed in by caller */
FreeXid(xid); FreeXid(xid);
return pntsd; return pntsd;
...@@ -664,14 +669,14 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, ...@@ -664,14 +669,14 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
} }
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
void acl_to_uid_mode(struct inode *inode, const char *path) void acl_to_uid_mode(struct inode *inode, const char *path, const __u16 *pfid)
{ {
struct cifs_ntsd *pntsd = NULL; struct cifs_ntsd *pntsd = NULL;
u32 acllen = 0; u32 acllen = 0;
int rc = 0; int rc = 0;
cFYI(DBG2, ("converting ACL to mode for %s", path)); cFYI(DBG2, ("converting ACL to mode for %s", path));
pntsd = get_cifs_acl(&acllen, inode, path); pntsd = get_cifs_acl(&acllen, inode, path, pfid);
/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
if (pntsd) if (pntsd)
...@@ -694,7 +699,7 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) ...@@ -694,7 +699,7 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
cFYI(DBG2, ("set ACL from mode for %s", path)); cFYI(DBG2, ("set ACL from mode for %s", path));
/* Get the security descriptor */ /* Get the security descriptor */
pntsd = get_cifs_acl(&acllen, inode, path); pntsd = get_cifs_acl(&acllen, inode, path, NULL);
/* Add three ACEs for owner, group, everyone getting rid of /* Add three ACEs for owner, group, everyone getting rid of
other ACEs as chmod disables ACEs and set the security descriptor */ other ACEs as chmod disables ACEs and set the security descriptor */
......
...@@ -39,8 +39,8 @@ extern int smb_send(struct socket *, struct smb_hdr *, ...@@ -39,8 +39,8 @@ extern int smb_send(struct socket *, struct smb_hdr *,
unsigned int /* length */ , struct sockaddr *); unsigned int /* length */ , struct sockaddr *);
extern unsigned int _GetXid(void); extern unsigned int _GetXid(void);
extern void _FreeXid(unsigned int); extern void _FreeXid(unsigned int);
#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid)); #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid));
#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));} #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));}
extern char *build_path_from_dentry(struct dentry *); extern char *build_path_from_dentry(struct dentry *);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry); extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
/* extern void renew_parental_timestamps(struct dentry *direntry);*/ /* extern void renew_parental_timestamps(struct dentry *direntry);*/
...@@ -92,11 +92,12 @@ extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time); ...@@ -92,11 +92,12 @@ extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
extern int cifs_get_inode_info(struct inode **pinode, extern int cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path, const unsigned char *search_path,
FILE_ALL_INFO * pfile_info, FILE_ALL_INFO * pfile_info,
struct super_block *sb, int xid); struct super_block *sb, int xid, const __u16 *pfid);
extern int cifs_get_inode_info_unix(struct inode **pinode, extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path, const unsigned char *search_path,
struct super_block *sb, int xid); struct super_block *sb, int xid);
extern void acl_to_uid_mode(struct inode *inode, const char *search_path); extern void acl_to_uid_mode(struct inode *inode, const char *path,
const __u16 *pfid);
extern int mode_to_acl(struct inode *inode, const char *path, __u64); extern int mode_to_acl(struct inode *inode, const char *path, __u64);
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
......
...@@ -229,7 +229,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -229,7 +229,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
inode->i_sb, xid); inode->i_sb, xid);
else { else {
rc = cifs_get_inode_info(&newinode, full_path, rc = cifs_get_inode_info(&newinode, full_path,
buf, inode->i_sb, xid); buf, inode->i_sb, xid,
&fileHandle);
if (newinode) { if (newinode) {
newinode->i_mode = mode; newinode->i_mode = mode;
if ((oplock & CIFS_CREATE_ACTION) && if ((oplock & CIFS_CREATE_ACTION) &&
...@@ -483,7 +484,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -483,7 +484,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
parent_dir_inode->i_sb, xid); parent_dir_inode->i_sb, xid);
else else
rc = cifs_get_inode_info(&newInode, full_path, NULL, rc = cifs_get_inode_info(&newInode, full_path, NULL,
parent_dir_inode->i_sb, xid); parent_dir_inode->i_sb, xid, NULL);
if ((rc == 0) && (newInode != NULL)) { if ((rc == 0) && (newInode != NULL)) {
if (pTcon->nocase) if (pTcon->nocase)
......
...@@ -77,14 +77,14 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) ...@@ -77,14 +77,14 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
/* search for server name delimiter */ /* search for server name delimiter */
len = strlen(unc); len = strlen(unc);
if (len < 3) { if (len < 3) {
cFYI(1, ("%s: unc is too short: %s", __FUNCTION__, unc)); cFYI(1, ("%s: unc is too short: %s", __func__, unc));
return -EINVAL; return -EINVAL;
} }
len -= 2; len -= 2;
name = memchr(unc+2, '\\', len); name = memchr(unc+2, '\\', len);
if (!name) { if (!name) {
cFYI(1, ("%s: probably server name is whole unc: %s", cFYI(1, ("%s: probably server name is whole unc: %s",
__FUNCTION__, unc)); __func__, unc));
} else { } else {
len = (name - unc) - 2/* leading // */; len = (name - unc) - 2/* leading // */;
} }
...@@ -104,7 +104,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) ...@@ -104,7 +104,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
if (*ip_addr) { if (*ip_addr) {
memcpy(*ip_addr, rkey->payload.data, len); memcpy(*ip_addr, rkey->payload.data, len);
(*ip_addr)[len] = '\0'; (*ip_addr)[len] = '\0';
cFYI(1, ("%s: resolved: %s to %s", __FUNCTION__, cFYI(1, ("%s: resolved: %s to %s", __func__,
rkey->description, rkey->description,
*ip_addr *ip_addr
)); ));
...@@ -114,7 +114,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) ...@@ -114,7 +114,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
} }
key_put(rkey); key_put(rkey);
} else { } else {
cERROR(1, ("%s: unable to resolve: %s", __FUNCTION__, name)); cERROR(1, ("%s: unable to resolve: %s", __func__, name));
} }
kfree(name); kfree(name);
......
...@@ -145,7 +145,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, ...@@ -145,7 +145,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
full_path, inode->i_sb, xid); full_path, inode->i_sb, xid);
else else
rc = cifs_get_inode_info(&file->f_path.dentry->d_inode, rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
full_path, buf, inode->i_sb, xid); full_path, buf, inode->i_sb, xid, NULL);
if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = TRUE; pCifsInode->clientCanCacheAll = TRUE;
...@@ -440,7 +440,7 @@ static int cifs_reopen_file(struct file *file, int can_flush) ...@@ -440,7 +440,7 @@ static int cifs_reopen_file(struct file *file, int can_flush)
else else
rc = cifs_get_inode_info(&inode, rc = cifs_get_inode_info(&inode,
full_path, NULL, inode->i_sb, full_path, NULL, inode->i_sb,
xid); xid, NULL);
} /* else we are writing out data to server already } /* else we are writing out data to server already
and could deadlock if we tried to flush data, and and could deadlock if we tried to flush data, and
since we do not know if we have data that would since we do not know if we have data that would
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include "cifs_fs_sb.h" #include "cifs_fs_sb.h"
static void cifs_set_ops(struct inode *inode) static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
{ {
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
...@@ -57,8 +57,16 @@ static void cifs_set_ops(struct inode *inode) ...@@ -57,8 +57,16 @@ static void cifs_set_ops(struct inode *inode)
inode->i_data.a_ops = &cifs_addr_ops; inode->i_data.a_ops = &cifs_addr_ops;
break; break;
case S_IFDIR: case S_IFDIR:
#ifdef CONFIG_CIFS_DFS_UPCALL
if (is_dfs_referral) {
inode->i_op = &cifs_dfs_referral_inode_operations;
} else {
#else /* NO DFS support, treat as a directory */
{
#endif
inode->i_op = &cifs_dir_inode_ops; inode->i_op = &cifs_dir_inode_ops;
inode->i_fop = &cifs_dir_ops; inode->i_fop = &cifs_dir_ops;
}
break; break;
case S_IFLNK: case S_IFLNK:
inode->i_op = &cifs_symlink_inode_ops; inode->i_op = &cifs_symlink_inode_ops;
...@@ -153,6 +161,30 @@ static void cifs_unix_info_to_inode(struct inode *inode, ...@@ -153,6 +161,30 @@ static void cifs_unix_info_to_inode(struct inode *inode,
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
static const unsigned char *cifs_get_search_path(struct cifsTconInfo *pTcon,
const char *search_path)
{
int tree_len;
int path_len;
char *tmp_path;
if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
return search_path;
/* use full path name for working with DFS */
tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1);
path_len = strnlen(search_path, MAX_PATHCONF);
tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL);
if (tmp_path == NULL)
return search_path;
strncpy(tmp_path, pTcon->treeName, tree_len);
strncpy(tmp_path+tree_len, search_path, path_len);
tmp_path[tree_len+path_len] = 0;
return tmp_path;
}
int cifs_get_inode_info_unix(struct inode **pinode, int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path, struct super_block *sb, int xid) const unsigned char *search_path, struct super_block *sb, int xid)
{ {
...@@ -161,41 +193,31 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -161,41 +193,31 @@ int cifs_get_inode_info_unix(struct inode **pinode,
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode *inode; struct inode *inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
char *tmp_path; const unsigned char *full_path;
bool is_dfs_referral = false;
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
cFYI(1, ("Getting info on %s", search_path)); cFYI(1, ("Getting info on %s", search_path));
full_path = cifs_get_search_path(pTcon, search_path);
try_again_CIFSSMBUnixQPathInfo:
/* could have done a find first instead but this returns more info */ /* could have done a find first instead but this returns more info */
rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
/* dump_mem("\nUnixQPathInfo return data", &findData, /* dump_mem("\nUnixQPathInfo return data", &findData,
sizeof(findData)); */ sizeof(findData)); */
if (rc) { if (rc) {
if (rc == -EREMOTE) { if (rc == -EREMOTE && !is_dfs_referral) {
tmp_path = is_dfs_referral = true;
kmalloc(strnlen(pTcon->treeName, if (full_path != search_path) {
MAX_TREE_SIZE + 1) + kfree(full_path);
strnlen(search_path, MAX_PATHCONF) + 1, full_path = search_path;
GFP_KERNEL); }
if (tmp_path == NULL) goto try_again_CIFSSMBUnixQPathInfo;
return -ENOMEM;
/* have to skip first of the double backslash of
UNC name */
strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
strncat(tmp_path, search_path, MAX_PATHCONF);
rc = connect_to_dfs_path(xid, pTcon->ses,
/* treename + */ tmp_path,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
kfree(tmp_path);
/* BB fix up inode etc. */
} else if (rc) {
return rc;
} }
goto cgiiu_exit;
} else { } else {
struct cifsInodeInfo *cifsInfo; struct cifsInodeInfo *cifsInfo;
__u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes); __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
...@@ -204,8 +226,10 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -204,8 +226,10 @@ int cifs_get_inode_info_unix(struct inode **pinode,
/* get new inode */ /* get new inode */
if (*pinode == NULL) { if (*pinode == NULL) {
*pinode = new_inode(sb); *pinode = new_inode(sb);
if (*pinode == NULL) if (*pinode == NULL) {
return -ENOMEM; rc = -ENOMEM;
goto cgiiu_exit;
}
/* Is an i_ino of zero legal? */ /* Is an i_ino of zero legal? */
/* Are there sanity checks we can use to ensure that /* Are there sanity checks we can use to ensure that
the server is really filling in that field? */ the server is really filling in that field? */
...@@ -237,8 +261,11 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -237,8 +261,11 @@ int cifs_get_inode_info_unix(struct inode **pinode,
(unsigned long) inode->i_size, (unsigned long) inode->i_size,
(unsigned long long)inode->i_blocks)); (unsigned long long)inode->i_blocks));
cifs_set_ops(inode); cifs_set_ops(inode, is_dfs_referral);
} }
cgiiu_exit:
if (full_path != search_path)
kfree(full_path);
return rc; return rc;
} }
...@@ -347,15 +374,16 @@ static int get_sfu_mode(struct inode *inode, ...@@ -347,15 +374,16 @@ static int get_sfu_mode(struct inode *inode,
int cifs_get_inode_info(struct inode **pinode, int cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path, FILE_ALL_INFO *pfindData, const unsigned char *search_path, FILE_ALL_INFO *pfindData,
struct super_block *sb, int xid) struct super_block *sb, int xid, const __u16 *pfid)
{ {
int rc = 0; int rc = 0;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode *inode; struct inode *inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
char *tmp_path; const unsigned char *full_path = NULL;
char *buf = NULL; char *buf = NULL;
int adjustTZ = FALSE; int adjustTZ = FALSE;
bool is_dfs_referral = false;
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
cFYI(1, ("Getting info on %s", search_path)); cFYI(1, ("Getting info on %s", search_path));
...@@ -373,8 +401,12 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -373,8 +401,12 @@ int cifs_get_inode_info(struct inode **pinode,
if (buf == NULL) if (buf == NULL)
return -ENOMEM; return -ENOMEM;
pfindData = (FILE_ALL_INFO *)buf; pfindData = (FILE_ALL_INFO *)buf;
full_path = cifs_get_search_path(pTcon, search_path);
try_again_CIFSSMBQPathInfo:
/* could do find first instead but this returns more info */ /* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
0 /* not legacy */, 0 /* not legacy */,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
...@@ -382,7 +414,7 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -382,7 +414,7 @@ int cifs_get_inode_info(struct inode **pinode,
when server claims no NT SMB support and the above call when server claims no NT SMB support and the above call
failed at least once - set flag in tcon or mount */ failed at least once - set flag in tcon or mount */
if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
rc = SMBQueryInformation(xid, pTcon, search_path, rc = SMBQueryInformation(xid, pTcon, full_path,
pfindData, cifs_sb->local_nls, pfindData, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
...@@ -391,31 +423,15 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -391,31 +423,15 @@ int cifs_get_inode_info(struct inode **pinode,
} }
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) { if (rc) {
if (rc == -EREMOTE) { if (rc == -EREMOTE && !is_dfs_referral) {
tmp_path = is_dfs_referral = true;
kmalloc(strnlen if (full_path != search_path) {
(pTcon->treeName, kfree(full_path);
MAX_TREE_SIZE + 1) + full_path = search_path;
strnlen(search_path, MAX_PATHCONF) + 1,
GFP_KERNEL);
if (tmp_path == NULL) {
kfree(buf);
return -ENOMEM;
} }
goto try_again_CIFSSMBQPathInfo;
strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
strncat(tmp_path, search_path, MAX_PATHCONF);
rc = connect_to_dfs_path(xid, pTcon->ses,
/* treename + */ tmp_path,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
kfree(tmp_path);
/* BB fix up inode etc. */
} else if (rc) {
kfree(buf);
return rc;
} }
goto cgii_exit;
} else { } else {
struct cifsInodeInfo *cifsInfo; struct cifsInodeInfo *cifsInfo;
__u32 attr = le32_to_cpu(pfindData->Attributes); __u32 attr = le32_to_cpu(pfindData->Attributes);
...@@ -424,8 +440,8 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -424,8 +440,8 @@ int cifs_get_inode_info(struct inode **pinode,
if (*pinode == NULL) { if (*pinode == NULL) {
*pinode = new_inode(sb); *pinode = new_inode(sb);
if (*pinode == NULL) { if (*pinode == NULL) {
kfree(buf); rc = -ENOMEM;
return -ENOMEM; goto cgii_exit;
} }
/* Is an i_ino of zero legal? Can we use that to check /* Is an i_ino of zero legal? Can we use that to check
if the server supports returning inode numbers? Are if the server supports returning inode numbers? Are
...@@ -559,7 +575,7 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -559,7 +575,7 @@ int cifs_get_inode_info(struct inode **pinode,
/* fill in 0777 bits from ACL */ /* fill in 0777 bits from ACL */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
cFYI(1, ("Getting mode bits from ACL")); cFYI(1, ("Getting mode bits from ACL"));
acl_to_uid_mode(inode, search_path); acl_to_uid_mode(inode, search_path, pfid);
} }
#endif #endif
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
...@@ -573,8 +589,11 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -573,8 +589,11 @@ int cifs_get_inode_info(struct inode **pinode,
atomic_set(&cifsInfo->inUse, 1); atomic_set(&cifsInfo->inUse, 1);
} }
cifs_set_ops(inode); cifs_set_ops(inode, is_dfs_referral);
} }
cgii_exit:
if (full_path != search_path)
kfree(full_path);
kfree(buf); kfree(buf);
return rc; return rc;
} }
...@@ -603,7 +622,8 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) ...@@ -603,7 +622,8 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
if (cifs_sb->tcon->unix_ext) if (cifs_sb->tcon->unix_ext)
rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
else else
rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid,
NULL);
if (rc && cifs_sb->tcon->ipc) { if (rc && cifs_sb->tcon->ipc) {
cFYI(1, ("ipc connection - fake read inode")); cFYI(1, ("ipc connection - fake read inode"));
inode->i_mode |= S_IFDIR; inode->i_mode |= S_IFDIR;
...@@ -804,7 +824,7 @@ static void posix_fill_in_inode(struct inode *tmp_inode, ...@@ -804,7 +824,7 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
local_size = tmp_inode->i_size; local_size = tmp_inode->i_size;
cifs_unix_info_to_inode(tmp_inode, pData, 1); cifs_unix_info_to_inode(tmp_inode, pData, 1);
cifs_set_ops(tmp_inode); cifs_set_ops(tmp_inode, false);
if (!S_ISREG(tmp_inode->i_mode)) if (!S_ISREG(tmp_inode->i_mode))
return; return;
...@@ -936,7 +956,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -936,7 +956,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
inode->i_sb, xid); inode->i_sb, xid);
else else
rc = cifs_get_inode_info(&newinode, full_path, NULL, rc = cifs_get_inode_info(&newinode, full_path, NULL,
inode->i_sb, xid); inode->i_sb, xid, NULL);
if (pTcon->nocase) if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops; direntry->d_op = &cifs_ci_dentry_ops;
...@@ -1218,7 +1238,7 @@ int cifs_revalidate(struct dentry *direntry) ...@@ -1218,7 +1238,7 @@ int cifs_revalidate(struct dentry *direntry)
} }
} else { } else {
rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
direntry->d_sb, xid); direntry->d_sb, xid, NULL);
if (rc) { if (rc) {
cFYI(1, ("error on getting revalidate info %d", rc)); cFYI(1, ("error on getting revalidate info %d", rc));
/* if (rc != -ENOENT) /* if (rc != -ENOENT)
...@@ -1407,11 +1427,10 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1407,11 +1427,10 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
} }
cifsInode = CIFS_I(direntry->d_inode); cifsInode = CIFS_I(direntry->d_inode);
/* BB check if we need to refresh inode from server now ? BB */ if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
if (attrs->ia_valid & ATTR_SIZE) {
/* /*
Flush data before changing file size on server. If the Flush data before changing file size or changing the last
write time of the file on the server. If the
flush returns error, store it to report later and continue. flush returns error, store it to report later and continue.
BB: This should be smarter. Why bother flushing pages that BB: This should be smarter. Why bother flushing pages that
will be truncated anyway? Also, should we error out here if will be truncated anyway? Also, should we error out here if
...@@ -1422,7 +1441,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1422,7 +1441,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
CIFS_I(direntry->d_inode)->write_behind_rc = rc; CIFS_I(direntry->d_inode)->write_behind_rc = rc;
rc = 0; rc = 0;
} }
}
if (attrs->ia_valid & ATTR_SIZE) {
/* To avoid spurious oplock breaks from server, in the case of /* To avoid spurious oplock breaks from server, in the case of
inodes that we already have open, avoid doing path based inodes that we already have open, avoid doing path based
setting of file size if we can do it by handle. setting of file size if we can do it by handle.
......
...@@ -205,7 +205,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) ...@@ -205,7 +205,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
inode->i_sb, xid); inode->i_sb, xid);
else else
rc = cifs_get_inode_info(&newinode, full_path, NULL, rc = cifs_get_inode_info(&newinode, full_path, NULL,
inode->i_sb, xid); inode->i_sb, xid, NULL);
if (rc != 0) { if (rc != 0) {
cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d", cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment