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 multiuser mounts so server does not invalidate earlier security contexts [CIFS] improve posix semantics of file create [CIFS] Fix oops in cifs_strfromUCS_le mounting to servers which do not specify their OS cifs: posix fill in inode needed by posix open cifs: properly handle case where CIFSGetSrvInodeNumber fails cifs: refactor new_inode() calls and inode initialization [CIFS] Prevent OOPs when mounting with remote prefixpath. [CIFS] ipv6_addr_equal for address comparison
This commit is contained in:
Коммит
710320d579
|
@ -1,3 +1,13 @@
|
|||
Version 1.57
|
||||
------------
|
||||
Improve support for multiple security contexts to the same server. We
|
||||
used to use the same "vcnumber" for all connections which could cause
|
||||
the server to treat subsequent connections, especially those that
|
||||
are authenticated as guest, as reconnections, invalidating the earlier
|
||||
user's smb session. This fix allows cifs to mount multiple times to the
|
||||
same server with different userids without risking invalidating earlier
|
||||
established security contexts.
|
||||
|
||||
Version 1.56
|
||||
------------
|
||||
Add "forcemandatorylock" mount option to allow user to use mandatory
|
||||
|
@ -7,7 +17,10 @@ specified and user does not have access to query information about the
|
|||
top of the share. Fix problem in 2.6.28 resolving DFS paths to
|
||||
Samba servers (worked to Windows). Fix rmdir so that pending search
|
||||
(readdir) requests do not get invalid results which include the now
|
||||
removed directory.
|
||||
removed directory. Fix oops in cifs_dfs_ref.c when prefixpath is not reachable
|
||||
when using DFS. Add better file create support to servers which support
|
||||
the CIFS POSIX protocol extensions (this adds support for new flags
|
||||
on create, and improves semantics for write of locked ranges).
|
||||
|
||||
Version 1.55
|
||||
------------
|
||||
|
|
|
@ -100,5 +100,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.56"
|
||||
#define CIFS_VERSION "1.57"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -164,9 +164,12 @@ struct TCP_Server_Info {
|
|||
/* multiplexed reads or writes */
|
||||
unsigned int maxBuf; /* maxBuf specifies the maximum */
|
||||
/* message size the server can send or receive for non-raw SMBs */
|
||||
unsigned int maxRw; /* maxRw specifies the maximum */
|
||||
unsigned int max_rw; /* maxRw specifies the maximum */
|
||||
/* message size the server can send or receive for */
|
||||
/* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
|
||||
unsigned int max_vcs; /* maximum number of smb sessions, at least
|
||||
those that can be specified uniquely with
|
||||
vcnumbers */
|
||||
char sessid[4]; /* unique token id for this session */
|
||||
/* (returned on Negotiate */
|
||||
int capabilities; /* allow selective disabling of caps by smb sess */
|
||||
|
@ -210,6 +213,7 @@ struct cifsSesInfo {
|
|||
unsigned overrideSecFlg; /* if non-zero override global sec flags */
|
||||
__u16 ipc_tid; /* special tid for connection to IPC share */
|
||||
__u16 flags;
|
||||
__u16 vcnum;
|
||||
char *serverOS; /* name of operating system underlying server */
|
||||
char *serverNOS; /* name of network operating system of server */
|
||||
char *serverDomain; /* security realm of server */
|
||||
|
|
|
@ -42,6 +42,7 @@ extern void _FreeXid(unsigned int);
|
|||
#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",__func__,curr_xid,(int)rc));}
|
||||
extern char *build_path_from_dentry(struct dentry *);
|
||||
extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb);
|
||||
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
|
||||
/* extern void renew_parental_timestamps(struct dentry *direntry);*/
|
||||
extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
|
||||
|
@ -91,6 +92,9 @@ extern u64 cifs_UnixTimeToNT(struct timespec);
|
|||
extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
|
||||
extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
|
||||
|
||||
extern void posix_fill_in_inode(struct inode *tmp_inode,
|
||||
FILE_UNIX_BASIC_INFO *pData, int isNewInode);
|
||||
extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum);
|
||||
extern int cifs_get_inode_info(struct inode **pinode,
|
||||
const unsigned char *search_path,
|
||||
FILE_ALL_INFO *pfile_info,
|
||||
|
|
|
@ -528,14 +528,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
|
||||
server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
|
||||
(__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
|
||||
server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
|
||||
GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
|
||||
/* even though we do not use raw we might as well set this
|
||||
accurately, in case we ever find a need for it */
|
||||
if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
|
||||
server->maxRw = 0xFF00;
|
||||
server->max_rw = 0xFF00;
|
||||
server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
|
||||
} else {
|
||||
server->maxRw = 0;/* we do not need to use raw anyway */
|
||||
server->max_rw = 0;/* do not need to use raw anyway */
|
||||
server->capabilities = CAP_MPX_MODE;
|
||||
}
|
||||
tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
|
||||
|
@ -638,7 +639,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
/* probably no need to store and check maxvcs */
|
||||
server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
|
||||
(__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
|
||||
server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
|
||||
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
|
||||
cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
|
||||
GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
|
||||
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/utsname.h>
|
||||
|
@ -35,6 +34,7 @@
|
|||
#include <linux/freezer.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/processor.h>
|
||||
#include <net/ipv6.h>
|
||||
#include "cifspdu.h"
|
||||
#include "cifsglob.h"
|
||||
#include "cifsproto.h"
|
||||
|
@ -1379,8 +1379,8 @@ cifs_find_tcp_session(struct sockaddr_storage *addr)
|
|||
server->addr.sockAddr.sin_addr.s_addr))
|
||||
continue;
|
||||
else if (addr->ss_family == AF_INET6 &&
|
||||
memcmp(&server->addr.sockAddr6.sin6_addr,
|
||||
&addr6->sin6_addr, sizeof(addr6->sin6_addr)))
|
||||
!ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
|
||||
&addr6->sin6_addr))
|
||||
continue;
|
||||
|
||||
++server->srv_count;
|
||||
|
@ -2180,6 +2180,33 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
|
|||
"mount option supported"));
|
||||
}
|
||||
|
||||
static int
|
||||
is_path_accessible(int xid, struct cifsTconInfo *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path)
|
||||
{
|
||||
int rc;
|
||||
__u64 inode_num;
|
||||
FILE_ALL_INFO *pfile_info;
|
||||
|
||||
rc = CIFSGetSrvInodeNumber(xid, tcon, full_path, &inode_num,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc != -EOPNOTSUPP)
|
||||
return rc;
|
||||
|
||||
pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
|
||||
if (pfile_info == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
|
||||
0 /* not legacy */, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
kfree(pfile_info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
char *mount_data, const char *devname)
|
||||
|
@ -2190,6 +2217,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
struct cifsSesInfo *pSesInfo = NULL;
|
||||
struct cifsTconInfo *tcon = NULL;
|
||||
struct TCP_Server_Info *srvTcp = NULL;
|
||||
char *full_path;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
|
@ -2426,6 +2454,23 @@ mount_fail_check:
|
|||
cifs_sb->rsize = min(cifs_sb->rsize,
|
||||
(tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
|
||||
|
||||
if (!rc && cifs_sb->prepathlen) {
|
||||
/* build_path_to_root works only when we have a valid tcon */
|
||||
full_path = cifs_build_path_to_root(cifs_sb);
|
||||
if (full_path == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto mount_fail_check;
|
||||
}
|
||||
rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
|
||||
if (rc) {
|
||||
cERROR(1, ("Path %s in not accessible: %d",
|
||||
full_path, rc));
|
||||
kfree(full_path);
|
||||
goto mount_fail_check;
|
||||
}
|
||||
kfree(full_path);
|
||||
}
|
||||
|
||||
/* volume_info->password is freed above when existing session found
|
||||
(in which case it is not needed anymore) but when new sesion is created
|
||||
the password ptr is put in the new session structure (in which case the
|
||||
|
|
301
fs/cifs/dir.c
301
fs/cifs/dir.c
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* vfs operations that deal with dentries
|
||||
*
|
||||
* Copyright (C) International Business Machines Corp., 2002,2008
|
||||
* Copyright (C) International Business Machines Corp., 2002,2009
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
|
@ -129,6 +129,78 @@ cifs_bp_rename_retry:
|
|||
return full_path;
|
||||
}
|
||||
|
||||
static int cifs_posix_open(char *full_path, struct inode **pinode,
|
||||
struct super_block *sb, int mode, int oflags,
|
||||
int *poplock, __u16 *pnetfid, int xid)
|
||||
{
|
||||
int rc;
|
||||
__u32 oplock;
|
||||
FILE_UNIX_BASIC_INFO *presp_data;
|
||||
__u32 posix_flags = 0;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
|
||||
cFYI(1, ("posix open %s", full_path));
|
||||
|
||||
presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
|
||||
if (presp_data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* So far cifs posix extensions can only map the following flags.
|
||||
There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but
|
||||
so far we do not seem to need them, and we can treat them as local only */
|
||||
if ((oflags & (FMODE_READ | FMODE_WRITE)) ==
|
||||
(FMODE_READ | FMODE_WRITE))
|
||||
posix_flags = SMB_O_RDWR;
|
||||
else if (oflags & FMODE_READ)
|
||||
posix_flags = SMB_O_RDONLY;
|
||||
else if (oflags & FMODE_WRITE)
|
||||
posix_flags = SMB_O_WRONLY;
|
||||
if (oflags & O_CREAT)
|
||||
posix_flags |= SMB_O_CREAT;
|
||||
if (oflags & O_EXCL)
|
||||
posix_flags |= SMB_O_EXCL;
|
||||
if (oflags & O_TRUNC)
|
||||
posix_flags |= SMB_O_TRUNC;
|
||||
if (oflags & O_APPEND)
|
||||
posix_flags |= SMB_O_APPEND;
|
||||
if (oflags & O_SYNC)
|
||||
posix_flags |= SMB_O_SYNC;
|
||||
if (oflags & O_DIRECTORY)
|
||||
posix_flags |= SMB_O_DIRECTORY;
|
||||
if (oflags & O_NOFOLLOW)
|
||||
posix_flags |= SMB_O_NOFOLLOW;
|
||||
if (oflags & O_DIRECT)
|
||||
posix_flags |= SMB_O_DIRECT;
|
||||
|
||||
|
||||
rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
|
||||
pnetfid, presp_data, &oplock, full_path,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc)
|
||||
goto posix_open_ret;
|
||||
|
||||
if (presp_data->Type == cpu_to_le32(-1))
|
||||
goto posix_open_ret; /* open ok, caller does qpathinfo */
|
||||
|
||||
/* get new inode and set it up */
|
||||
if (!pinode)
|
||||
goto posix_open_ret; /* caller does not need info */
|
||||
|
||||
*pinode = cifs_new_inode(sb, &presp_data->UniqueId);
|
||||
|
||||
/* We do not need to close the file if new_inode fails since
|
||||
the caller will retry qpathinfo as long as inode is null */
|
||||
if (*pinode == NULL)
|
||||
goto posix_open_ret;
|
||||
|
||||
posix_fill_in_inode(*pinode, presp_data, 1);
|
||||
|
||||
posix_open_ret:
|
||||
kfree(presp_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void setup_cifs_dentry(struct cifsTconInfo *tcon,
|
||||
struct dentry *direntry,
|
||||
struct inode *newinode)
|
||||
|
@ -150,7 +222,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
int xid;
|
||||
int create_options = CREATE_NOT_DIR;
|
||||
int oplock = 0;
|
||||
/* BB below access is too much for the mknod to request */
|
||||
int oflags;
|
||||
/*
|
||||
* BB below access is probably too much for mknod to request
|
||||
* but we have to do query and setpathinfo so requesting
|
||||
* less could fail (unless we want to request getatr and setatr
|
||||
* permissions (only). At least for POSIX we do not have to
|
||||
* request so much.
|
||||
*/
|
||||
int desiredAccess = GENERIC_READ | GENERIC_WRITE;
|
||||
__u16 fileHandle;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
|
@ -174,13 +253,43 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
}
|
||||
|
||||
mode &= ~current->fs->umask;
|
||||
if (oplockEnabled)
|
||||
oplock = REQ_OPLOCK;
|
||||
|
||||
if (nd && (nd->flags & LOOKUP_OPEN))
|
||||
oflags = nd->intent.open.flags;
|
||||
else
|
||||
oflags = FMODE_READ;
|
||||
|
||||
if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
|
||||
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
||||
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
||||
rc = cifs_posix_open(full_path, &newinode, inode->i_sb,
|
||||
mode, oflags, &oplock, &fileHandle, xid);
|
||||
/* EIO could indicate that (posix open) operation is not
|
||||
supported, despite what server claimed in capability
|
||||
negotation. EREMOTE indicates DFS junction, which is not
|
||||
handled in posix open */
|
||||
|
||||
if ((rc == 0) && (newinode == NULL))
|
||||
goto cifs_create_get_file_info; /* query inode info */
|
||||
else if (rc == 0) /* success, no need to query */
|
||||
goto cifs_create_set_dentry;
|
||||
else if ((rc != -EIO) && (rc != -EREMOTE) &&
|
||||
(rc != -EOPNOTSUPP)) /* path not found or net err */
|
||||
goto cifs_create_out;
|
||||
/* else fallthrough to retry, using older open call, this is
|
||||
case where server does not support this SMB level, and
|
||||
falsely claims capability (also get here for DFS case
|
||||
which should be rare for path not covered on files) */
|
||||
}
|
||||
|
||||
if (nd && (nd->flags & LOOKUP_OPEN)) {
|
||||
int oflags = nd->intent.open.flags;
|
||||
|
||||
/* if the file is going to stay open, then we
|
||||
need to set the desired access properly */
|
||||
desiredAccess = 0;
|
||||
if (oflags & FMODE_READ)
|
||||
desiredAccess |= GENERIC_READ;
|
||||
desiredAccess |= GENERIC_READ; /* is this too little? */
|
||||
if (oflags & FMODE_WRITE) {
|
||||
desiredAccess |= GENERIC_WRITE;
|
||||
if (!(oflags & FMODE_READ))
|
||||
|
@ -199,8 +308,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
|
||||
/* BB add processing to set equivalent of mode - e.g. via CreateX with
|
||||
ACLs */
|
||||
if (oplockEnabled)
|
||||
oplock = REQ_OPLOCK;
|
||||
|
||||
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
|
||||
if (buf == NULL) {
|
||||
|
@ -233,116 +340,112 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
}
|
||||
if (rc) {
|
||||
cFYI(1, ("cifs_create returned 0x%x", rc));
|
||||
} else {
|
||||
/* If Open reported that we actually created a file
|
||||
then we now have to set the mode if possible */
|
||||
if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
|
||||
struct cifs_unix_set_info_args args = {
|
||||
goto cifs_create_out;
|
||||
}
|
||||
|
||||
/* If Open reported that we actually created a file
|
||||
then we now have to set the mode if possible */
|
||||
if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
|
||||
struct cifs_unix_set_info_args args = {
|
||||
.mode = mode,
|
||||
.ctime = NO_CHANGE_64,
|
||||
.atime = NO_CHANGE_64,
|
||||
.mtime = NO_CHANGE_64,
|
||||
.device = 0,
|
||||
};
|
||||
};
|
||||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
|
||||
args.uid = (__u64) current_fsuid();
|
||||
if (inode->i_mode & S_ISGID)
|
||||
args.gid = (__u64) inode->i_gid;
|
||||
else
|
||||
args.gid = (__u64) current_fsgid();
|
||||
} else {
|
||||
args.uid = NO_CHANGE_64;
|
||||
args.gid = NO_CHANGE_64;
|
||||
}
|
||||
CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
|
||||
args.uid = (__u64) current_fsuid();
|
||||
if (inode->i_mode & S_ISGID)
|
||||
args.gid = (__u64) inode->i_gid;
|
||||
else
|
||||
args.gid = (__u64) current_fsgid();
|
||||
} else {
|
||||
/* BB implement mode setting via Windows security
|
||||
descriptors e.g. */
|
||||
/* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
|
||||
|
||||
/* Could set r/o dos attribute if mode & 0222 == 0 */
|
||||
args.uid = NO_CHANGE_64;
|
||||
args.gid = NO_CHANGE_64;
|
||||
}
|
||||
CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
} else {
|
||||
/* BB implement mode setting via Windows security
|
||||
descriptors e.g. */
|
||||
/* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
|
||||
|
||||
/* server might mask mode so we have to query for it */
|
||||
if (tcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&newinode, full_path,
|
||||
inode->i_sb, xid);
|
||||
else {
|
||||
rc = cifs_get_inode_info(&newinode, full_path,
|
||||
buf, inode->i_sb, xid,
|
||||
&fileHandle);
|
||||
if (newinode) {
|
||||
if (cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_DYNPERM)
|
||||
newinode->i_mode = mode;
|
||||
if ((oplock & CIFS_CREATE_ACTION) &&
|
||||
(cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_SET_UID)) {
|
||||
newinode->i_uid = current_fsuid();
|
||||
if (inode->i_mode & S_ISGID)
|
||||
newinode->i_gid =
|
||||
inode->i_gid;
|
||||
else
|
||||
newinode->i_gid =
|
||||
current_fsgid();
|
||||
}
|
||||
/* Could set r/o dos attribute if mode & 0222 == 0 */
|
||||
}
|
||||
|
||||
cifs_create_get_file_info:
|
||||
/* server might mask mode so we have to query for it */
|
||||
if (tcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&newinode, full_path,
|
||||
inode->i_sb, xid);
|
||||
else {
|
||||
rc = cifs_get_inode_info(&newinode, full_path, buf,
|
||||
inode->i_sb, xid, &fileHandle);
|
||||
if (newinode) {
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
|
||||
newinode->i_mode = mode;
|
||||
if ((oplock & CIFS_CREATE_ACTION) &&
|
||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
|
||||
newinode->i_uid = current_fsuid();
|
||||
if (inode->i_mode & S_ISGID)
|
||||
newinode->i_gid = inode->i_gid;
|
||||
else
|
||||
newinode->i_gid = current_fsgid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
cFYI(1, ("Create worked, get_inode_info failed rc = %d",
|
||||
rc));
|
||||
} else
|
||||
setup_cifs_dentry(tcon, direntry, newinode);
|
||||
cifs_create_set_dentry:
|
||||
if (rc == 0)
|
||||
setup_cifs_dentry(tcon, direntry, newinode);
|
||||
else
|
||||
cFYI(1, ("Create worked, get_inode_info failed rc = %d", rc));
|
||||
|
||||
if ((nd == NULL /* nfsd case - nfs srv does not set nd */) ||
|
||||
(!(nd->flags & LOOKUP_OPEN))) {
|
||||
/* mknod case - do not leave file open */
|
||||
CIFSSMBClose(xid, tcon, fileHandle);
|
||||
} else if (newinode) {
|
||||
struct cifsFileInfo *pCifsFile =
|
||||
kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
||||
/* nfsd case - nfs srv does not set nd */
|
||||
if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) {
|
||||
/* mknod case - do not leave file open */
|
||||
CIFSSMBClose(xid, tcon, fileHandle);
|
||||
} else if (newinode) {
|
||||
struct cifsFileInfo *pCifsFile =
|
||||
kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
||||
|
||||
if (pCifsFile == NULL)
|
||||
goto cifs_create_out;
|
||||
pCifsFile->netfid = fileHandle;
|
||||
pCifsFile->pid = current->tgid;
|
||||
pCifsFile->pInode = newinode;
|
||||
pCifsFile->invalidHandle = false;
|
||||
pCifsFile->closePend = false;
|
||||
init_MUTEX(&pCifsFile->fh_sem);
|
||||
mutex_init(&pCifsFile->lock_mutex);
|
||||
INIT_LIST_HEAD(&pCifsFile->llist);
|
||||
atomic_set(&pCifsFile->wrtPending, 0);
|
||||
if (pCifsFile == NULL)
|
||||
goto cifs_create_out;
|
||||
pCifsFile->netfid = fileHandle;
|
||||
pCifsFile->pid = current->tgid;
|
||||
pCifsFile->pInode = newinode;
|
||||
pCifsFile->invalidHandle = false;
|
||||
pCifsFile->closePend = false;
|
||||
init_MUTEX(&pCifsFile->fh_sem);
|
||||
mutex_init(&pCifsFile->lock_mutex);
|
||||
INIT_LIST_HEAD(&pCifsFile->llist);
|
||||
atomic_set(&pCifsFile->wrtPending, 0);
|
||||
|
||||
/* set the following in open now
|
||||
/* set the following in open now
|
||||
pCifsFile->pfile = file; */
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_add(&pCifsFile->tlist, &tcon->openFileList);
|
||||
pCifsInode = CIFS_I(newinode);
|
||||
if (pCifsInode) {
|
||||
/* if readable file instance put first in list*/
|
||||
if (write_only) {
|
||||
list_add_tail(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
} else {
|
||||
list_add(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
}
|
||||
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
|
||||
pCifsInode->clientCanCacheAll = true;
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
cFYI(1, ("Exclusive Oplock inode %p",
|
||||
newinode));
|
||||
} else if ((oplock & 0xF) == OPLOCK_READ)
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_add(&pCifsFile->tlist, &tcon->openFileList);
|
||||
pCifsInode = CIFS_I(newinode);
|
||||
if (pCifsInode) {
|
||||
/* if readable file instance put first in list*/
|
||||
if (write_only) {
|
||||
list_add_tail(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
} else {
|
||||
list_add(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
}
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
|
||||
pCifsInode->clientCanCacheAll = true;
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
cFYI(1, ("Exclusive Oplock inode %p",
|
||||
newinode));
|
||||
} else if ((oplock & 0xF) == OPLOCK_READ)
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
}
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
}
|
||||
cifs_create_out:
|
||||
kfree(buf);
|
||||
|
|
104
fs/cifs/inode.c
104
fs/cifs/inode.c
|
@ -199,6 +199,49 @@ static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
|
|||
pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
|
||||
}
|
||||
|
||||
/**
|
||||
* cifs_new inode - create new inode, initialize, and hash it
|
||||
* @sb - pointer to superblock
|
||||
* @inum - if valid pointer and serverino is enabled, replace i_ino with val
|
||||
*
|
||||
* Create a new inode, initialize it for CIFS and hash it. Returns the new
|
||||
* inode or NULL if one couldn't be allocated.
|
||||
*
|
||||
* If the share isn't mounted with "serverino" or inum is a NULL pointer then
|
||||
* we'll just use the inode number assigned by new_inode(). Note that this can
|
||||
* mean i_ino collisions since the i_ino assigned by new_inode is not
|
||||
* guaranteed to be unique.
|
||||
*/
|
||||
struct inode *
|
||||
cifs_new_inode(struct super_block *sb, __u64 *inum)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
inode = new_inode(sb);
|
||||
if (inode == NULL)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we
|
||||
* stop passing inum as ptr. Are there sanity checks we can use to
|
||||
* ensure that the server is really filling in that field? Also,
|
||||
* if serverino is disabled, perhaps we should be using iunique()?
|
||||
*/
|
||||
if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
|
||||
inode->i_ino = (unsigned long) *inum;
|
||||
|
||||
/*
|
||||
* must set this here instead of cifs_alloc_inode since VFS will
|
||||
* clobber i_flags
|
||||
*/
|
||||
if (sb->s_flags & MS_NOATIME)
|
||||
inode->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
|
||||
insert_inode_hash(inode);
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
const unsigned char *full_path, struct super_block *sb, int xid)
|
||||
{
|
||||
|
@ -233,22 +276,11 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|||
|
||||
/* get new inode */
|
||||
if (*pinode == NULL) {
|
||||
*pinode = new_inode(sb);
|
||||
*pinode = cifs_new_inode(sb, &find_data.UniqueId);
|
||||
if (*pinode == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cgiiu_exit;
|
||||
}
|
||||
/* Is an i_ino of zero legal? */
|
||||
/* note ino incremented to unique num in new_inode */
|
||||
/* Are there sanity checks we can use to ensure that
|
||||
the server is really filling in that field? */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
|
||||
(*pinode)->i_ino = (unsigned long)find_data.UniqueId;
|
||||
|
||||
if (sb->s_flags & MS_NOATIME)
|
||||
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
|
||||
insert_inode_hash(*pinode);
|
||||
}
|
||||
|
||||
inode = *pinode;
|
||||
|
@ -465,11 +497,9 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
|
||||
/* get new inode */
|
||||
if (*pinode == NULL) {
|
||||
*pinode = new_inode(sb);
|
||||
if (*pinode == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cgii_exit;
|
||||
}
|
||||
__u64 inode_num;
|
||||
__u64 *pinum = &inode_num;
|
||||
|
||||
/* Is an i_ino of zero legal? Can we use that to check
|
||||
if the server supports returning inode numbers? Are
|
||||
there other sanity checks we can use to ensure that
|
||||
|
@ -486,22 +516,26 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
||||
int rc1 = 0;
|
||||
__u64 inode_num;
|
||||
|
||||
rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
|
||||
full_path, &inode_num,
|
||||
full_path, pinum,
|
||||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc1) {
|
||||
cFYI(1, ("GetSrvInodeNum rc %d", rc1));
|
||||
pinum = NULL;
|
||||
/* BB EOPNOSUPP disable SERVER_INUM? */
|
||||
} else /* do we need cast or hash to ino? */
|
||||
(*pinode)->i_ino = inode_num;
|
||||
} /* else ino incremented to unique num in new_inode*/
|
||||
if (sb->s_flags & MS_NOATIME)
|
||||
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
insert_inode_hash(*pinode);
|
||||
}
|
||||
} else {
|
||||
pinum = NULL;
|
||||
}
|
||||
|
||||
*pinode = cifs_new_inode(sb, pinum);
|
||||
if (*pinode == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cgii_exit;
|
||||
}
|
||||
}
|
||||
inode = *pinode;
|
||||
cifsInfo = CIFS_I(inode);
|
||||
|
@ -621,7 +655,7 @@ static const struct inode_operations cifs_ipc_inode_ops = {
|
|||
.lookup = cifs_lookup,
|
||||
};
|
||||
|
||||
static char *build_path_to_root(struct cifs_sb_info *cifs_sb)
|
||||
char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
int pplen = cifs_sb->prepathlen;
|
||||
int dfsplen;
|
||||
|
@ -678,7 +712,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
|||
return inode;
|
||||
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
full_path = build_path_to_root(cifs_sb);
|
||||
full_path = cifs_build_path_to_root(cifs_sb);
|
||||
if (full_path == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
|
@ -1017,7 +1051,7 @@ out_reval:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void posix_fill_in_inode(struct inode *tmp_inode,
|
||||
void posix_fill_in_inode(struct inode *tmp_inode,
|
||||
FILE_UNIX_BASIC_INFO *pData, int isNewInode)
|
||||
{
|
||||
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
|
||||
|
@ -1114,24 +1148,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|||
else
|
||||
direntry->d_op = &cifs_dentry_ops;
|
||||
|
||||
newinode = new_inode(inode->i_sb);
|
||||
newinode = cifs_new_inode(inode->i_sb,
|
||||
&pInfo->UniqueId);
|
||||
if (newinode == NULL) {
|
||||
kfree(pInfo);
|
||||
goto mkdir_get_info;
|
||||
}
|
||||
|
||||
/* Is an i_ino of zero legal? */
|
||||
/* Are there sanity checks we can use to ensure that
|
||||
the server is really filling in that field? */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
||||
newinode->i_ino =
|
||||
(unsigned long)pInfo->UniqueId;
|
||||
} /* note ino incremented to unique num in new_inode */
|
||||
if (inode->i_sb->s_flags & MS_NOATIME)
|
||||
newinode->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
newinode->i_nlink = 2;
|
||||
|
||||
insert_inode_hash(newinode);
|
||||
d_instantiate(direntry, newinode);
|
||||
|
||||
/* we already checked in POSIXCreate whether
|
||||
|
|
|
@ -56,35 +56,34 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
|
|||
}
|
||||
#endif /* DEBUG2 */
|
||||
|
||||
/* Returns one if new inode created (which therefore needs to be hashed) */
|
||||
/* Returns 1 if new inode created, 2 if both dentry and inode were */
|
||||
/* Might check in the future if inode number changed so we can rehash inode */
|
||||
static int construct_dentry(struct qstr *qstring, struct file *file,
|
||||
struct inode **ptmp_inode, struct dentry **pnew_dentry)
|
||||
static int
|
||||
construct_dentry(struct qstr *qstring, struct file *file,
|
||||
struct inode **ptmp_inode, struct dentry **pnew_dentry,
|
||||
__u64 *inum)
|
||||
{
|
||||
struct dentry *tmp_dentry;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
struct dentry *tmp_dentry = NULL;
|
||||
struct super_block *sb = file->f_path.dentry->d_sb;
|
||||
int rc = 0;
|
||||
|
||||
cFYI(1, ("For %s", qstring->name));
|
||||
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
||||
pTcon = cifs_sb->tcon;
|
||||
|
||||
qstring->hash = full_name_hash(qstring->name, qstring->len);
|
||||
tmp_dentry = d_lookup(file->f_path.dentry, qstring);
|
||||
if (tmp_dentry) {
|
||||
/* BB: overwrite old name? i.e. tmp_dentry->d_name and
|
||||
* tmp_dentry->d_name.len??
|
||||
*/
|
||||
cFYI(0, ("existing dentry with inode 0x%p",
|
||||
tmp_dentry->d_inode));
|
||||
*ptmp_inode = tmp_dentry->d_inode;
|
||||
/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
|
||||
if (*ptmp_inode == NULL) {
|
||||
*ptmp_inode = new_inode(file->f_path.dentry->d_sb);
|
||||
*ptmp_inode = cifs_new_inode(sb, inum);
|
||||
if (*ptmp_inode == NULL)
|
||||
return rc;
|
||||
rc = 1;
|
||||
}
|
||||
if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
|
||||
(*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
} else {
|
||||
tmp_dentry = d_alloc(file->f_path.dentry, qstring);
|
||||
if (tmp_dentry == NULL) {
|
||||
|
@ -93,15 +92,14 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
|
|||
return rc;
|
||||
}
|
||||
|
||||
*ptmp_inode = new_inode(file->f_path.dentry->d_sb);
|
||||
if (pTcon->nocase)
|
||||
if (CIFS_SB(sb)->tcon->nocase)
|
||||
tmp_dentry->d_op = &cifs_ci_dentry_ops;
|
||||
else
|
||||
tmp_dentry->d_op = &cifs_dentry_ops;
|
||||
|
||||
*ptmp_inode = cifs_new_inode(sb, inum);
|
||||
if (*ptmp_inode == NULL)
|
||||
return rc;
|
||||
if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
|
||||
(*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
|
||||
rc = 2;
|
||||
}
|
||||
|
||||
|
@ -822,7 +820,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
|
|||
/* inode num, inode type and filename returned */
|
||||
static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
||||
char *current_entry, __u16 level, unsigned int unicode,
|
||||
struct cifs_sb_info *cifs_sb, int max_len, ino_t *pinum)
|
||||
struct cifs_sb_info *cifs_sb, int max_len, __u64 *pinum)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned int len = 0;
|
||||
|
@ -842,9 +840,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
|||
len = strnlen(filename, PATH_MAX);
|
||||
}
|
||||
|
||||
/* BB fixme - hash low and high 32 bits if not 64 bit arch BB */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
|
||||
*pinum = pFindData->UniqueId;
|
||||
*pinum = pFindData->UniqueId;
|
||||
} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
|
||||
FILE_DIRECTORY_INFO *pFindData =
|
||||
(FILE_DIRECTORY_INFO *)current_entry;
|
||||
|
@ -907,7 +903,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
|
|||
struct qstr qstring;
|
||||
struct cifsFileInfo *pCifsF;
|
||||
unsigned int obj_type;
|
||||
ino_t inum;
|
||||
__u64 inum;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct inode *tmp_inode;
|
||||
struct dentry *tmp_dentry;
|
||||
|
@ -940,20 +936,18 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry);
|
||||
/* only these two infolevels return valid inode numbers */
|
||||
if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX ||
|
||||
pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
|
||||
rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
|
||||
&inum);
|
||||
else
|
||||
rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
|
||||
NULL);
|
||||
|
||||
if ((tmp_inode == NULL) || (tmp_dentry == NULL))
|
||||
return -ENOMEM;
|
||||
|
||||
if (rc) {
|
||||
/* inode created, we need to hash it with right inode number */
|
||||
if (inum != 0) {
|
||||
/* BB fixme - hash the 2 32 quantities bits together if
|
||||
* necessary BB */
|
||||
tmp_inode->i_ino = inum;
|
||||
}
|
||||
insert_inode_hash(tmp_inode);
|
||||
}
|
||||
|
||||
/* we pass in rc below, indicating whether it is a new inode,
|
||||
so we can figure out whether to invalidate the inode cached
|
||||
data if the file has changed */
|
||||
|
|
|
@ -34,15 +34,99 @@
|
|||
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
/* Checks if this is the first smb session to be reconnected after
|
||||
the socket has been reestablished (so we know whether to use vc 0).
|
||||
Called while holding the cifs_tcp_ses_lock, so do not block */
|
||||
static bool is_first_ses_reconnect(struct cifsSesInfo *ses)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct cifsSesInfo *tmp_ses;
|
||||
|
||||
list_for_each(tmp, &ses->server->smb_ses_list) {
|
||||
tmp_ses = list_entry(tmp, struct cifsSesInfo,
|
||||
smb_ses_list);
|
||||
if (tmp_ses->need_reconnect == false)
|
||||
return false;
|
||||
}
|
||||
/* could not find a session that was already connected,
|
||||
this must be the first one we are reconnecting */
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* vc number 0 is treated specially by some servers, and should be the
|
||||
* first one we request. After that we can use vcnumbers up to maxvcs,
|
||||
* one for each smb session (some Windows versions set maxvcs incorrectly
|
||||
* so maxvc=1 can be ignored). If we have too many vcs, we can reuse
|
||||
* any vc but zero (some servers reset the connection on vcnum zero)
|
||||
*
|
||||
*/
|
||||
static __le16 get_next_vcnum(struct cifsSesInfo *ses)
|
||||
{
|
||||
__u16 vcnum = 0;
|
||||
struct list_head *tmp;
|
||||
struct cifsSesInfo *tmp_ses;
|
||||
__u16 max_vcs = ses->server->max_vcs;
|
||||
__u16 i;
|
||||
int free_vc_found = 0;
|
||||
|
||||
/* Quoting the MS-SMB specification: "Windows-based SMB servers set this
|
||||
field to one but do not enforce this limit, which allows an SMB client
|
||||
to establish more virtual circuits than allowed by this value ... but
|
||||
other server implementations can enforce this limit." */
|
||||
if (max_vcs < 2)
|
||||
max_vcs = 0xFFFF;
|
||||
|
||||
write_lock(&cifs_tcp_ses_lock);
|
||||
if ((ses->need_reconnect) && is_first_ses_reconnect(ses))
|
||||
goto get_vc_num_exit; /* vcnum will be zero */
|
||||
for (i = ses->server->srv_count - 1; i < max_vcs; i++) {
|
||||
if (i == 0) /* this is the only connection, use vc 0 */
|
||||
break;
|
||||
|
||||
free_vc_found = 1;
|
||||
|
||||
list_for_each(tmp, &ses->server->smb_ses_list) {
|
||||
tmp_ses = list_entry(tmp, struct cifsSesInfo,
|
||||
smb_ses_list);
|
||||
if (tmp_ses->vcnum == i) {
|
||||
free_vc_found = 0;
|
||||
break; /* found duplicate, try next vcnum */
|
||||
}
|
||||
}
|
||||
if (free_vc_found)
|
||||
break; /* we found a vcnumber that will work - use it */
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
vcnum = 0; /* for most common case, ie if one smb session, use
|
||||
vc zero. Also for case when no free vcnum, zero
|
||||
is safest to send (some clients only send zero) */
|
||||
else if (free_vc_found == 0)
|
||||
vcnum = 1; /* we can not reuse vc=0 safely, since some servers
|
||||
reset all uids on that, but 1 is ok. */
|
||||
else
|
||||
vcnum = i;
|
||||
ses->vcnum = vcnum;
|
||||
get_vc_num_exit:
|
||||
write_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
return le16_to_cpu(vcnum);
|
||||
}
|
||||
|
||||
static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
|
||||
{
|
||||
__u32 capabilities = 0;
|
||||
|
||||
/* init fields common to all four types of SessSetup */
|
||||
/* note that header is initialized to zero in header_assemble */
|
||||
/* Note that offsets for first seven fields in req struct are same */
|
||||
/* in CIFS Specs so does not matter which of 3 forms of struct */
|
||||
/* that we use in next few lines */
|
||||
/* Note that header is initialized to zero in header_assemble */
|
||||
pSMB->req.AndXCommand = 0xFF;
|
||||
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
|
||||
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
|
||||
pSMB->req.VcNumber = get_next_vcnum(ses);
|
||||
|
||||
/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
|
||||
|
||||
|
@ -71,7 +155,6 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
|
|||
if (ses->capabilities & CAP_UNIX)
|
||||
capabilities |= CAP_UNIX;
|
||||
|
||||
/* BB check whether to init vcnum BB */
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
|
@ -228,7 +311,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
|
|||
|
||||
kfree(ses->serverOS);
|
||||
/* UTF-8 string will not grow more than four times as big as UCS-16 */
|
||||
ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
|
||||
ses->serverOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL);
|
||||
if (ses->serverOS != NULL)
|
||||
cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp);
|
||||
data += 2 * (len + 1);
|
||||
|
@ -241,7 +324,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
|
|||
return rc;
|
||||
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
|
||||
ses->serverNOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL);
|
||||
if (ses->serverNOS != NULL) {
|
||||
cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
|
||||
nls_cp);
|
||||
|
|
Загрузка…
Ссылка в новой задаче