Commit d2ecad9f 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: (56 commits)
  [CIFS] move close processing  from cifs_close to cifsFileInfo_put
  cifs: convert cifs_tcp_ses_lock from a rwlock to a spinlock
  cifs: cancel_delayed_work() + flush_scheduled_work() -> cancel_delayed_work_sync()
  Clean up two declarations of blob_len
  cifs: move cifsFileInfo_put to file.c
  cifs: convert GlobalSMBSeslock from a rwlock to regular spinlock
  [CIFS] Fix minor checkpatch warning and update cifs version
  cifs: move cifs_new_fileinfo to file.c
  cifs: eliminate pfile pointer from cifsFileInfo
  cifs: cifs_write argument change and cleanup
  cifs: clean up cifs_reopen_file
  cifs: eliminate the inode argument from cifs_new_fileinfo
  cifs: eliminate oflags option from cifs_new_fileinfo
  cifs: fix flags handling in cifs_posix_open
  cifs: eliminate cifs_posix_open_inode_helper
  cifs: handle FindFirst failure gracefully
  NTLM authentication and signing - Calculate auth response per smb session
  cifs: don't use vfsmount to pin superblock for oplock breaks
  cifs: keep dentry reference in cifsFileInfo instead of inode reference
  cifs: on multiuser mount, set ownership to current_fsuid/current_fsgid (try #7)
  ...

Fix up trivial conflict in fs/cifs/cifsfs.c due to added/removed header files
parents c70b5296 cdff08e7
......@@ -527,6 +527,11 @@ A partial list of the supported mount options follows:
SFU does). In the future the bottom 9 bits of the
mode also will be emulated using queries of the security
descriptor (ACL).
mfsymlinks Enable support for Minshall+French symlinks
(see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks)
This option is ignored when specified together with the
'sfu' option. Minshall+French symlinks are used even if
the server supports the CIFS Unix Extensions.
sign Must use packet signing (helps avoid unwanted data modification
by intermediate systems in the route). Note that signing
does not work with lanman or plaintext authentication.
......
......@@ -148,7 +148,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
seq_printf(m, "Servers:");
i = 0;
read_lock(&cifs_tcp_ses_lock);
spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp1, &cifs_tcp_ses_list) {
server = list_entry(tmp1, struct TCP_Server_Info,
tcp_ses_list);
......@@ -230,7 +230,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
spin_unlock(&GlobalMid_Lock);
}
}
read_unlock(&cifs_tcp_ses_lock);
spin_unlock(&cifs_tcp_ses_lock);
seq_putc(m, '\n');
/* BB add code to dump additional info such as TCP session info now */
......@@ -270,7 +270,7 @@ static ssize_t cifs_stats_proc_write(struct file *file,
atomic_set(&totBufAllocCount, 0);
atomic_set(&totSmBufAllocCount, 0);
#endif /* CONFIG_CIFS_STATS2 */
read_lock(&cifs_tcp_ses_lock);
spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp1, &cifs_tcp_ses_list) {
server = list_entry(tmp1, struct TCP_Server_Info,
tcp_ses_list);
......@@ -303,7 +303,7 @@ static ssize_t cifs_stats_proc_write(struct file *file,
}
}
}
read_unlock(&cifs_tcp_ses_lock);
spin_unlock(&cifs_tcp_ses_lock);
}
return count;
......@@ -343,7 +343,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
GlobalCurrentXid, GlobalMaxActiveXid);
i = 0;
read_lock(&cifs_tcp_ses_lock);
spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp1, &cifs_tcp_ses_list) {
server = list_entry(tmp1, struct TCP_Server_Info,
tcp_ses_list);
......@@ -397,7 +397,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
}
}
}
read_unlock(&cifs_tcp_ses_lock);
spin_unlock(&cifs_tcp_ses_lock);
seq_putc(m, '\n');
return 0;
......
......@@ -34,7 +34,7 @@ void cifs_dump_mids(struct TCP_Server_Info *);
extern int traceSMB; /* flag which enables the function below */
void dump_smb(struct smb_hdr *, int);
#define CIFS_INFO 0x01
#define CIFS_RC 0x02
#define CIFS_RC 0x02
#define CIFS_TIMER 0x04
/*
......
......@@ -44,8 +44,7 @@ static void cifs_dfs_expire_automounts(struct work_struct *work)
void cifs_dfs_release_automount_timer(void)
{
BUG_ON(!list_empty(&cifs_dfs_automount_list));
cancel_delayed_work(&cifs_dfs_automount_task);
flush_scheduled_work();
cancel_delayed_work_sync(&cifs_dfs_automount_task);
}
/**
......@@ -306,6 +305,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
int xid, i;
int rc = 0;
struct vfsmount *mnt = ERR_PTR(-ENOENT);
struct tcon_link *tlink;
cFYI(1, "in %s", __func__);
BUG_ON(IS_ROOT(dentry));
......@@ -315,14 +315,6 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
dput(nd->path.dentry);
nd->path.dentry = dget(dentry);
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
ses = cifs_sb->tcon->ses;
if (!ses) {
rc = -EINVAL;
goto out_err;
}
/*
* The MSDFS spec states that paths in DFS referral requests and
* responses must be prefixed by a single '\' character instead of
......@@ -335,10 +327,20 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
goto out_err;
}
rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb->local_nls,
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) {
rc = PTR_ERR(tlink);
goto out_err;
}
ses = tlink_tcon(tlink)->ses;
rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls,
&num_referrals, &referrals,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
cifs_put_tlink(tlink);
for (i = 0; i < num_referrals; i++) {
int len;
dump_referral(referrals+i);
......
......@@ -15,6 +15,8 @@
* the GNU Lesser General Public License for more details.
*
*/
#include <linux/radix-tree.h>
#ifndef _CIFS_FS_SB_H
#define _CIFS_FS_SB_H
......@@ -36,23 +38,28 @@
#define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */
#define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/
#define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */
#define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */
#define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */
struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */
struct list_head nested_tcon_q;
struct radix_tree_root tlink_tree;
#define CIFS_TLINK_MASTER_TAG 0 /* is "master" (mount) tcon */
spinlock_t tlink_tree_lock;
struct nls_table *local_nls;
unsigned int rsize;
unsigned int wsize;
atomic_t active;
uid_t mnt_uid;
gid_t mnt_gid;
mode_t mnt_file_mode;
mode_t mnt_dir_mode;
int mnt_cifs_flags;
unsigned int mnt_cifs_flags;
int prepathlen;
char *prepath; /* relative path under the share to mount to */
#ifdef CONFIG_CIFS_DFS_UPCALL
char *mountdata; /* mount options received at mount time */
#endif
struct backing_dev_info bdi;
struct delayed_work prune_tlinks;
};
#endif /* _CIFS_FS_SB_H */
......@@ -557,11 +557,16 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
{
struct cifs_ntsd *pntsd = NULL;
int xid, rc;
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return NULL;
xid = GetXid();
rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
FreeXid(xid);
cifs_put_tlink(tlink);
cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);
return pntsd;
......@@ -574,10 +579,16 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
int oplock = 0;
int xid, rc;
__u16 fid;
struct cifsTconInfo *tcon;
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return NULL;
tcon = tlink_tcon(tlink);
xid = GetXid();
rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, READ_CONTROL, 0,
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
&fid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
......@@ -585,11 +596,12 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
goto out;
}
rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);
CIFSSMBClose(xid, cifs_sb->tcon, fid);
CIFSSMBClose(xid, tcon, fid);
out:
cifs_put_tlink(tlink);
FreeXid(xid);
return pntsd;
}
......@@ -603,7 +615,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
struct cifsFileInfo *open_file = NULL;
if (inode)
open_file = find_readable_file(CIFS_I(inode));
open_file = find_readable_file(CIFS_I(inode), true);
if (!open_file)
return get_cifs_acl_by_path(cifs_sb, path, pacllen);
......@@ -616,10 +628,15 @@ static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
struct cifs_ntsd *pnntsd, u32 acllen)
{
int xid, rc;
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
xid = GetXid();
rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
FreeXid(xid);
cifs_put_tlink(tlink);
cFYI(DBG2, "SetCIFSACL rc = %d", rc);
return rc;
......@@ -631,10 +648,16 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
int oplock = 0;
int xid, rc;
__u16 fid;
struct cifsTconInfo *tcon;
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
tcon = tlink_tcon(tlink);
xid = GetXid();
rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, WRITE_DAC, 0,
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
&fid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
......@@ -642,12 +665,13 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
goto out;
}
rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
cFYI(DBG2, "SetCIFSACL rc = %d", rc);
CIFSSMBClose(xid, cifs_sb->tcon, fid);
out:
CIFSSMBClose(xid, tcon, fid);
out:
FreeXid(xid);
cifs_put_tlink(tlink);
return rc;
}
......@@ -661,7 +685,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
open_file = find_readable_file(CIFS_I(inode));
open_file = find_readable_file(CIFS_I(inode), true);
if (!open_file)
return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
......
This diff is collapsed.
......@@ -35,6 +35,7 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <net/ipv6.h>
#include "cifsfs.h"
#include "cifspdu.h"
#define DECLARE_GLOBALS_HERE
......@@ -81,6 +82,24 @@ extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
extern mempool_t *cifs_mid_poolp;
void
cifs_sb_active(struct super_block *sb)
{
struct cifs_sb_info *server = CIFS_SB(sb);
if (atomic_inc_return(&server->active) == 1)
atomic_inc(&sb->s_active);
}
void
cifs_sb_deactive(struct super_block *sb)
{
struct cifs_sb_info *server = CIFS_SB(sb);
if (atomic_dec_and_test(&server->active))
deactivate_super(sb);
}
static int
cifs_read_super(struct super_block *sb, void *data,
const char *devname, int silent)
......@@ -96,6 +115,9 @@ cifs_read_super(struct super_block *sb, void *data,
if (cifs_sb == NULL)
return -ENOMEM;
spin_lock_init(&cifs_sb->tlink_tree_lock);
INIT_RADIX_TREE(&cifs_sb->tlink_tree, GFP_KERNEL);
rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
if (rc) {
kfree(cifs_sb);
......@@ -135,9 +157,6 @@ cifs_read_super(struct super_block *sb, void *data,
sb->s_magic = CIFS_MAGIC_NUMBER;
sb->s_op = &cifs_super_ops;
sb->s_bdi = &cifs_sb->bdi;
/* if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
sb->s_blocksize =
cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
sb->s_blocksize = CIFS_MAX_MSGSIZE;
sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */
inode = cifs_root_iget(sb, ROOT_I);
......@@ -219,7 +238,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *tcon = cifs_sb->tcon;
struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
int rc = -EOPNOTSUPP;
int xid;
......@@ -361,14 +380,36 @@ static int
cifs_show_options(struct seq_file *s, struct vfsmount *m)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(m->mnt_sb);
struct cifsTconInfo *tcon = cifs_sb->tcon;
struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
struct sockaddr *srcaddr;
srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr;
seq_printf(s, ",unc=%s", tcon->treeName);
if (tcon->ses->userName)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
seq_printf(s, ",multiuser");
else if (tcon->ses->userName)
seq_printf(s, ",username=%s", tcon->ses->userName);
if (tcon->ses->domainName)
seq_printf(s, ",domain=%s", tcon->ses->domainName);
if (srcaddr->sa_family != AF_UNSPEC) {
struct sockaddr_in *saddr4;
struct sockaddr_in6 *saddr6;
saddr4 = (struct sockaddr_in *)srcaddr;
saddr6 = (struct sockaddr_in6 *)srcaddr;
if (srcaddr->sa_family == AF_INET6)
seq_printf(s, ",srcaddr=%pI6c",
&saddr6->sin6_addr);
else if (srcaddr->sa_family == AF_INET)
seq_printf(s, ",srcaddr=%pI4",
&saddr4->sin_addr.s_addr);
else
seq_printf(s, ",srcaddr=BAD-AF:%i",
(int)(srcaddr->sa_family));
}
seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
seq_printf(s, ",forceuid");
......@@ -417,6 +458,8 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
seq_printf(s, ",dynperm");
if (m->mnt_sb->s_flags & MS_POSIXACL)
seq_printf(s, ",acl");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
seq_printf(s, ",mfsymlinks");
seq_printf(s, ",rsize=%d", cifs_sb->rsize);
seq_printf(s, ",wsize=%d", cifs_sb->wsize);
......@@ -432,20 +475,18 @@ static void cifs_umount_begin(struct super_block *sb)
if (cifs_sb == NULL)
return;
tcon = cifs_sb->tcon;
if (tcon == NULL)
return;
tcon = cifs_sb_master_tcon(cifs_sb);
read_lock(&cifs_tcp_ses_lock);
spin_lock(&cifs_tcp_ses_lock);
if ((tcon->tc_count > 1) || (tcon->tidStatus == CifsExiting)) {
/* we have other mounts to same share or we have
already tried to force umount this and woken up
all waiting network requests, nothing to do */
read_unlock(&cifs_tcp_ses_lock);
spin_unlock(&cifs_tcp_ses_lock);
return;
} else if (tcon->tc_count == 1)
tcon->tidStatus = CifsExiting;
read_unlock(&cifs_tcp_ses_lock);
spin_unlock(&cifs_tcp_ses_lock);
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
/* cancel_notify_requests(tcon); */
......@@ -565,6 +606,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
/* note that this is called by vfs setlease with lock_flocks held
to protect *lease from going away */
struct inode *inode = file->f_path.dentry->d_inode;
struct cifsFileInfo *cfile = file->private_data;
if (!(S_ISREG(inode->i_mode)))
return -EINVAL;
......@@ -575,8 +617,8 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
((arg == F_WRLCK) &&
(CIFS_I(inode)->clientCanCacheAll)))
return generic_setlease(file, arg, lease);
else if (CIFS_SB(inode->i_sb)->tcon->local_lease &&
!CIFS_I(inode)->clientCanCacheRead)
else if (tlink_tcon(cfile->tlink)->local_lease &&
!CIFS_I(inode)->clientCanCacheRead)
/* If the server claims to support oplock on this
file, then we still need to check oplock even
if the local_lease mount option is set, but there
......@@ -895,8 +937,8 @@ init_cifs(void)
GlobalTotalActiveXid = 0;
GlobalMaxActiveXid = 0;
memset(Local_System_Name, 0, 15);
rwlock_init(&GlobalSMBSeslock);
rwlock_init(&cifs_tcp_ses_lock);
spin_lock_init(&cifs_tcp_ses_lock);
spin_lock_init(&cifs_file_list_lock);
spin_lock_init(&GlobalMid_Lock);
if (cifs_max_pending < 2) {
......@@ -909,11 +951,11 @@ init_cifs(void)
rc = cifs_fscache_register();
if (rc)
goto out;
goto out_clean_proc;
rc = cifs_init_inodecache();
if (rc)
goto out_clean_proc;
goto out_unreg_fscache;
rc = cifs_init_mids();
if (rc)
......@@ -935,19 +977,19 @@ init_cifs(void)
return 0;
#ifdef CONFIG_CIFS_UPCALL
out_unregister_filesystem:
out_unregister_filesystem:
unregister_filesystem(&cifs_fs_type);
#endif
out_destroy_request_bufs:
out_destroy_request_bufs:
cifs_destroy_request_bufs();
out_destroy_mids:
out_destroy_mids:
cifs_destroy_mids();
out_destroy_inodecache:
out_destroy_inodecache:
cifs_destroy_inodecache();
out_clean_proc:
cifs_proc_clean();
out_unreg_fscache:
cifs_fscache_unregister();
out:
out_clean_proc:
cifs_proc_clean();
return rc;
}
......
......@@ -42,10 +42,8 @@ extern const struct address_space_operations cifs_addr_ops;
extern const struct address_space_operations cifs_addr_ops_smallbuf;
/* Functions related to super block operations */
/* extern const struct super_operations cifs_super_ops;*/
extern void cifs_read_inode(struct inode *);
/*extern void cifs_delete_inode(struct inode *);*/ /* BB not needed yet */
/* extern void cifs_write_inode(struct inode *); */ /* BB not needed yet */
extern void cifs_sb_active(struct super_block *sb);
extern void cifs_sb_deactive(struct super_block *sb);
/* Functions related to inodes */
extern const struct inode_operations cifs_dir_inode_ops;
......@@ -104,7 +102,7 @@ extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
const char *symname);
extern int cifs_removexattr(struct dentry *, const char *);
extern int cifs_setxattr(struct dentry *, const char *, const void *,
extern int cifs_setxattr(struct dentry *, const char *, const void *,
size_t, int);
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
......@@ -114,5 +112,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */
#define CIFS_VERSION "1.65"
#define CIFS_VERSION "1.67"
#endif /* _CIFSFS_H */
......@@ -97,7 +97,7 @@ enum protocolEnum {
/* Netbios frames protocol not supported at this time */
};
struct mac_key {
struct session_key {
unsigned int len;
union {
char ntlm[CIFS_SESS_KEY_SIZE + 16];
......@@ -139,6 +139,7 @@ struct TCP_Server_Info {
struct sockaddr_in sockAddr;
struct sockaddr_in6 sockAddr6;
} addr;
struct sockaddr_storage srcaddr; /* locally bind to this IP */
wait_queue_head_t response_q;
wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
struct list_head pending_mid_q;
......@@ -178,12 +179,10 @@ struct TCP_Server_Info {
int capabilities; /* allow selective disabling of caps by smb sess */
int timeAdj; /* Adjust for difference in server time zone in sec */
__u16 CurrentMid; /* multiplex id - rotating counter */
char cryptKey[CIFS_CRYPTO_KEY_SIZE];
/* 16th byte of RFC1001 workstation name is always null */
char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
__u32 sequence_number; /* needed for CIFS PDU signature */
struct mac_key mac_signing_key;
char ntlmv2_hash[16];
struct session_key session_key;
unsigned long lstrp; /* when we got last response from this server */
u16 dialect; /* dialect index that server chose */
/* extended security flavors that server supports */
......@@ -191,6 +190,7 @@ struct TCP_Server_Info {
bool sec_mskerberos; /* supports legacy MS Kerberos */
bool sec_kerberosu2u; /* supports U2U Kerberos */
bool sec_ntlmssp; /* supports NTLMSSP */
bool session_estab; /* mark when very first sess is established */
#ifdef CONFIG_CIFS_FSCACHE
struct fscache_cookie *fscache; /* client index cache cookie */
#endif
......@@ -222,6 +222,11 @@ struct cifsSesInfo {
char userName[MAX_USERNAME_SIZE + 1];
char *domainName;
char *password;
char cryptKey[CIFS_CRYPTO_KEY_SIZE];
struct session_key auth_key;
char ntlmv2_hash[16];
unsigned int tilen; /* length of the target info blob */
unsigned char *tiblob; /* target info blob in challenge response */
bool need_reconnect:1; /* connection reset, uid now invalid */
};
/* no more than one of the following three session flags may be set */
......@@ -307,6 +312,44 @@ struct cifsTconInfo {
/* BB add field for back pointer to sb struct(s)? */
};
/*
* This is a refcounted and timestamped container for a tcon pointer. The
* container holds a tcon reference. It is considered safe to free one of
* these when the tl_count goes to 0. The tl_time is the time of the last
* "get" on the container.
*/
struct tcon_link {
unsigned long tl_index;
unsigned long tl_flags;
#define TCON_LINK_MASTER 0
#define TCON_LINK_PENDING 1
#define TCON_LINK_IN_TREE 2
unsigned long tl_time;
atomic_t tl_count;
struct cifsTconInfo *tl_tcon;
};
extern struct tcon_link *cifs_sb_tlink(struct cifs_sb_info *cifs_sb);
static inline struct cifsTconInfo *
tlink_tcon(struct tcon_link *tlink)
{
return tlink->tl_tcon;
}
extern void cifs_put_tlink(struct tcon_link *tlink);
static inline struct tcon_link *
cifs_get_tlink(struct tcon_link *tlink)
{
if (tlink && !IS_ERR(tlink))
atomic_inc(&tlink->tl_count);
return tlink;
}
/* This function is always expected to succeed */
extern struct cifsTconInfo *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb);
/*
* This info hangs off the cifsFileInfo structure, pointed to by llist.
* This is used to track byte stream locks on the file
......@@ -345,12 +388,11 @@ struct cifsFileInfo {
__u16 netfid; /* file id from remote */
/* BB add lock scope info here if needed */ ;
/* lock scope id (0 if none) */
struct file *pfile; /* needed for writepage */
struct inode *pInode; /* needed for oplock break */
struct vfsmount *mnt;
struct dentry *dentry;
unsigned int f_flags;
struct tcon_link *tlink;
struct mutex lock_mutex;
struct list_head llist; /* list of byte range locks we have. */
bool closePend:1; /* file is marked to close */
bool invalidHandle:1; /* file closed via session abend */
bool oplock_break_cancelled:1;
atomic_t count; /* reference count */
......@@ -365,14 +407,7 @@ static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file)
atomic_inc(&cifs_file->count);
}
/* Release a reference on the file private data */
static inline void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
{
if (atomic_dec_and_test(&cifs_file->count)) {
iput(cifs_file->pInode);
kfree(cifs_file);
}
}
void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
/*
* One of these for each file inode
......@@ -474,16 +509,16 @@ struct oplock_q_entry {
/* for pending dnotify requests */
struct dir_notify_req {
struct list_head lhead;
__le16 Pid;
__le16 PidHigh;
__u16 Mid;
__u16 Tid;
__u16 Uid;
__u16 netfid;
__u32 filter; /* CompletionFilter (for multishot) */
int multishot;
struct file *pfile;
struct list_head lhead;
__le16 Pid;
__le16 PidHigh;
__u16 Mid;
__u16 Tid;
__u16 Uid;
__u16 netfid;
__u32 filter; /* CompletionFilter (for multishot) */
int multishot;
struct file *pfile;
};
struct dfs_info3_param {
......@@ -667,7 +702,7 @@ GLOBAL_EXTERN struct list_head cifs_tcp_ses_list;
* the reference counters for the server, smb session, and tcon. Finally,
* changes to the tcon->tidStatus should be done while holding this lock.
*/
GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock;
GLOBAL_EXTERN spinlock_t cifs_tcp_ses_lock;
/*
* This lock protects the cifs_file->llist and cifs_file->flist
......@@ -676,7 +711,7 @@ GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock;
* If cifs_tcp_ses_lock and the lock below are both needed to be held, then
* the cifs_tcp_ses_lock must be grabbed first and released last.
*/
GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;
GLOBAL_EXTERN spinlock_t cifs_file_list_lock;
/* Outstanding dir notify requests */
GLOBAL_EXTERN struct list_head GlobalDnotifyReqList;
......
......@@ -663,7 +663,6 @@ struct ntlmv2_resp {
__le64 time;
__u64 client_chal; /* random */
__u32 reserved2;
struct ntlmssp2_name names[2];
/* array of name entries could follow ending in minimum 4 byte struct */
} __attribute__((packed));
......
......@@ -78,9 +78,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
extern bool is_valid_oplock_break(struct smb_hdr *smb,
struct TCP_Server_Info *);
extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
#ifdef CONFIG_CIFS_EXPERIMENTAL
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *);
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
#endif
extern unsigned int smbCalcSize(struct smb_hdr *ptr);
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
......@@ -105,12 +105,12 @@ extern u64 cifs_UnixTimeToNT(struct timespec);
extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
int offset);
extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode,
__u16 fileHandle, struct file *file,
struct vfsmount *mnt, unsigned int oflags);
extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
struct file *file, struct tcon_link *tlink,
__u32 oplock);
extern int cifs_posix_open(char *full_path, struct inode **pinode,
struct super_block *sb,
int mode, int oflags,
int mode, unsigned int f_flags,
__u32 *poplock, __u16 *pnetfid, int xid);
void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr);
extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
......@@ -362,12 +362,12 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
__u32 *);
extern int cifs_verify_signature(struct smb_hdr *,
const struct mac_key *mac_key,
const struct session_key *session_key,
__u32 expected_sequence_number);
extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
extern int cifs_calculate_session_key(struct session_key *key, const char *rn,
const char *pass);
extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *);
extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
const struct nls_table *);
#ifdef CONFIG_CIFS_WEAK_PW_HASH
extern void calc_lanman_hash(const char *password, const char *cryptkey,
......@@ -408,4 +408,8 @@ extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr);
extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr,
const unsigned char *path,
struct cifs_sb_info *cifs_sb, int xid);
#endif /* _CIFSPROTO_H */
......@@ -91,13 +91,13 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
struct list_head *tmp1;
/* list all files open on tree connection and mark them invalid */
write_lock(&GlobalSMBSeslock);
spin_lock(&cifs_file_list_lock);
list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
open_file = list_entry(tmp, struct cifsFileInfo, tlist);
open_file->invalidHandle = true;
open_file->oplock_break_cancelled = true;
}
write_unlock(&GlobalSMBSeslock);
spin_unlock(&cifs_file_list_lock);
/* BB Add call to invalidate_inodes(sb) for all superblocks mounted
to this tcon */
}
......@@ -503,7 +503,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
if (rsp->EncryptionKeyLength ==
cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
memcpy(server->cryptKey, rsp->EncryptionKey,
memcpy(ses->cryptKey, rsp->EncryptionKey,
CIFS_CRYPTO_KEY_SIZE);
} else if (server->secMode & SECMODE_PW_ENCRYPT) {
rc = -EIO; /* need cryptkey unless plain text */
......@@ -574,7 +574,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
server->timeAdj *= 60;
if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
memcpy(ses->cryptKey, pSMBr->u.EncryptionKey,
CIFS_CRYPTO_KEY_SIZE);
} else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
&& (pSMBr->EncryptionKeyLength == 0)) {
......@@ -593,9 +593,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
rc = -EIO;
goto neg_err_exit;
}
read_lock(&cifs_tcp_ses_lock);
spin_lock(&cifs_tcp_ses_lock);
if (server->srv_count > 1) {
read_unlock(&cifs_tcp_ses_lock);
spin_unlock(&cifs_tcp_ses_lock);
if (memcmp(server->server_GUID,
pSMBr->u.extended_response.
GUID, 16) != 0) {
......@@ -605,7 +605,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
16);
}
} else {
read_unlock(&cifs_tcp_ses_lock);
spin_unlock(&cifs_tcp_ses_lock);
memcpy(server->server_GUID,
pSMBr->u.extended_response.GUID, 16);
}
......@@ -620,13 +620,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
rc = 0;
else
rc = -EINVAL;
if (server->sec_kerberos || server->sec_mskerberos)
server->secType = Kerberos;
else if (server->sec_ntlmssp)
server->secType = RawNTLMSSP;
else
rc = -EOPNOTSUPP;
if (server->secType == Kerberos) {
if (!server->sec_kerberos &&
!server->sec_mskerberos)
rc = -EOPNOTSUPP;
} else if (server->secType == RawNTLMSSP) {
if (!server->sec_ntlmssp)
rc = -EOPNOTSUPP;
} else
rc = -EOPNOTSUPP;
}
} else
server->capabilities &= ~CAP_EXTENDED_SECURITY;
......
/*
* fs/cifs/cn_cifs.h
*
* Copyright (c) International Business Machines Corp., 2002
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _CN_CIFS_H
#define _CN_CIFS_H
#ifdef CONFIG_CIFS_UPCALL
#include <linux/types.h>
#include <linux/connector.h>
struct cifs_upcall {
char signature[4]; /* CIFS */
enum command {
CIFS_GET_IP = 0x00000001, /* get ip address for hostname */
CIFS_GET_SECBLOB = 0x00000002, /* get SPNEGO wrapped blob */
} command;
/* union cifs upcall data follows */
};
#endif /* CIFS_UPCALL */
#endif /* _CN_CIFS_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -62,15 +62,15 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode)
{
struct cifsInodeInfo *cifsi = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
if (cifsi->fscache)
return;
cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache,
&cifs_fscache_inode_object_def,
cifsi);
cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)",
cifs_sb->tcon->fscache, cifsi->fscache);
cifsi->fscache = fscache_acquire_cookie(tcon->fscache,
&cifs_fscache_inode_object_def, cifsi);
cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache,
cifsi->fscache);
}
void cifs_fscache_release_inode_cookie(struct inode *inode)
......@@ -117,7 +117,8 @@ void cifs_fscache_reset_inode_cookie(struct inode *inode)
/* retire the current fscache cache and get a new one */
fscache_relinquish_cookie(cifsi->fscache, 1);
cifsi->fscache = fscache_acquire_cookie(cifs_sb->tcon->fscache,
cifsi->fscache = fscache_acquire_cookie(
cifs_sb_master_tcon(cifs_sb)->fscache,
&cifs_fscache_inode_object_def,
cifsi);
cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p",
......
This diff is collapsed.
......@@ -37,11 +37,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
int xid;
struct cifs_sb_info *cifs_sb;
#ifdef CONFIG_CIFS_POSIX
struct cifsFileInfo *pSMBFile = filep->private_data;
struct cifsTconInfo *tcon = tlink_tcon(pSMBFile->tlink);
__u64 ExtAttrBits = 0;
__u64 ExtAttrMask = 0;
__u64 caps;
struct cifsTconInfo *tcon;
struct cifsFileInfo *pSMBFile = filep->private_data;
__u64 caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
#endif /* CONFIG_CIFS_POSIX */
xid = GetXid();
......@@ -50,17 +50,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
cifs_sb = CIFS_SB(inode->i_sb);
#ifdef CONFIG_CIFS_POSIX
tcon = cifs_sb->tcon;
if (tcon)
caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
else {
rc = -EIO;
FreeXid(xid);
return -EIO;
}
#endif /* CONFIG_CIFS_POSIX */
switch (command) {
case CIFS_IOC_CHECKUMOUNT:
cFYI(1, "User unmount attempted");
......
This diff is collapsed.
......@@ -347,7 +347,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
if (current_fsuid() != treeCon->ses->linux_uid) {
cFYI(1, "Multiuser mode and UID "
"did not match tcon uid");
read_lock(&cifs_tcp_ses_lock);
spin_lock(&cifs_tcp_ses_lock);
list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) {
ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list);
if (ses->linux_uid == current_fsuid()) {
......@@ -361,7 +361,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
}
}
}
read_unlock(&cifs_tcp_ses_lock);
spin_unlock(&cifs_tcp_ses_lock);
}
}
}
......@@ -551,7 +551,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
return false;
/* look up tcon based on tid & uid */
read_lock(&cifs_tcp_ses_lock);
spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &srv->smb_ses_list) {
ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
list_for_each(tmp1, &ses->tcon_list) {
......@@ -560,25 +560,15 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
continue;
cifs_stats_inc(&tcon->num_oplock_brks);
read_lock(&GlobalSMBSeslock);
spin_lock(&cifs_file_list_lock);
list_for_each(tmp2, &tcon->openFileList) {
netfile = list_entry(tmp2, struct cifsFileInfo,
tlist);
if (pSMB->Fid != netfile->netfid)
continue;
/*
* don't do anything if file is about to be
* closed anyway.
*/
if (netfile->closePend) {
read_unlock(&GlobalSMBSeslock);
read_unlock(&cifs_tcp_ses_lock);
return true;
}
cFYI(1, "file id match, oplock break");
pCifsInode = CIFS_I(netfile->pInode);
pCifsInode = CIFS_I(netfile->dentry->d_inode);
pCifsInode->clientCanCacheAll = false;
if (pSMB->OplockLevel == 0)
pCifsInode->clientCanCacheRead = false;
......@@ -594,17 +584,17 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
cifs_oplock_break_get(netfile);
netfile->oplock_break_cancelled = false;
read_unlock(&GlobalSMBSeslock);
read_unlock(&cifs_tcp_ses_lock);
spin_unlock(&cifs_file_list_lock);
spin_unlock(&cifs_tcp_ses_lock);
return true;
}
read_unlock(&GlobalSMBSeslock);
read_unlock(&cifs_tcp_ses_lock);
spin_unlock(&cifs_file_list_lock);
spin_unlock(&cifs_tcp_ses_lock);
cFYI(1, "No matching file for oplock break");
return true;
}
}
read_unlock(&cifs_tcp_ses_lock);
spin_unlock(&cifs_tcp_ses_lock);
cFYI(1, "Can not process oplock break for non-existent connection");
return true;
}
......@@ -729,6 +719,6 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
"properly. Hardlinks will not be recognized on this "
"mount. Consider mounting with the \"noserverino\" "
"option to silence this message.",
cifs_sb->tcon->treeName);
cifs_sb_master_tcon(cifs_sb)->treeName);
}
}
......@@ -61,6 +61,21 @@
#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
#define NTLMSSP_NEGOTIATE_56 0x80000000
/* Define AV Pair Field IDs */
enum av_field_type {
NTLMSSP_AV_EOL = 0,
NTLMSSP_AV_NB_COMPUTER_NAME,
NTLMSSP_AV_NB_DOMAIN_NAME,
NTLMSSP_AV_DNS_COMPUTER_NAME,
NTLMSSP_AV_DNS_DOMAIN_NAME,
NTLMSSP_AV_DNS_TREE_NAME,
NTLMSSP_AV_FLAGS,
NTLMSSP_AV_TIMESTAMP,
NTLMSSP_AV_RESTRICTION,
NTLMSSP_AV_TARGET_NAME,
NTLMSSP_AV_CHANNEL_BINDINGS
};
/* Although typedefs are not commonly used for structure definitions */
/* in the Linux kernel, in this particular case they are useful */
/* to more closely match the standards document for NTLMSSP from */
......
......@@ -102,7 +102,7 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
return NULL;
}
if (CIFS_SB(sb)->tcon->nocase)
if (cifs_sb_master_tcon(CIFS_SB(sb))->nocase)
dentry->d_op = &cifs_ci_dentry_ops;
else
dentry->d_op = &cifs_dentry_ops;
......@@ -171,7 +171,7 @@ static void
cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
struct cifs_sb_info *cifs_sb)
{
int offset = cifs_sb->tcon->ses->server->timeAdj;
int offset = cifs_sb_master_tcon(cifs_sb)->ses->server->timeAdj;
memset(fattr, 0, sizeof(*fattr));
fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate,
......@@ -199,7 +199,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
int len;
int oplock = 0;
int rc;
struct cifsTconInfo *ptcon = cifs_sb->tcon;
struct cifsTconInfo *ptcon = cifs_sb_tcon(cifs_sb);
char *tmpbuffer;
rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
......@@ -223,34 +223,35 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
static int initiate_cifs_search(const int xid, struct file *file)
{
int rc = 0;
char *full_path;
char *full_path = NULL;
struct cifsFileInfo *cifsFile;
struct cifs_sb_info *cifs_sb;
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
struct tcon_link *tlink;
struct cifsTconInfo *pTcon;
if (file->private_data == NULL) {
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
pTcon = tlink_tcon(tlink);
if (file->private_data == NULL)
file->private_data =
kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
if (file->private_data == NULL) {
rc = -ENOMEM;
goto error_exit;
}
if (file->private_data == NULL)
return -ENOMEM;
cifsFile = file->private_data;
cifsFile->invalidHandle = true;
cifsFile->srch_inf.endOfSearch = false;
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
if (cifs_sb == NULL)
return -EINVAL;
pTcon = cifs_sb->tcon;
if (pTcon == NULL)
return -EINVAL;
cifsFile->tlink = cifs_get_tlink(tlink);
full_path = build_path_from_dentry(file->f_path.dentry);
if (full_path == NULL)
return -ENOMEM;
if (full_path == NULL) {
rc = -ENOMEM;
goto error_exit;
}
cFYI(1, "Full path: %s start at: %lld", full_path, file->f_pos);
......@@ -283,7 +284,9 @@ static int initiate_cifs_search(const int xid, struct file *file)
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
goto ffirst_retry;
}
error_exit:
kfree(full_path);
cifs_put_tlink(tlink);
return rc;
}
......@@ -525,14 +528,14 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
(index_to_find < first_entry_in_buffer)) {
/* close and restart search */
cFYI(1, "search backing up - close and restart search");
write_lock(&GlobalSMBSeslock);
spin_lock(&cifs_file_list_lock);
if (!cifsFile->srch_inf.endOfSearch &&
!cifsFile->invalidHandle) {
cifsFile->invalidHandle = true;
write_unlock(&GlobalSMBSeslock);
spin_unlock(&cifs_file_list_lock);
CIFSFindClose(xid, pTcon, cifsFile->netfid);
} else
write_unlock(&GlobalSMBSeslock);
spin_unlock(&cifs_file_list_lock);
if (cifsFile->srch_inf.ntwrk_buf_start) {
cFYI(1, "freeing SMB ff cache buf on search rewind");
if (cifsFile->srch_inf.smallBuf)
......@@ -738,6 +741,15 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
cifs_autodisable_serverino(cifs_sb);
}
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
CIFSCouldBeMFSymlink(&fattr))
/*
* trying to get the type and mode can be slow,
* so just call those regular files for now, and mark
* for reval
*/
fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr);
......@@ -777,9 +789,17 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
xid = GetXid();
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if (pTcon == NULL)
return -EINVAL;
/*
* Ensure FindFirst doesn't fail before doing filldir() for '.' and
* '..'. Otherwise we won't be able to notify VFS in case of failure.
*/
if (file->private_data == NULL) {
rc = initiate_cifs_search(xid, file);
cFYI(1, "initiate cifs search rc %d", rc);
if (rc)
goto rddir2_exit;
}
switch ((int) file->f_pos) {
case 0:
......@@ -804,14 +824,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
if it before then restart search
if after then keep searching till find it */
if (file->private_data == NULL) {
rc = initiate_cifs_search(xid, file);
cFYI(1, "initiate cifs search rc %d", rc);
if (rc) {
FreeXid(xid);
return rc;
}
}
if (file->private_data == NULL) {
rc = -EINVAL;
FreeXid(xid);
......@@ -829,6 +841,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
CIFSFindClose(xid, pTcon, cifsFile->netfid);
} */
pTcon = tlink_tcon(cifsFile->tlink);
rc = find_cifs_entry(xid, pTcon, file,
&current_entry, &num_to_fill);
if (rc) {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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