Commit 9054cc31 authored by Vitaly Lipatov's avatar Vitaly Lipatov Committed by Automatic Converter

1.50c-alt4

- fix build on Fedora 8 (2.6.18-53)
parent 08a10117
tar.bz2: cifs-bld-tmp name=cifs-@version@ base=cifs-bld-tmp tar.bz2: new-cifs-backport name=cifs-@version@ base=new-cifs-backport
tar.bz2: linux-cifs tar.bz2: linux-cifs
/*
* fs/cifs/cifsfs.c
*
* Copyright (C) International Business Machines Corp., 2002,2004
* Author(s): Steve French (sfrench@us.ibm.com)
*
* Common Internet FileSystem (CIFS) client
*
* 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
*/
/* Note that BB means BUGBUG (ie something to fix eventually) */
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/seq_file.h>
#include <linux/vfs.h>
#include <linux/delay.h>
#include "cifsfs.h"
#include "cifspdu.h"
#define DECLARE_GLOBALS_HERE
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#include <linux/mm.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25))
#include <linux/moduleparam.h>
#endif
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
#ifdef CONFIG_CIFS_QUOTA
static struct quotactl_ops cifs_quotactl_ops;
#endif
int cifsFYI = 0;
int cifsERROR = 1;
int traceSMB = 0;
unsigned int oplockEnabled = 1;
unsigned int experimEnabled = 0;
unsigned int linuxExtEnabled = 1;
unsigned int lookupCacheEnabled = 1;
unsigned int multiuser_mount = 0;
unsigned int extended_security = CIFSSEC_DEF;
/* unsigned int ntlmv2_support = 0; */
unsigned int sign_CIFS_PDUs = 1;
extern struct task_struct * oplockThread; /* remove sparse warning */
struct task_struct * oplockThread = NULL;
static struct task_struct * dnotifyThread;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
MODULE_PARM(CIFSMaxBufSize, "i");
MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL;
MODULE_PARM(cifs_min_rcv, "i");
MODULE_PARM_DESC(cifs_min_rcv,"Network buffers in pool. Default: 4 Range: 1 to 64");
unsigned int cifs_min_small = 30;
MODULE_PARM(cifs_min_small, "i");
MODULE_PARM_DESC(cifs_min_small,"Small network buffers in pool. Default: 30 Range: 2 to 256");
unsigned int cifs_max_pending = CIFS_MAX_REQ;
MODULE_PARM(cifs_max_pending, "i");
MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256");
static DECLARE_COMPLETION(cifs_oplock_exited);
static DECLARE_COMPLETION(cifs_dnotify_exited);
extern kmem_cache_t *cifs_oplock_cachep;
static struct super_block *
cifs_read_super(struct super_block *sb, void *data,
int silent)
{
struct inode *inode;
struct cifs_sb_info *cifs_sb;
int rc = 0;
sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */
cifs_sb = CIFS_SB(sb);
if(cifs_sb == NULL)
return 0;
rc = cifs_mount(sb, cifs_sb, data, NULL);
if (rc) {
if (!silent)
cERROR(1, ("cifs_mount failed, return code = %d", rc));
goto out_mount_failed;
}
sb->s_magic = CIFS_MAGIC_NUMBER;
sb->s_op = &cifs_super_ops;
/* 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; */
#ifdef CONFIG_CIFS_QUOTA
sb->s_qcop = &cifs_quotactl_ops;
#endif
sb->s_blocksize = CIFS_MAX_MSGSIZE;
sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */
inode = iget(sb, ROOT_I);
if (!inode) {
rc = -ENOMEM;
goto out_no_root;
}
sb->s_root = d_alloc_root(inode);
if (!sb->s_root) {
rc = -ENOMEM;
goto out_no_root;
}
return sb;
out_no_root:
cERROR(1, ("cifs_read_super: get root inode failed"));
if (inode)
iput(inode);
out_mount_failed:
if(cifs_sb) {
if(cifs_sb->local_nls)
unload_nls(cifs_sb->local_nls);
}
return 0;
}
static void
cifs_put_super(struct super_block *sb)
{
int rc = 0;
struct cifs_sb_info *cifs_sb;
cFYI(1, ("In cifs_put_super"));
cifs_sb = CIFS_SB(sb);
if(cifs_sb == NULL) {
cFYI(1,("Empty cifs superblock info passed to unmount"));
return;
}
rc = cifs_umount(sb, cifs_sb);
if (rc) {
cERROR(1, ("cifs_umount failed with return code %d", rc));
}
unload_nls(cifs_sb->local_nls);
return;
}
void * kzalloc(size_t size, unsigned flgs)
{
void * buf;
buf = kmalloc(size, flgs);
if(buf != NULL)
memset(buf, 0, size);
return buf;
}
static int
cifs_statfs(struct super_block *sb, struct statfs *buf)
{
int xid;
int rc = -EOPNOTSUPP;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
xid = GetXid();
cifs_sb = CIFS_SB(sb);
pTcon = cifs_sb->tcon;
buf->f_type = CIFS_MAGIC_NUMBER;
/* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */
buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would
presumably be total path, but note
that some servers (includinng Samba 3)
have a shorter maximum path */
buf->f_files = 0; /* undefined */
buf->f_ffree = 0; /* unlimited */
#ifdef CONFIG_CIFS_EXPERIMENTAL
/* BB we could add a second check for a QFS Unix capability bit */
/* BB FIXME check CIFS_POSIX_EXTENSIONS Unix cap first FIXME BB */
if ((pTcon->ses->capabilities & CAP_UNIX) && (CIFS_POSIX_EXTENSIONS &
le64_to_cpu(pTcon->fsUnixInfo.Capability)))
rc = CIFSSMBQFSPosixInfo(xid, pTcon, buf);
/* Only need to call the old QFSInfo if failed
on newer one */
if(rc)
#endif /* CIFS_EXPERIMENTAL */
rc = CIFSSMBQFSInfo(xid, pTcon, buf);
/* Old Windows servers do not support level 103, retry with level
one if old server failed the previous call */
if(rc)
rc = SMBOldQFSInfo(xid, pTcon, buf);
/*
int f_type;
__fsid_t f_fsid;
int f_namelen; */
/* BB get from info in tcon struct at mount time call to QFSAttrInfo */
FreeXid(xid);
return 0; /* always return success? what if volume is no
longer available? */
}
static int cifs_permission(struct inode * inode, int mask)
{
struct cifs_sb_info *cifs_sb;
cifs_sb = CIFS_SB(inode->i_sb);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
return 0;
} else /* file mode might have been restricted at mount time
on the client (above and beyond ACL on servers) for
servers which do not support setting and viewing mode bits,
so allowing client to check permissions is useful */
return vfs_permission(inode, mask);
}
static kmem_cache_t *cifs_req_cachep;
static kmem_cache_t *cifs_mid_cachep;
kmem_cache_t *cifs_oplock_cachep;
static kmem_cache_t *cifs_sm_req_cachep;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
static struct inode *
cifs_alloc_inode(struct super_block *sb)
{
struct cifsInodeInfo *cifs_inode;
cifs_inode = kmem_cache_alloc(cifs_inode_cachep, SLAB_KERNEL);
if (!cifs_inode)
return NULL;
cifs_inode->cifsAttrs = 0x20; /* default */
atomic_set(&cifs_inode->inUse, 0);
cifs_inode->time = 0;
/* Until the file is open and we have gotten oplock
info back from the server, can not assume caching of
file data or metadata */
cifs_inode->clientCanCacheRead = FALSE;
cifs_inode->clientCanCacheAll = FALSE;
cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE;
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;
INIT_LIST_HEAD(&cifs_inode->openFileList);
return &cifs_inode->vfs_inode;
}
#endif
/*
* cifs_show_options() is for displaying mount options in /proc/mounts.
* Not all settable options are displayed but most of the important
* ones are.
*/
static int
cifs_show_options(struct seq_file *s, struct vfsmount *m)
{
struct cifs_sb_info *cifs_sb;
cifs_sb = CIFS_SB(m->mnt_sb);
if (cifs_sb) {
if (cifs_sb->tcon) {
seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
if (cifs_sb->tcon->ses) {
if (cifs_sb->tcon->ses->userName)
seq_printf(s, ",username=%s",
cifs_sb->tcon->ses->userName);
if(cifs_sb->tcon->ses->domainName)
seq_printf(s, ",domain=%s",
cifs_sb->tcon->ses->domainName);
}
}
seq_printf(s, ",rsize=%d",cifs_sb->rsize);
seq_printf(s, ",wsize=%d",cifs_sb->wsize);
}
return 0;
}
#ifdef CONFIG_CIFS_QUOTA
int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid,
struct fs_disk_quota * pdquota)
{
int xid;
int rc = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon;
if(cifs_sb)
pTcon = cifs_sb->tcon;
else
return -EIO;
xid = GetXid();
if(pTcon) {
cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
} else {
return -EIO;
}
FreeXid(xid);
return rc;
}
int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid,
struct fs_disk_quota * pdquota)
{
int xid;
int rc = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon;
if(cifs_sb)
pTcon = cifs_sb->tcon;
else
return -EIO;
xid = GetXid();
if(pTcon) {
cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
} else {
rc = -EIO;
}
FreeXid(xid);
return rc;
}
int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation)
{
int xid;
int rc = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon;
if(cifs_sb)
pTcon = cifs_sb->tcon;
else
return -EIO;
xid = GetXid();
if(pTcon) {
cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation));
} else {
rc = -EIO;
}
FreeXid(xid);
return rc;
}
int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats)
{
int xid;
int rc = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon;
if(cifs_sb) {
pTcon = cifs_sb->tcon;
} else {
return -EIO;
}
xid = GetXid();
if(pTcon) {
cFYI(1,("pqstats %p",qstats));
} else {
rc = -EIO;
}
FreeXid(xid);
return rc;
}
static struct quotactl_ops cifs_quotactl_ops = {
.set_xquota = cifs_xquota_set,
.get_xquota = cifs_xquota_set,
.set_xstate = cifs_xstate_set,
.get_xstate = cifs_xstate_get,
};
#endif
static void cifs_umount_begin(struct super_block * sblock)
{
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo * tcon;
cifs_sb = CIFS_SB(sblock);
if(cifs_sb == NULL)
return;
tcon = cifs_sb->tcon;
if(tcon == NULL)
return;
down(&tcon->tconSem);
if (atomic_read(&tcon->useCount) == 1)
tcon->tidStatus = CifsExiting;
up(&tcon->tconSem);
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
/* cancel_notify_requests(tcon); */
if(tcon->ses && tcon->ses->server)
{
cFYI(1,("wake up tasks now - umount begin not complete"));
wake_up_all(&tcon->ses->server->request_q);
wake_up_all(&tcon->ses->server->response_q);
msleep(1); /* yield */
/* we have to kick the requests once more */
wake_up_all(&tcon->ses->server->response_q);
msleep(1);
}
/* BB FIXME - finish add checks for tidStatus BB */
return;
}
static int cifs_remount(struct super_block *sb, int *flags, char *data)
{
*flags |= MS_NODIRATIME;
return 0;
}
struct super_operations cifs_super_ops = {
.read_inode = cifs_read_inode,
.put_super = cifs_put_super,
.statfs = cifs_statfs,
/* .drop_inode = generic_delete_inode,
.delete_inode = cifs_delete_inode, *//* Do not need the above two functions
unless later we add lazy close of inodes or unless the kernel forgets to call
us with the same number of releases (closes) as opens */
.show_options = cifs_show_options,
.umount_begin = cifs_umount_begin,
.remount_fs = cifs_remount,
};
static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
{
/* origin == SEEK_END => we must revalidate the cached file length */
if (origin == 2) {
int retval = cifs_revalidate(file->f_dentry);
if (retval < 0)
return (loff_t)retval;
}
return generic_file_llseek(file, offset, origin);
}
static ssize_t
cifs_read_wrapper(struct file * file, char *read_data, size_t read_size,
loff_t * poffset)
{
if(file == NULL)
return -EIO;
else if(file->f_dentry == NULL)
return -EIO;
else if(file->f_dentry->d_inode == NULL)
return -EIO;
if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) {
return generic_file_read(file,read_data,read_size,poffset);
} else {
/* BB do we need to lock inode from here until after invalidate? */
/* if(file->f_dentry->d_inode->i_mapping) {
filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
}*/
/* cifs_revalidate(file->f_dentry);*/ /* BB fixme */
/* BB we should make timer configurable - perhaps
by simply calling cifs_revalidate here */
/* invalidate_remote_inode(file->f_dentry->d_inode);*/
return generic_file_read(file,read_data,read_size,poffset);
}
}
static ssize_t
cifs_write_wrapper(struct file * file, const char *write_data,
size_t write_size, loff_t * poffset)
{
ssize_t written;
if(file == NULL)
return -EIO;
else if(file->f_dentry == NULL)
return -EIO;
else if(file->f_dentry->d_inode == NULL)
return -EIO;
/* check whether we can cache writes locally */
written = generic_file_write(file,write_data,write_size,poffset);
if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) {
if(file->f_dentry->d_inode->i_mapping) {
filemap_fdatasync(file->f_dentry->d_inode->i_mapping);
}
}
return written;
}
static DECLARE_FSTYPE(cifs_fs_type, "cifs", cifs_read_super,0);
struct inode_operations cifs_dir_inode_ops = {
.create = cifs_create,
.lookup = cifs_lookup,
.unlink = cifs_unlink,
.link = cifs_hardlink,
.mkdir = cifs_mkdir,
.rmdir = cifs_rmdir,
.rename = cifs_rename,
.permission = cifs_permission,
.revalidate = cifs_revalidate,
.setattr = cifs_setattr,
.symlink = cifs_symlink,
.mknod = cifs_mknod,
#ifdef CONFIG_CIFS_XATTR
.setxattr = cifs_setxattr,
.getxattr = cifs_getxattr,
.listxattr = cifs_listxattr,
.removexattr = cifs_removexattr,
#endif
};
struct inode_operations cifs_file_inode_ops = {
.revalidate = cifs_revalidate,
.setattr = cifs_setattr,
.rename = cifs_rename,
.permission = cifs_permission,
#ifdef CONFIG_CIFS_XATTR
.setxattr = cifs_setxattr,
.getxattr = cifs_getxattr,
.listxattr = cifs_listxattr,
.removexattr = cifs_removexattr,
#endif
};
struct inode_operations cifs_symlink_inode_ops = {
.readlink = cifs_readlink,
.follow_link = cifs_follow_link,
.permission = cifs_permission,
/* BB add the following two eventually */
/* revalidate: cifs_revalidate,
setattr: cifs_notify_change, *//* BB do we need notify change */
#ifdef CONFIG_CIFS_XATTR
.setxattr = cifs_setxattr,
.getxattr = cifs_getxattr,
.listxattr = cifs_listxattr,
.removexattr = cifs_removexattr,
#endif
};
const struct file_operations cifs_file_ops = {
.read = cifs_read_wrapper,
.write = cifs_write_wrapper,
.open = cifs_open,
.release = cifs_close,
.lock = cifs_lock,
.fsync = cifs_fsync,
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */
#ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
const struct file_operations cifs_file_direct_ops = {
/* no mmap, no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */
.read = cifs_user_read,
.write = cifs_user_write,
.open = cifs_open,
.release = cifs_close,
.lock = cifs_lock,
.fsync = cifs_fsync,
.flush = cifs_flush,
#ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
const struct file_operations cifs_file_nobrl_ops = {
.read = cifs_read_wrapper,
.write = cifs_write_wrapper,
.open = cifs_open,
.release = cifs_close,
.fsync = cifs_fsync,
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */
#ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
const struct file_operations cifs_file_direct_nobrl_ops = {
/* no mmap, no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */
.read = cifs_user_read,
.write = cifs_user_write,
.open = cifs_open,
.release = cifs_close,
.fsync = cifs_fsync,
.flush = cifs_flush,
#ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */
.llseek = cifs_llseek,
#ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
const struct file_operations cifs_dir_ops = {
.readdir = cifs_readdir,
.release = cifs_closedir,
.read = generic_read_dir,
#ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
.ioctl = cifs_ioctl,
};
static int
cifs_init_request_bufs(void)
{
if(CIFSMaxBufSize < 8192) {
/* Buffer size can not be smaller than 2 * PATH_MAX since maximum
Unicode path name has to fit in any SMB/CIFS path based frames */
CIFSMaxBufSize = 8192;
} else if (CIFSMaxBufSize > 1024*127) {
CIFSMaxBufSize = 1024 * 127;
} else {
CIFSMaxBufSize &= 0x1FE00; /* Round size to even 512 byte mult*/
}
/* cERROR(1,("CIFSMaxBufSize %d 0x%x",CIFSMaxBufSize,CIFSMaxBufSize)); */
cifs_req_cachep = kmem_cache_create("cifs_request",
CIFSMaxBufSize +
MAX_CIFS_HDR_SIZE, 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (cifs_req_cachep == NULL)
return -ENOMEM;
/* if(cifs_min_rcv < 1)
cifs_min_rcv = 1;
else if (cifs_min_rcv > 64) {
cifs_min_rcv = 64;
cERROR(1,("cifs_min_rcv set to maximum (64)"));
}
cifs_req_poolp = mempool_create(cifs_min_rcv,
mempool_alloc_slab,
mempool_free_slab,
cifs_req_cachep);
if(cifs_req_poolp == NULL) {
kmem_cache_destroy(cifs_req_cachep);
return -ENOMEM;
} */
/* MAX_CIFS_SMALL_BUFFER_SIZE bytes is enough for most SMB responses and
almost all handle based requests (but not write response, nor is it
sufficient for path based requests). A smaller size would have
been more efficient (compacting multiple slab items on one 4k page)
for the case in which debug was on, but this larger size allows
more SMBs to use small buffer alloc and is still much more
efficient to alloc 1 per page off the slab compared to 17K (5page)
alloc of large cifs buffers even when page debugging is on */
cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq",
MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
if (cifs_sm_req_cachep == NULL) {
/* mempool_destroy(cifs_req_poolp); */
kmem_cache_destroy(cifs_req_cachep);
return -ENOMEM;
}
if(cifs_min_small < 2)
cifs_min_small = 2;
else if (cifs_min_small > 256) {
cifs_min_small = 256;
cFYI(1,("cifs_min_small set to maximum (256)"));
}
/* cifs_sm_req_poolp = mempool_create(cifs_min_small,
mempool_alloc_slab,
mempool_free_slab,
cifs_sm_req_cachep);
if(cifs_sm_req_poolp == NULL) {
mempool_destroy(cifs_req_poolp);
kmem_cache_destroy(cifs_req_cachep);
kmem_cache_destroy(cifs_sm_req_cachep);
return -ENOMEM;
} */
return 0;
}
static void
cifs_destroy_request_bufs(void)
{
/* mempool_destroy(cifs_req_poolp); */
if (kmem_cache_destroy(cifs_req_cachep))
printk(KERN_WARNING
"cifs_destroy_request_cache: error not all structures were freed\n");
/* mempool_destroy(cifs_sm_req_poolp); */
if (kmem_cache_destroy(cifs_sm_req_cachep))
printk(KERN_WARNING
"cifs_destroy_request_cache: cifs_small_rq free error\n");
}
static int
cifs_init_mids(void)
{
cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids",
sizeof (struct mid_q_entry), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (cifs_mid_cachep == NULL)
return -ENOMEM;
cifs_oplock_cachep = kmem_cache_create("cifs_oplock_strcts",
sizeof (struct oplock_q_entry), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (cifs_oplock_cachep == NULL) {
kmem_cache_destroy(cifs_mid_cachep);
return -ENOMEM;
}
return 0;
}
static void
cifs_destroy_mids(void)
{
/* mempool_destroy(cifs_mid_poolp); */
if (kmem_cache_destroy(cifs_mid_cachep))
printk(KERN_WARNING
"cifs_destroy_mids: error not all structures were freed\n");
if (kmem_cache_destroy(cifs_oplock_cachep))
printk(KERN_WARNING
"error not all oplock structures were freed\n");
}
static int cifs_oplock_thread(void * dummyarg)
{
struct oplock_q_entry * oplock_item;
struct cifsTconInfo *pTcon;
struct inode * inode;
__u16 netfid;
int rc;
daemonize();
sprintf(current->comm,"cifsoplockd");
/* allow_signal(SIGTERM);*/ /* BB Is there a 2.4 equivalent? */
oplockThread = current;
do {
spin_lock(&GlobalMid_Lock);
if(list_empty(&GlobalOplock_Q)) {
spin_unlock(&GlobalMid_Lock);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(39*HZ);
} else {
oplock_item = list_entry(GlobalOplock_Q.next,
struct oplock_q_entry, qhead);
if(oplock_item) {
cFYI(1,("found oplock item to write out"));
pTcon = oplock_item->tcon;
inode = oplock_item->pinode;
netfid = oplock_item->netfid;
spin_unlock(&GlobalMid_Lock);
DeleteOplockQEntry(oplock_item);
/* can not grab inode sem here since it would
deadlock when oplock received on delete
since vfs_unlink holds the i_mutex across
the call */
/* mutex_lock(&inode->i_mutex);*/
if (S_ISREG(inode->i_mode)) {
rc = filemap_fdatawrite(inode->i_mapping);
if(CIFS_I(inode)->clientCanCacheRead == 0) {
filemap_fdatawait(inode->i_mapping);
invalidate_remote_inode(inode);
}
} else
rc = 0;
/* mutex_unlock(&inode->i_mutex);*/
if (rc)
CIFS_I(inode)->write_behind_rc = rc;
cFYI(1,("Oplock flush inode %p rc %d",inode,rc));
/* releasing a stale oplock after recent reconnection
of smb session using a now incorrect file
handle is not a data integrity issue but do
not bother sending an oplock release if session
to server still is disconnected since oplock
already released by the server in that case */
if(pTcon->tidStatus != CifsNeedReconnect) {
rc = CIFSSMBLock(0, pTcon, netfid,
0 /* len */ , 0 /* offset */, 0,
0, LOCKING_ANDX_OPLOCK_RELEASE,
0 /* wait flag */);
cFYI(1,("Oplock release rc = %d ",rc));
}
} else
spin_unlock(&GlobalMid_Lock);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1); /* yield in case q were corrupt */
}
} while(!signal_pending(current));
oplockThread = NULL;
complete_and_exit (&cifs_oplock_exited, 0);
}
static int cifs_dnotify_thread(void * dummyarg)
{
struct list_head *tmp;
struct cifsSesInfo *ses;
daemonize();
sprintf(current->comm,"cifsdnotifyd");
/* allow_signal(SIGTERM);*/ /* BB Is there a 2.4 equivalent? */
dnotifyThread = current;
do {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(15*HZ);
read_lock(&GlobalSMBSeslock);
/* check if any stuck requests that need
to be woken up and wakeq so the
thread can wake up and error out */
list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo,
cifsSessionList);
if(ses && ses->server &&
atomic_read(&ses->server->inFlight))
wake_up_all(&ses->server->response_q);
}
read_unlock(&GlobalSMBSeslock);
} while(!signal_pending(current));
complete_and_exit (&cifs_dnotify_exited, 0);
}
static int __init
init_cifs(void)
{
int rc = 0;
#ifdef CONFIG_PROC_FS
cifs_proc_init();
#endif
/* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */
INIT_LIST_HEAD(&GlobalSMBSessionList);
INIT_LIST_HEAD(&GlobalTreeConnectionList);
INIT_LIST_HEAD(&GlobalOplock_Q);
#ifdef CONFIG_CIFS_EXPERIMENTAL
INIT_LIST_HEAD(&GlobalDnotifyReqList);
INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
#endif
/*
* Initialize Global counters
*/
atomic_set(&sesInfoAllocCount, 0);
atomic_set(&tconInfoAllocCount, 0);
atomic_set(&tcpSesAllocCount,0);
atomic_set(&tcpSesReconnectCount, 0);
atomic_set(&tconInfoReconnectCount, 0);
atomic_set(&bufAllocCount, 0);
atomic_set(&smBufAllocCount, 0);
#ifdef CONFIG_CIFS_STATS2
atomic_set(&totBufAllocCount, 0);
atomic_set(&totSmBufAllocCount, 0);
#endif /* CONFIG_CIFS_STATS2 */
atomic_set(&midCount, 0);
GlobalCurrentXid = 0;
GlobalTotalActiveXid = 0;
GlobalMaxActiveXid = 0;
rwlock_init(&GlobalSMBSeslock);
spin_lock_init(&GlobalMid_Lock);
if(cifs_max_pending < 2) {
cifs_max_pending = 2;
cFYI(1,("cifs_max_pending set to min of 2"));
} else if(cifs_max_pending > 256) {
cifs_max_pending = 256;
cFYI(1,("cifs_max_pending set to max of 256"));
}
/* rc = cifs_init_inodecache();*/
if (!rc) {
rc = cifs_init_mids();
if (!rc) {
rc = cifs_init_request_bufs();
if (!rc) {
rc = register_filesystem(&cifs_fs_type);
if (!rc) {
rc = (int)kernel_thread(cifs_oplock_thread, NULL,
CLONE_FS | CLONE_FILES | CLONE_VM);
if(rc > 0) {
rc = (int)kernel_thread(cifs_dnotify_thread, NULL,
CLONE_FS | CLONE_FILES | CLONE_VM);
if(rc > 0)
return 0;
else
cERROR(1,("error %d create dnotify thread", rc));
} else {
cERROR(1,("error %d create oplock thread",rc));
}
}
cifs_destroy_request_bufs();
}
cifs_destroy_mids();
}
/* cifs_destroy_inodecache();*/
}
#ifdef CONFIG_PROC_FS
cifs_proc_clean();
#endif
return rc;
}
static void __exit
exit_cifs(void)
{
cFYI(0, ("In unregister ie exit_cifs"));
#ifdef CONFIG_PROC_FS
cifs_proc_clean();
#endif
unregister_filesystem(&cifs_fs_type);
/* cifs_destroy_inodecache();*/
cifs_destroy_mids();
cifs_destroy_request_bufs();
if(oplockThread) {
send_sig(SIGTERM, oplockThread, 1);
wait_for_completion(&cifs_oplock_exited);
}
if(dnotifyThread) {
send_sig(SIGTERM, dnotifyThread, 1);
wait_for_completion(&cifs_dnotify_exited);
}
}
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */
MODULE_DESCRIPTION
("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows");
module_init(init_cifs)
module_exit(exit_cifs)
# Etersoft (c) 2007 # Etersoft (c) 2007, 2008
# Multiplatform spec for autobuild system # Multiplatform spec for autobuild system
# in kernel build dir you can have gcc_version.inc file with export GCC_VERSION=x.xx # in kernel build dir you can have gcc_version.inc file with export GCC_VERSION=x.xx
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
# kernel-source-XXXX for Slackware / MOPSLinux # kernel-source-XXXX for Slackware / MOPSLinux
Name: linux-cifs Name: linux-cifs
Version: 1.48a Version: 1.50c
%define relnum 7 Release: alt4
Summary: Advanced Common Internet File System for Linux with Etersoft extension Summary: Advanced Common Internet File System for Linux with Etersoft extension
...@@ -26,27 +26,19 @@ Url: http://linux-cifs.samba.org/ ...@@ -26,27 +26,19 @@ Url: http://linux-cifs.samba.org/
Source: ftp://updates.etersoft.ru/pub/Etersoft/WINE@Etersoft/sources/tarball/%name-%version.tar.bz2 Source: ftp://updates.etersoft.ru/pub/Etersoft/WINE@Etersoft/sources/tarball/%name-%version.tar.bz2
Source1: http://pserver.samba.org/samba/ftp/cifs-cvs/cifs-%version.tar.bz2 Source1: http://pserver.samba.org/samba/ftp/cifs-cvs/cifs-%version.tar.bz2
BuildRequires: rpm-build-compat >= 0.97
# Spec part for ALT Linux # Spec part for ALT Linux
%if %_vendor == "alt" %if %_vendor == "alt"
Release: alt%relnum
BuildRequires: rpm-build-compat >= 0.7
BuildRequires: kernel-build-tools BuildRequires: kernel-build-tools
BuildRequires: kernel-headers-modules-std-smp kernel-headers-modules-wks-smp kernel-headers-modules-ovz-smp BuildRequires: kernel-headers-modules-std-smp kernel-headers-modules-ovz-smp kernel-headers-modules-std-def
# do not work?
%ifarch x86_64 %ifarch x86_64
# Don't know if ifnarch exist # Don't know if ifnarch exist
BuildRequires: kernel-headers-modules-std-smp BuildRequires: kernel-headers-modules-std-smp
%else %else
BuildRequires: kernel-headers-modules-std-pae BuildRequires: kernel-headers-modules-std-pae
%endif %endif
%else
Release: eter%relnum%_vendor
BuildRequires: rpm-build-altlinux-compat >= 0.7
%endif
# FIXME: ifndef broken in Ubuntu
#ifndef buildroot
%if %{undefined buildroot}
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
%endif %endif
%if %_vendor == "suse" %if %_vendor == "suse"
...@@ -82,32 +74,56 @@ though. ...@@ -82,32 +74,56 @@ though.
This package has Etersoft's patches for WINE@Etersoft sharing access support. This package has Etersoft's patches for WINE@Etersoft sharing access support.
#cifs-bld-tmp/fs/cifs
%define intdir new-cifs-backport
%prep %prep
%setup -q %setup -q
tar xfj %SOURCE1 tar xfj %SOURCE1
patch -s -p1 -d cifs-bld-tmp/fs/cifs <%name-shared.patch patch -s -p1 -d %intdir <%name-shared-%version.patch
%install %install
#export KBUILD_VERBOSE=1 #export KBUILD_VERBOSE=1
MAN_DIR=%buildroot%_mandir/ INIT_DIR=%buildroot%_initdir/ SBIN_DIR=%buildroot%_sbindir/ INSTALL_MOD_PATH=%buildroot%module_dir ./build.sh MAN_DIR=%buildroot%_mandir/ INIT_DIR=%buildroot%_initdir/ SBIN_DIR=%buildroot%_sbindir/ \
INSTALL_MOD_PATH=%buildroot/lib/modules BUILDDIR=`pwd`/%intdir \
DESTDIR=%buildroot SRC_DIR=%_usrsrc/%name-%version ./build.sh
# Debian, Suse, Slackware do not have command service
# start service if first time install
%post %post
%post_service %name %post_service %name
[ "$1" = "1" ] && %_initdir/%name start || : %start_service %name
%preun %preun
%preun_service %name %preun_service %name
%files %files
%defattr(-,root,root)
%_initdir/%name %_initdir/%name
%_initdir/%name.outformat %_initdir/%name.outformat
%module_dir/ /lib/modules/*
/usr/src/%name/ %_usrsrc/%name-%version/
%changelog %changelog
* Thu Jan 31 2008 Vitaly Lipatov <lav@altlinux.ru> 1.50c-alt4
- fix build on Fedora 8 (2.6.18-53)
* Sun Jan 27 2008 Vitaly Lipatov <lav@altlinux.ru> 1.50c-alt3
- move modules placement
- move src files to name-version for dkms compatibility
- change module name to etercifs.ko
* Fri Dec 28 2007 Vitaly Lipatov <lav@altlinux.ru> 1.50c-alt2
- add fix for SLED10 kernel 2.6.16.46
- fix warnings, add missed access setting in reopen file func
* Tue Nov 06 2007 Vitaly Lipatov <lav@altlinux.ru> 1.50c-alt1
- update version
- fix spec according to Korinf build system
* Fri Oct 12 2007 Vitaly Lipatov <lav@altlinux.ru> 1.50-alt1
- update version
* Fri Sep 14 2007 Sergey Lebedev <barabashka@altlinux.ru> 1.50-alt0
- new version cifs 1.50
* Fri Jul 27 2007 Vitaly Lipatov <lav@altlinux.ru> 1.48a-alt7 * Fri Jul 27 2007 Vitaly Lipatov <lav@altlinux.ru> 1.48a-alt7
- fix build on 2.6.22 kernels - fix build on 2.6.22 kernels
- fix scripts for Debian/Ubuntu - fix scripts for Debian/Ubuntu
......
/functions.sh/1.1/Sat Jun 9 18:28:40 2007// /functions.sh/1.1/Sat Jun 9 18:28:40 2007//
/kernel_src.list/1.1/Fri Jun 8 11:05:01 2007//
/linux-cifs_depmod.sh/1.1/Fri Mar 16 18:14:13 2007// /linux-cifs_depmod.sh/1.1/Fri Mar 16 18:14:13 2007//
/buildmodule.sh/1.13/Sat Jun 23 07:18:55 2007//
D/gentoo//// D/gentoo////
/build.sh/1.23/Tue Jul 3 06:26:08 2007//
/TODO/1.6/Tue Jul 3 06:12:36 2007//
/linux-cifs.outformat/1.3/Fri Jul 27 11:55:53 2007// /linux-cifs.outformat/1.3/Fri Jul 27 11:55:53 2007//
/linux-cifs-shared.patch/1.29/Fri Jul 27 16:25:24 2007// /linux-cifs-shared.patch/1.29/Fri Jul 27 16:25:24 2007//
/linux-cifs.spec/1.21/Fri Jul 27 16:41:33 2007// /linux-cifs-shared-1.50.patch/1.1/Fri Sep 14 12:11:33 2007//
/linux-cifs.init/1.27/Fri Aug 31 18:21:27 2007// /kernel_src.list/1.2/Fri Dec 7 14:19:41 2007//
/linux-cifs.release.sh/1.2/Fri Jul 27 11:58:40 2007// /TODO/1.8/Sun Jan 27 15:46:44 2008//
/build.sh/1.26/Sun Jan 27 16:54:11 2008//
/linux-cifs.release.sh/1.4/Sun Jan 27 16:44:57 2008//
/buildmodule.sh/1.15/Sun Jan 27 17:45:53 2008//
/dkms-linux-cifs.spec/1.2/Sun Jan 27 17:58:57 2008//
/linux-cifs.init/1.36/Sun Jan 27 18:00:59 2008//
/linux-cifs-shared-1.50c.patch/1.8/Thu Jan 31 10:49:35 2008//
/linux-cifs.spec/1.29/Thu Jan 31 10:50:25 2008//
/var/local/cvsroot :ext:cvs.etersoft/var/local/cvsroot
[12:51:54] <Lav> LinuxExtensions UNIX-, ģ
[12:52:23] <lebedev.sv> ?
[12:52:37] <Lav> nounix,
[12:53:14] <lebedev.sv> ? ?
[12:53:54] <lebedev.sv> , lin to win , mount -o nounix
LinuxExtensions ( unix) ?
ݣ , , - ?
+ gcc + gcc
+ ? + ?
wine, - ? wine, - ?
Что делать с -e - посмотреть, как устроено в Ubuntu + -e - , Ubuntu
/proc /proc
#!/bin/sh #!/bin/sh
# 2006, 2007 (c) Etersoft http://etersoft.ru # 2006, 2007, 2008 (c) Etersoft http://etersoft.ru
# Author: Vitaly Lipatov <lav@etersoft.ru> # Author: Vitaly Lipatov <lav@etersoft.ru>
# GNU Public License # GNU Public License
...@@ -7,18 +7,21 @@ ...@@ -7,18 +7,21 @@
. ./functions.sh . ./functions.sh
echo "All kernel build script. (c) 2007 Etersoft. $Id: build.sh,v 1.23 2007/07/03 06:26:08 lav Exp $" echo "All kernel build script. (c) 2007, 2008 Etersoft. $Id: build.sh,v 1.26 2008/01/27 16:54:11 lav Exp $"
PACKNAME=linux-cifs PACKNAME=linux-cifs
MODULENAME=etercifs
get_src_dir || fatal "Distro $($DISTR_VENDOR -e) is not supported yet" get_src_dir || fatal "Distro $($DISTR_VENDOR -e) is not supported yet"
BUILDDIR=`pwd`/cifs-bld-tmp/fs/cifs [ -n "$BUILDDIR" ] || BUILDDIR=`pwd`/new-cifs-backport
BUILTLIST= BUILTLIST=
# SMP build # SMP build
[ -z "$RPM_BUILD_NCPUS" ] && RPM_BUILD_NCPUS=`/usr/bin/getconf _NPROCESSORS_ONLN` [ -z "$RPM_BUILD_NCPUS" ] && RPM_BUILD_NCPUS=`/usr/bin/getconf _NPROCESSORS_ONLN`
[ "$RPM_BUILD_NCPUS" -gt 1 ] && MAKESMP="-j$RPM_BUILD_NCPUS" || MAKESMP="" [ "$RPM_BUILD_NCPUS" -gt 1 ] && MAKESMP="-j$RPM_BUILD_NCPUS" || MAKESMP=""
# Heuristic
detect_kernel() detect_kernel()
{ {
# Detect kernel version # Detect kernel version
...@@ -41,10 +44,11 @@ detect_kernel() ...@@ -41,10 +44,11 @@ detect_kernel()
fi fi
} }
echo "Install sources to $SBIN_DIR/../src/linux-cifs/" [ -z "$DESTDIR$SRC_DIR" ] && exit 1
install -m755 -d $SBIN_DIR/../src/linux-cifs/ echo "Install sources to $DESTDIR/$SRC_DIR"
install -m644 $BUILDDIR/* $SBIN_DIR/../src/linux-cifs/ || exit 1 install -m755 -d $DESTDIR/$SRC_DIR
install -m644 buildmodule.sh $SBIN_DIR/../src/linux-cifs/ || exit 1 install -m644 $BUILDDIR/* $DESTDIR/$SRC_DIR || exit 1
install -m644 buildmodule.sh $DESTDIR/$SRC_DIR || exit 1
for KERNEL_SOURCE in `echo $BASE_KERNEL_SOURCES_DIR` ; do for KERNEL_SOURCE in `echo $BASE_KERNEL_SOURCES_DIR` ; do
[ -L $KERNEL_SOURCE ] && [ `basename $KERNEL_SOURCE` != "build" ] && continue [ -L $KERNEL_SOURCE ] && [ `basename $KERNEL_SOURCE` != "build" ] && continue
...@@ -69,15 +73,14 @@ for KERNEL_SOURCE in `echo $BASE_KERNEL_SOURCES_DIR` ; do ...@@ -69,15 +73,14 @@ for KERNEL_SOURCE in `echo $BASE_KERNEL_SOURCES_DIR` ; do
# Clean, build and check # Clean, build and check
make $USEGCC -C $KERNEL_SOURCE here=$BUILDDIR SUBDIRS=$BUILDDIR clean make $USEGCC -C $KERNEL_SOURCE here=$BUILDDIR SUBDIRS=$BUILDDIR clean
make $USEGCC -C $KERNEL_SOURCE here=$BUILDDIR SUBDIRS=$BUILDDIR modules $MAKESMP make $USEGCC -C $KERNEL_SOURCE here=$BUILDDIR SUBDIRS=$BUILDDIR modules $MAKESMP
MODULENAME=cifs
#[ "$KERVER" = "2.4" ] && MODULENAME=$(echo $MODULENAME.o) || MODULENAME=$(echo $MODULENAME.?o) #[ "$KERVER" = "2.4" ] && MODULENAME=$(echo $MODULENAME.o) || MODULENAME=$(echo $MODULENAME.?o)
[ "$KERVER" = "2.4" ] && MODULENAME=$MODULENAME.o || MODULENAME=$MODULENAME.ko [ "$KERVER" = "2.4" ] && MODULEFILENAME=$MODULEFILENAME.o || MODULEFILENAME=$MODULENAME.ko
test -r "$BUILDDIR/$MODULENAME" || { echo "can't locate built module $MODULENAME, continue" ; continue ; } test -r "$BUILDDIR/$MODULEFILENAME" || { echo "can't locate built module $MODULEFILENAME, continue" ; continue ; }
#echo "$KERNELVERSION $MODULENAME to $INSTALL_MOD_PATH" #echo "$KERNELVERSION $MODULENAME to $INSTALL_MOD_PATH"
strip --strip-debug --discard-all $BUILDDIR/$MODULENAME strip --strip-debug --discard-all $BUILDDIR/$MODULEFILENAME
mkdir -p $INSTALL_MOD_PATH/$KERNELVERSION/ || fatal "broken path" mkdir -p $INSTALL_MOD_PATH/$KERNELVERSION/kernel/fs/cifs || fatal "broken path"
cp -fv $BUILDDIR/$MODULENAME $INSTALL_MOD_PATH/$KERNELVERSION/ || fatal "copy error" cp -fv $BUILDDIR/$MODULEFILENAME $INSTALL_MOD_PATH/$KERNELVERSION/kernel/fs/cifs || fatal "copy error"
# copy last as default # copy last as default
#cp -f $BUILDDIR/$MODULENAME $INSTALL_MOD_PATH/$PACKNAME/ #cp -f $BUILDDIR/$MODULENAME $INSTALL_MOD_PATH/$PACKNAME/
#make -C $KERNEL_SOURCE here=`pwd`/ SUBDIRS=`pwd`/ modules_install #make -C $KERNEL_SOURCE here=`pwd`/ SUBDIRS=`pwd`/ modules_install
...@@ -94,7 +97,8 @@ echo ...@@ -94,7 +97,8 @@ echo
mkdir -p $SBIN_DIR $INIT_DIR mkdir -p $SBIN_DIR $INIT_DIR
#install -m755 linux-cifs_depmod.sh $INSTALL_MOD_PATH/$PACKNAME/ #install -m755 linux-cifs_depmod.sh $INSTALL_MOD_PATH/$PACKNAME/
install -m755 -D $PACKNAME.init $INIT_DIR/$PACKNAME sed -e "s|@SRC_DIR@|$SRC_DIR|g" < $PACKNAME.init > $PACKNAME.init.repl
install -m755 -D $PACKNAME.init.repl $INIT_DIR/$PACKNAME
install -m755 $PACKNAME.outformat $INIT_DIR/ install -m755 $PACKNAME.outformat $INIT_DIR/
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
# Build kernel module in installed system # Build kernel module in installed system
MODULENAME=cifs.ko MODULEFILENAME=etercifs.ko
BUILDDIR=/usr/src/linux-cifs BUILDDIR=$(pwd)
KERNELVERSION=$(uname -r) KERNELVERSION=$(uname -r)
# SMP build # SMP build
...@@ -19,8 +19,8 @@ if [ -z "$KERNSRC" ]; then ...@@ -19,8 +19,8 @@ if [ -z "$KERNSRC" ]; then
KERNSRC=/lib/modules/$KERNELVERSION/build KERNSRC=/lib/modules/$KERNELVERSION/build
fi fi
if [ -z "$INSTALL_MOD_PATH" ]; then if [ -z "$INSTALL_MOD_PATH" ]; then
#INSTALL_MOD_PATH=/lib/modules/$KERNELVERSION/kernel/extra INSTALL_MOD_PATH=/lib/modules/$KERNELVERSION/kernel/fs/cifs
INSTALL_MOD_PATH=/lib/modules/linux-cifs #INSTALL_MOD_PATH=/lib/modules/linux-cifs
fi fi
echo echo
...@@ -32,7 +32,7 @@ Error: no kernel headers found at $KERNSRC ...@@ -32,7 +32,7 @@ Error: no kernel headers found at $KERNSRC
Please install package Please install package
kernel-headers-modules-XXXX for ALT Linux kernel-headers-modules-XXXX for ALT Linux
kernel-XXXX-devel for FCx / ASP Linux kernel-XXXX-devel for FCx / ASP Linux
kernel-source-stripped-XXXX for Mandriva 2007 dkms-linux-cifs for Mandriva 2008
linux-headers-XXXX for Debian / Ubuntu linux-headers-XXXX for Debian / Ubuntu
kernel-source-XXXX for SuSe kernel-source-XXXX for SuSe
kernel-source-XXXX for Slackware / MOPSLinux kernel-source-XXXX for Slackware / MOPSLinux
...@@ -58,17 +58,17 @@ if ! which $GCCNAME ; then ...@@ -58,17 +58,17 @@ if ! which $GCCNAME ; then
fi fi
# Clean, build and check # Clean, build and check
rm -f $BUILDDIR/$MODULENAME rm -f $BUILDDIR/$MODULEFILENAME
make $USEGCC -C $KERNSRC here=$BUILDDIR SUBDIRS=$BUILDDIR clean make $USEGCC -C $KERNSRC here=$BUILDDIR SUBDIRS=$BUILDDIR clean
make $USEGCC -C $KERNSRC here=$BUILDDIR SUBDIRS=$BUILDDIR modules $MAKESMP make $USEGCC -C $KERNSRC here=$BUILDDIR SUBDIRS=$BUILDDIR modules $MAKESMP
#[ "$KERVER" = "2.4" ] && MODULENAME=$MODULENAME.o || MODULENAME=$MODULENAME.ko #[ "$KERVER" = "2.4" ] && MODULENAME=$MODULENAME.o || MODULENAME=$MODULENAME.ko
test -r "$BUILDDIR/$MODULENAME" || { echo "can't locate built module $MODULENAME, continue" ; exit 1 ; } test -r "$BUILDDIR/$MODULEFILENAME" || { echo "can't locate built module $MODULEFILENAME, continue" ; exit 1 ; }
strip --strip-debug --discard-all $BUILDDIR/$MODULENAME strip --strip-debug --discard-all $BUILDDIR/$MODULEFILENAME
echo "Copying built module to $INSTALL_MOD_PATH" echo "Copying built module to $INSTALL_MOD_PATH"
mkdir -p $INSTALL_MOD_PATH mkdir -p $INSTALL_MOD_PATH
install -m 644 -o root -g root $BUILDDIR/$MODULENAME $INSTALL_MOD_PATH/ || exit 1 install -m 644 -o root -g root $BUILDDIR/$MODULEFILENAME $INSTALL_MOD_PATH/ || exit 1
#depmod -ae || exit 1 depmod -ae || exit 1
#echo "$MODULENAME build correctly" #echo "$MODULENAME build correctly"
exit 0 exit 0
%define modname linux-cifs
Name: dkms-linux-cifs
Version: 1.50c
Release: alt1
Summary: DKMS-ready CIFS Linux kernel module with Etersoft extensions
License: GPL
Packager: Vitaly Lipatov <lav@altlinux.ru>
#Source: ftp://updates.etersoft.ru/pub/Etersoft/WINE@Etersoft/sources/tarball/%name-%version.tar.bz2
Group: Development/Kernel
Requires(preun): dkms
Requires(post): dkms
Requires: linux-cifs
Buildarch: noarch
%description
The CIFS VFS is a virtual file system for Linux to allow access to
servers and storage appliances compliant with the SNIA CIFS Specification
version 1.0 or later.
This package contains DKMS-ready CIFS Linux kernel module with Etersoft extensions.
%prep
%setup -c -T -n %name-%version
%install
mkdir -p %buildroot%_usrsrc/%modname-%version/
cat > %buildroot%_usrsrc/%modname-%version/dkms.conf <<EOF
# DKMS file for Linux CIFS with Etersoft's extensions
PACKAGE_NAME="%modname"
PACKAGE_VERSION="%version"
BUILT_MODULE_NAME[0]="etercifs"
DEST_MODULE_LOCATION[0]="/kernel/fs/cifs/"
REMAKE_INITRD="no"
AUTOINSTALL="YES"
EOF
%post
if [ "$1" == 1 ]
then
dkms add -m %modname -v %version --rpm_safe_upgrade
fi
dkms build -m %modname -v %version --rpm_safe_upgrade
dkms install -m %modname -v %version --rpm_safe_upgrade
%preun
if [ "$1" == 0 ]
then
dkms remove -m %modname -v %version --rpm_safe_upgrade --all
fi
%files
%_usrsrc/%modname-%version/dkms.conf
%changelog
* Sat Jan 26 2008 Vitaly Lipatov <lav@altlinux.ru> 1.50c-alt1
- initial build for Korinf project
/var/local/cvsroot :ext:cvs.etersoft/var/local/cvsroot
/linux-cifs-1.48a.ebuild/1.5/Wed Jun 27 18:06:00 2007// /linux-cifs-1.50c.ebuild/1.3/Sun Jan 27 16:02:09 2008//
D D
/var/local/cvsroot :ext:cvs.etersoft/var/local/cvsroot
...@@ -5,13 +5,13 @@ inherit eutils flag-o-matic multilib ...@@ -5,13 +5,13 @@ inherit eutils flag-o-matic multilib
DESCRIPTION="Advanced Common Internet File System for Linux with Etersoft extension" DESCRIPTION="Advanced Common Internet File System for Linux with Etersoft extension"
HOMEPAGE="http://etersoft.ru/wine" HOMEPAGE="http://etersoft.ru/wine"
CIFSVER=1.48a CIFSVER=1.50c
WINENUMVERSION=current WINENUMVERSION=1.0.8
SRC_URI="ftp://updates.etersoft.ru/pub/Etersoft/WINE@Etersoft-$WINENUMVERSION/sources/tarball/${P}.tar.bz2 SRC_URI="ftp://updates.etersoft.ru/pub/Etersoft/WINE@Etersoft-$WINENUMVERSION/sources/tarball/${P}.tar.bz2
ftp://updates.etersoft.ru/pub/Etersoft/WINE@Etersoft-$WINENUMVERSION/sources/tarball/cifs-$CIFSVER.tar.bz2" ftp://updates.etersoft.ru/pub/Etersoft/WINE@Etersoft-$WINENUMVERSION/sources/tarball/cifs-$CIFSVER.tar.bz2"
LICENSE="LGPL-2.1" LICENSE="LGPL-2.1"
SLOT="0" SLOT="0"
KEYWORDS="-* ~amd64 ~x86" KEYWORDS="-* amd64 x86"
IUSE="" IUSE=""
RESTRICT="test" #72375 RESTRICT="test" #72375
...@@ -23,8 +23,8 @@ RDEPEND=">=sys-kernel/linux-headers-2.6" ...@@ -23,8 +23,8 @@ RDEPEND=">=sys-kernel/linux-headers-2.6"
src_unpack() { src_unpack() {
unpack ${A} unpack ${A}
cd "${WORKDIR}/${P}" || die cd "${WORKDIR}/${P}" || die
mv ../cifs-bld-tmp ./ || die mv ../new-cifs-backport ./ || die
patch -s -p1 -d cifs-bld-tmp/fs/cifs <linux-cifs-shared.patch || die patch -p1 -d new-cifs-backport/ <linux-cifs-shared-1.50c.patch || die
} }
config_cache() { config_cache() {
...@@ -46,7 +46,7 @@ src_compile() { ...@@ -46,7 +46,7 @@ src_compile() {
} }
src_install() { src_install() {
MAN_DIR=${D}/usr/man/ INIT_DIR=${D}/etc/init.d/ SBIN_DIR=${D}/usr/sbin/ INSTALL_MOD_PATH=${D}/lib/modules/ ./build.sh || die MAN_DIR=${D}/usr/man/ INIT_DIR=${D}/etc/init.d/ SBIN_DIR=${D}/usr/sbin/ INSTALL_MOD_PATH=${D}/lib/modules/ DESTDIR=${D} SRC_DIR=/usr/src/${P} ./build.sh || die
true true
} }
......
...@@ -4,6 +4,7 @@ ASPLinux /usr/src/kernels/* ...@@ -4,6 +4,7 @@ ASPLinux /usr/src/kernels/*
ASPLinux/10 /lib/modules/*/build ASPLinux/10 /lib/modules/*/build
RedHat /usr/src/kernels/* RedHat /usr/src/kernels/*
RHEL /usr/src/kernels/* RHEL /usr/src/kernels/*
CentOS /usr/src/kernels/*
LinuxXP /usr/src/kernels/* LinuxXP /usr/src/kernels/*
Scientific /usr/src/kernels/* Scientific /usr/src/kernels/*
FedoraCore /usr/src/kernels/* FedoraCore /usr/src/kernels/*
......
diff -Naur -k-orig150 cifs-orig150/asn1.c cifs/asn1.c
--- cifs-orig150/asn1.c 2007-09-14 14:45:12 +0400
+++ cifs/asn1.c 2007-09-14 15:48:01 +0400
@@ -26,7 +26,7 @@
#include "cifsglob.h"
#include "cifs_debug.h"
#include "cifsproto.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
#include <linux/config.h>
#endif
diff -Naur -k-orig150 cifs-orig150/cifs_debug.c cifs/cifs_debug.c
--- cifs-orig150/cifs_debug.c 2007-09-14 14:45:12 +0400
+++ cifs/cifs_debug.c 2007-09-14 14:49:18 +0400
@@ -460,6 +460,8 @@
static write_proc_t experimEnabled_write;
static read_proc_t linuxExtensionsEnabled_read;
static write_proc_t linuxExtensionsEnabled_write;
+static read_proc_t etersoft_read;
+static write_proc_t etersoft_write;
void
cifs_proc_init(void)
@@ -524,6 +526,12 @@
if (pde)
pde->write_proc = lookupFlag_write;
+ pde =
+ create_proc_read_entry("Etersoft", 0, proc_fs_cifs,
+ etersoft_read, NULL);
+ if (pde)
+ pde->write_proc = etersoft_write;
+
/* pde =
create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
ntlmv2_enabled_read, NULL);
@@ -557,6 +565,7 @@
remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
remove_proc_entry("Experimental", proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
+ remove_proc_entry("Etersoft",proc_fs_cifs);
remove_proc_entry("cifs", proc_root_fs);
}
@@ -910,4 +919,44 @@
/* BB should we turn on MAY flags for other MUST options? */
return count;
}
+
+static int
+etersoft_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", etersoft_flag);
+
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+etersoft_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ etersoft_flag = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ etersoft_flag = 1;
+
+ return count;
+}
+
#endif
diff -Naur -k-orig150 cifs-orig150/cifsfs.c cifs/cifsfs.c
--- cifs-orig150/cifsfs.c 2007-09-14 14:45:12 +0400
+++ cifs/cifsfs.c 2007-09-14 15:50:36 +0400
@@ -61,6 +61,7 @@
int cifsFYI = 0;
int cifsERROR = 1;
int traceSMB = 0;
+unsigned int etersoft_flag = 1;
unsigned int oplockEnabled = 1;
unsigned int experimEnabled = 0;
unsigned int linuxExtEnabled = 1;
@@ -190,7 +191,7 @@
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
-void * kzalloc(size_t size, unsigned flgs)
++void * kzalloc(size_t size, int flgs)
{
void * buf;
buf = kmalloc(size, flgs);
@@ -627,6 +628,19 @@
return written;
}
+static ssize_t cifs_file_read(struct file *file, char *user, size_t cnt, loff_t *pos)
+{
+ if( file!=NULL && file->f_dentry!=NULL && CIFS_I(file->f_dentry->d_inode)!=NULL ) {
+ int retval = 0;
+ CIFS_I(file->f_dentry->d_inode)->needForceInvalidate = 1;
+ retval = cifs_revalidate(file->f_dentry);
+ if( retval < 0 )
+ return (ssize_t)retval;
+ }
+
+ return do_sync_read(file,user,cnt,pos);
+}
+
static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
{
/* origin == SEEK_END => we must revalidate the cached file length */
@@ -715,7 +729,7 @@
};
const struct file_operations cifs_file_ops = {
- .read = do_sync_read,
+ .read = cifs_file_read,
.write = do_sync_write,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
.readv = generic_file_readv,
@@ -1057,6 +1071,10 @@
to server still is disconnected since oplock
already released by the server in that case */
if (pTcon->tidStatus != CifsNeedReconnect) {
+ /* PV: disable caching if oplock missed */
+ CIFS_I(inode)->clientCanCacheRead = FALSE;
+ CIFS_I(inode)->clientCanCacheAll = FALSE;
+
rc = CIFSSMBLock(0, pTcon, netfid,
0 /* len */ , 0 /* offset */, 0,
0, LOCKING_ANDX_OPLOCK_RELEASE,
diff -Naur -k-orig150 cifs-orig150/cifsglob.h cifs/cifsglob.h
--- cifs-orig150/cifsglob.h 2007-09-14 14:45:12 +0400
+++ cifs/cifsglob.h 2007-09-14 15:33:30 +0400
@@ -363,6 +363,7 @@
unsigned clientCanCacheRead:1; /* read oplock */
unsigned clientCanCacheAll:1; /* read and writebehind oplock */
unsigned oplockPending:1;
+ unsigned needForceInvalidate:1;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
struct inode vfs_inode;
#endif
@@ -611,6 +612,8 @@
GLOBAL_EXTERN atomic_t midCount;
/* Misc globals */
+GLOBAL_EXTERN unsigned int etersoft_flag; /* if enabled allows extended shared modes in open */
+
GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
to be established on existing mount if we
have the uid/password or Kerberos credential
diff -Naur -k-orig150 cifs-orig150/cifsproto.h cifs/cifsproto.h
--- cifs-orig150/cifsproto.h 2007-09-14 14:45:12 +0400
+++ cifs/cifsproto.h 2007-09-14 15:49:51 +0400
@@ -269,7 +269,7 @@
extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int disposition,
- const int access_flags, const int omode,
+ const int access_flags, const int share_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap);
extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
@@ -377,6 +377,6 @@
extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
-extern void * kzalloc(size_t size, unsigned flgs);
+extern void * kzalloc(size_t size, int flgs);
#endif
#endif /* _CIFSPROTO_H */
diff -Naur -k-orig150 cifs-orig150/cifssmb.c cifs/cifssmb.c
--- cifs-orig150/cifssmb.c 2007-09-14 14:45:12 +0400
+++ cifs/cifssmb.c 2007-09-14 14:55:45 +0400
@@ -1188,6 +1188,11 @@
int name_len;
__u16 count;
+ if (etersoft_flag) {
+ printk("Etersoft: Do not use SMBLegacyOpen!\n");
+ return rc;
+ }
+
OldOpenRetry:
rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
@@ -1292,7 +1297,7 @@
int
CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition,
- const int access_flags, const int create_options, __u16 * netfid,
+ const int access_flags, const int share_flags, const int create_options, __u16 * netfid,
int *pOplock, FILE_ALL_INFO * pfile_info,
const struct nls_table *nls_codepage, int remap)
{
@@ -1351,7 +1356,7 @@
/* Above line causes problems due to vfs splitting create into two
pieces - need to set mode after file created not while it is
being created */
- pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
+ pSMB->ShareAccess = cpu_to_le32(share_flags);
pSMB->CreateDisposition = cpu_to_le32(openDisposition);
pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
/* BB Expirement with various impersonation levels and verify */
diff -Naur -k-orig150 cifs-orig150/connect.c cifs/connect.c
--- cifs-orig150/connect.c 2007-09-14 14:45:12 +0400
+++ cifs/connect.c 2007-09-14 15:43:20 +0400
@@ -40,6 +40,7 @@
#include <linux/kthread.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
+#include <linux/autoconf.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
@@ -837,7 +838,8 @@
if (Local_System_Name[0] != 0)
memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
else {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+//
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
char *nodename = utsname()->nodename;
#else
char *nodename = system_utsname.nodename;
@@ -2412,7 +2414,7 @@
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
32, nls_codepage);
#else
@@ -2444,7 +2446,7 @@
}
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
strcpy(bcc_ptr, utsname()->release);
bcc_ptr += strlen(utsname()->release) + 1;
#else
@@ -2733,7 +2735,7 @@
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
nls_codepage);
#else
@@ -2755,7 +2757,7 @@
} else { /* ASCII */
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
strcpy(bcc_ptr, utsname()->release);
bcc_ptr += strlen(utsname()->release) + 1;
#else
@@ -3142,7 +3144,7 @@
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
nls_codepage);
#else
@@ -3199,7 +3201,7 @@
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
strcpy(bcc_ptr, utsname()->release);
bcc_ptr += strlen(utsname()->release) + 1;
#else
diff -Naur -k-orig150 cifs-orig150/dir.c cifs/dir.c
--- cifs-orig150/dir.c 2007-09-14 14:45:12 +0400
+++ cifs/dir.c 2007-09-14 14:57:05 +0400
@@ -209,7 +209,7 @@
}
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
- desiredAccess, CREATE_NOT_DIR,
+ desiredAccess, FILE_SHARE_ALL, CREATE_NOT_DIR,
&fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
else
@@ -419,6 +419,7 @@
WRITE_OWNER | WRITE_DAC be better? */,
/* Create a file and set the
file attribute to SYSTEM */
+ FILE_SHARE_ALL,
CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
&fileHandle, &oplock, buf,
cifs_sb->local_nls,
diff -Naur -k-orig150 cifs-orig150/fcntl.c cifs/fcntl.c
--- cifs-orig150/fcntl.c 2007-09-14 14:45:12 +0400
+++ cifs/fcntl.c 2007-09-14 14:58:08 +0400
@@ -98,7 +98,7 @@
} else {
cFYI(1, ("dir notify on file %s Arg 0x%lx", full_path, arg));
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
- GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
+ GENERIC_READ | SYNCHRONIZE, FILE_SHARE_ALL, 0 /* create options */,
&netfid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
/* BB fixme - add this handle to a notify handle list */
diff -Naur -k-orig150 cifs-orig150/file.c cifs/file.c
--- cifs-orig150/file.c 2007-09-14 14:45:12 +0400
+++ cifs/file.c 2007-09-14 15:24:22 +0400
@@ -108,6 +108,15 @@
else
return FILE_OPEN;
}
+
+static inline int cifs_get_share_flags(unsigned int flags)
+{
+ if (!etersoft_flag)
+ return FILE_SHARE_ALL;
+ return ((~(flags>>29))&7);
+}
+
+
/* all arguments to this function must be checked for validity in caller */
static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
@@ -221,6 +230,7 @@
struct list_head *tmp;
char *full_path = NULL;
int desiredAccess;
+ int desiredShare;
int disposition;
__u16 netfid;
FILE_ALL_INFO *buf = NULL;
@@ -277,6 +287,7 @@
cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
inode, file->f_flags, full_path));
desiredAccess = cifs_convert_flags(file->f_flags);
+ desiredShare = cifs_get_share_flags(file->f_flags);
/*********************************************************************
* open flag mapping table:
@@ -326,7 +337,7 @@
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
- desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
+ desiredAccess, desiredShare, CREATE_NOT_DIR, &netfid, &oplock, buf,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR);
else
@@ -414,6 +425,7 @@
struct inode *inode;
char *full_path = NULL;
int desiredAccess;
+ int desiredShare;
int disposition = FILE_OPEN;
__u16 netfid;
@@ -489,7 +501,7 @@
cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
inode, file->f_flags, full_path));
- desiredAccess = cifs_convert_flags(file->f_flags);
+ desiredShare = cifs_get_share_flags(file->f_flags);
if (oplockEnabled)
oplock = REQ_OPLOCK;
@@ -502,7 +514,7 @@
and server version of file size can be stale. If we knew for sure
that inode was not dirty locally we could do this */
- rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
+ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, desiredShare,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -877,7 +889,7 @@
mutex_lock(&fid->lock_mutex);
list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
if (pfLock->fl_start <= li->offset &&
- length >= li->length) {
+ pfLock->fl_start+length >= li->offset+li->length) {
stored_rc = CIFSSMBLock(xid, pTcon,
netfid,
li->length, li->offset,
diff -Naur -k-orig150 cifs-orig150/inode.c cifs/inode.c
--- cifs-orig150/inode.c 2007-09-14 14:45:12 +0400
+++ cifs/inode.c 2007-09-14 15:45:41 +0400
@@ -256,7 +256,7 @@
return -EINVAL; /* EOPNOTSUPP? */
}
- rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
+ rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, FILE_SHARE_ALL,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
@@ -665,8 +665,8 @@
int oplock = FALSE;
__u16 netfid;
- rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
- CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
+ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, FILE_SHARE_ALL,
+ CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
&netfid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -708,8 +709,7 @@
/* BB could scan to see if we already have it open
and pass in pid of opener to function */
rc = CIFSSMBOpen(xid, pTcon, full_path,
- FILE_OPEN, SYNCHRONIZE |
- FILE_WRITE_ATTRIBUTES, 0,
+ FILE_OPEN, SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, FILE_SHARE_ALL, 0,
&netfid, &oplock, NULL,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
@@ -736,7 +736,7 @@
__u16 netfid;
rc = CIFSSMBOpen(xid, pTcon, full_path,
- FILE_OPEN, DELETE,
+ FILE_OPEN, DELETE, FILE_SHARE_ALL,
CREATE_NOT_DIR |
CREATE_DELETE_ON_CLOSE,
&netfid, &oplock, NULL,
@@ -1200,7 +1200,7 @@
/* if renaming directory - we should not say CREATE_NOT_DIR,
need to test renaming open directory, also GENERIC_READ
might not right be right access to request */
- rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
+ rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, FILE_SHARE_ALL,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
cifs_sb_source->local_nls,
cifs_sb_source->mnt_cifs_flags &
@@ -1264,7 +1264,7 @@
direntry->d_inode->i_count.counter, direntry,
direntry->d_time, jiffies));
- if (cifsInode->time == 0) {
+ if (cifsInode->time == 0 || cifsInode->needForceInvalidate ) {
/* was set to zero previously to force revalidate */
} else if (time_before(jiffies, cifsInode->time + HZ) &&
lookupCacheEnabled) {
@@ -1306,18 +1306,19 @@
/* if not oplocked, we invalidate inode pages if mtime or file size
had changed on server */
- if (timespec_equal(&local_mtime, &direntry->d_inode->i_mtime) &&
- (local_size == direntry->d_inode->i_size)) {
- cFYI(1, ("cifs_revalidate - inode unchanged"));
+ if (!cifsInode->needForceInvalidate &&
+ timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
+ (local_size == direntry->d_inode->i_size) ) {
+ cFYI(1, ("***************************** cifs_revalidate - inode unchanged"));
} else {
/* file may have changed on server */
if (cifsInode->clientCanCacheRead) {
/* no need to invalidate inode pages since we were the
only ones who could have modified the file and the
server copy is staler than ours */
- } else {
+ } else
invalidate_inode = TRUE;
- }
+
}
/* can not grab this sem since kernel filesys locking documentation
@@ -1336,10 +1337,17 @@
/* if (S_ISDIR(direntry->d_inode->i_mode))
shrink_dcache_parent(direntry); */
if (S_ISREG(direntry->d_inode->i_mode)) {
+ /* (pv): filemap_fdatawait
+ . */
if (direntry->d_inode->i_mapping)
filemap_fdatawait(direntry->d_inode->i_mapping);
+
+ if( cifsInode->needForceInvalidate ) {
+ cFYI(1, ("Force invalidating."));
+ invalidate_remote_inode(direntry->d_inode);
+ cifsInode->needForceInvalidate = 0;
/* may eventually have to do this for open files too */
- if (list_empty(&(cifsInode->openFileList))) {
+ } else if (list_empty(&(cifsInode->openFileList))) {
/* changed on server - flush read ahead pages */
cFYI(1, ("Invalidating read ahead data on "
"closed file"));
@@ -1415,7 +1423,11 @@
goto out_truncate;
do_expand:
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
+#else
+ limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+#endif
if (limit != RLIM_INFINITY && offset > limit) {
spin_unlock(&inode->i_lock);
goto out_sig;
@@ -1665,7 +1677,7 @@
/* BB we could scan to see if we already have it open
and pass in pid of opener to function */
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
- SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
+ SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, FILE_SHARE_ALL,
CREATE_NOT_DIR, &netfid, &oplock,
NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
diff -Naur -k-orig150 cifs-orig150/link.c cifs/link.c
--- cifs-orig150/link.c 2007-09-14 14:45:12 +0400
+++ cifs/link.c 2007-09-14 15:22:17 +0400
@@ -298,7 +298,7 @@
cERROR(1, ("SFU style symlinks not implemented yet"));
/* add open and read as in fs/cifs/inode.c */
} else {
- rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
+ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, FILE_SHARE_ALL,
OPEN_REPARSE_POINT, &fid, &oplock, NULL,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
diff -Naur -k-orig150 cifs-orig150/sess.c cifs/sess.c
--- cifs-orig150/sess.c 2007-09-14 14:45:12 +0400
+++ cifs/sess.c 2007-09-14 15:44:32 +0400
@@ -30,6 +30,7 @@
#include "ntlmssp.h"
#include "nterr.h"
#include <linux/utsname.h>
+#include <linux/autoconf.h>
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);
@@ -118,7 +119,7 @@
bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
nls_cp);
bcc_ptr += 2 * bytes_ret;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release,
32, nls_cp);
#else
@@ -168,7 +169,7 @@
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
strcpy(bcc_ptr, init_utsname()->release);
bcc_ptr += strlen(init_utsname()->release) + 1;
#else
diff -Naur -k-orig150 cifs-orig150/asn1.c cifs/asn1.c
--- cifs-orig150/asn1.c 2007-09-14 14:45:12 +0400
+++ cifs/asn1.c 2007-09-14 15:48:01 +0400
@@ -26,7 +26,7 @@
#include "cifsglob.h"
#include "cifs_debug.h"
#include "cifsproto.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
#include <linux/config.h>
#endif
diff -Naur -k-orig150 cifs-orig150/cifs_debug.c cifs/cifs_debug.c
--- cifs-orig150/cifs_debug.c 2007-09-14 14:45:12 +0400
+++ cifs/cifs_debug.c 2007-09-14 14:49:18 +0400
@@ -460,6 +460,8 @@
static write_proc_t experimEnabled_write;
static read_proc_t linuxExtensionsEnabled_read;
static write_proc_t linuxExtensionsEnabled_write;
+static read_proc_t etersoft_read;
+static write_proc_t etersoft_write;
void
cifs_proc_init(void)
@@ -524,6 +526,12 @@
if (pde)
pde->write_proc = lookupFlag_write;
+ pde =
+ create_proc_read_entry("Etersoft", 0, proc_fs_cifs,
+ etersoft_read, NULL);
+ if (pde)
+ pde->write_proc = etersoft_write;
+
/* pde =
create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
ntlmv2_enabled_read, NULL);
@@ -557,6 +565,7 @@
remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
remove_proc_entry("Experimental", proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
+ remove_proc_entry("Etersoft",proc_fs_cifs);
remove_proc_entry("cifs", proc_root_fs);
}
@@ -910,4 +919,44 @@
/* BB should we turn on MAY flags for other MUST options? */
return count;
}
+
+static int
+etersoft_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = sprintf(page, "%d\n", etersoft_flag);
+
+ len -= off;
+ *start = page + off;
+
+ if (len > count)
+ len = count;
+ else
+ *eof = 1;
+
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+static int
+etersoft_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+ if (c == '0' || c == 'n' || c == 'N')
+ etersoft_flag = 0;
+ else if (c == '1' || c == 'y' || c == 'Y')
+ etersoft_flag = 1;
+
+ return count;
+}
+
#endif
diff -Naur -k-orig150 cifs-orig150/cifsfs.c cifs/cifsfs.c
--- cifs-orig150/cifsfs.c 2007-09-14 14:45:12 +0400
+++ cifs/cifsfs.c 2007-09-14 15:50:36 +0400
@@ -61,6 +61,7 @@
int cifsFYI = 0;
int cifsERROR = 1;
int traceSMB = 0;
+unsigned int etersoft_flag = 1;
unsigned int oplockEnabled = 1;
unsigned int experimEnabled = 0;
unsigned int linuxExtEnabled = 1;
@@ -190,7 +191,7 @@
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
-void * kzalloc(size_t size, unsigned flgs)
++void * kzalloc(size_t size, int flgs)
{
void * buf;
buf = kmalloc(size, flgs);
@@ -627,6 +628,19 @@
return written;
}
+static ssize_t cifs_file_read(struct file *file, char *user, size_t cnt, loff_t *pos)
+{
+ if( file!=NULL && file->f_dentry!=NULL && CIFS_I(file->f_dentry->d_inode)!=NULL ) {
+ int retval = 0;
+ CIFS_I(file->f_dentry->d_inode)->needForceInvalidate = 1;
+ retval = cifs_revalidate(file->f_dentry);
+ if( retval < 0 )
+ return (ssize_t)retval;
+ }
+
+ return do_sync_read(file,user,cnt,pos);
+}
+
static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
{
/* origin == SEEK_END => we must revalidate the cached file length */
@@ -715,7 +729,7 @@
};
const struct file_operations cifs_file_ops = {
- .read = do_sync_read,
+ .read = cifs_file_read,
.write = do_sync_write,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
.readv = generic_file_readv,
@@ -1057,6 +1071,10 @@
to server still is disconnected since oplock
already released by the server in that case */
if (pTcon->tidStatus != CifsNeedReconnect) {
+ /* PV: disable caching if oplock missed */
+ CIFS_I(inode)->clientCanCacheRead = FALSE;
+ CIFS_I(inode)->clientCanCacheAll = FALSE;
+
rc = CIFSSMBLock(0, pTcon, netfid,
0 /* len */ , 0 /* offset */, 0,
0, LOCKING_ANDX_OPLOCK_RELEASE,
diff -Naur -k-orig150 cifs-orig150/cifsglob.h cifs/cifsglob.h
--- cifs-orig150/cifsglob.h 2007-09-14 14:45:12 +0400
+++ cifs/cifsglob.h 2007-09-14 15:33:30 +0400
@@ -363,6 +363,7 @@
unsigned clientCanCacheRead:1; /* read oplock */
unsigned clientCanCacheAll:1; /* read and writebehind oplock */
unsigned oplockPending:1;
+ unsigned needForceInvalidate:1;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
struct inode vfs_inode;
#endif
@@ -611,6 +612,8 @@
GLOBAL_EXTERN atomic_t midCount;
/* Misc globals */
+GLOBAL_EXTERN unsigned int etersoft_flag; /* if enabled allows extended shared modes in open */
+
GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
to be established on existing mount if we
have the uid/password or Kerberos credential
diff -Naur -k-orig150 cifs-orig150/cifsproto.h cifs/cifsproto.h
--- cifs-orig150/cifsproto.h 2007-09-14 14:45:12 +0400
+++ cifs/cifsproto.h 2007-09-14 15:49:51 +0400
@@ -269,7 +269,7 @@
extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int disposition,
- const int access_flags, const int omode,
+ const int access_flags, const int share_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap);
extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
@@ -377,6 +377,6 @@
extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
-extern void * kzalloc(size_t size, unsigned flgs);
+extern void * kzalloc(size_t size, int flgs);
#endif
#endif /* _CIFSPROTO_H */
diff -Naur -k-orig150 cifs-orig150/cifssmb.c cifs/cifssmb.c
--- cifs-orig150/cifssmb.c 2007-09-14 14:45:12 +0400
+++ cifs/cifssmb.c 2007-09-14 14:55:45 +0400
@@ -1188,6 +1188,11 @@
int name_len;
__u16 count;
+ if (etersoft_flag) {
+ printk("Etersoft: Do not use SMBLegacyOpen!\n");
+ return rc;
+ }
+
OldOpenRetry:
rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
@@ -1292,7 +1297,7 @@
int
CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition,
- const int access_flags, const int create_options, __u16 * netfid,
+ const int access_flags, const int share_flags, const int create_options, __u16 * netfid,
int *pOplock, FILE_ALL_INFO * pfile_info,
const struct nls_table *nls_codepage, int remap)
{
@@ -1351,7 +1356,7 @@
/* Above line causes problems due to vfs splitting create into two
pieces - need to set mode after file created not while it is
being created */
- pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
+ pSMB->ShareAccess = cpu_to_le32(share_flags);
pSMB->CreateDisposition = cpu_to_le32(openDisposition);
pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
/* BB Expirement with various impersonation levels and verify */
diff -Naur -k-orig150 cifs-orig150/connect.c cifs/connect.c
--- cifs-orig150/connect.c 2007-09-14 14:45:12 +0400
+++ cifs/connect.c 2007-09-14 15:43:20 +0400
@@ -40,6 +40,7 @@
#include <linux/kthread.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
+#include <linux/autoconf.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
@@ -837,7 +838,8 @@
if (Local_System_Name[0] != 0)
memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
else {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+//
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
char *nodename = utsname()->nodename;
#else
char *nodename = system_utsname.nodename;
@@ -2412,7 +2414,7 @@
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
32, nls_codepage);
#else
@@ -2444,7 +2446,7 @@
}
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
strcpy(bcc_ptr, utsname()->release);
bcc_ptr += strlen(utsname()->release) + 1;
#else
@@ -2733,7 +2735,7 @@
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
nls_codepage);
#else
@@ -2755,7 +2757,7 @@
} else { /* ASCII */
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
strcpy(bcc_ptr, utsname()->release);
bcc_ptr += strlen(utsname()->release) + 1;
#else
@@ -3142,7 +3144,7 @@
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
nls_codepage);
#else
@@ -3199,7 +3201,7 @@
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
strcpy(bcc_ptr, utsname()->release);
bcc_ptr += strlen(utsname()->release) + 1;
#else
diff -Naur -k-orig150 cifs-orig150/dir.c cifs/dir.c
--- cifs-orig150/dir.c 2007-09-14 14:45:12 +0400
+++ cifs/dir.c 2007-09-14 14:57:05 +0400
@@ -209,7 +209,7 @@
}
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
- desiredAccess, CREATE_NOT_DIR,
+ desiredAccess, FILE_SHARE_ALL, CREATE_NOT_DIR,
&fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
else
@@ -419,6 +419,7 @@
WRITE_OWNER | WRITE_DAC be better? */,
/* Create a file and set the
file attribute to SYSTEM */
+ FILE_SHARE_ALL,
CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
&fileHandle, &oplock, buf,
cifs_sb->local_nls,
diff -Naur -k-orig150 cifs-orig150/fcntl.c cifs/fcntl.c
--- cifs-orig150/fcntl.c 2007-09-14 14:45:12 +0400
+++ cifs/fcntl.c 2007-09-14 14:58:08 +0400
@@ -98,7 +98,7 @@
} else {
cFYI(1, ("dir notify on file %s Arg 0x%lx", full_path, arg));
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
- GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
+ GENERIC_READ | SYNCHRONIZE, FILE_SHARE_ALL, 0 /* create options */,
&netfid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
/* BB fixme - add this handle to a notify handle list */
diff -Naur -k-orig150 cifs-orig150/file.c cifs/file.c
--- cifs-orig150/file.c 2007-09-14 14:45:12 +0400
+++ cifs/file.c 2007-09-14 15:24:22 +0400
@@ -108,6 +108,15 @@
else
return FILE_OPEN;
}
+
+static inline int cifs_get_share_flags(unsigned int flags)
+{
+ if (!etersoft_flag)
+ return FILE_SHARE_ALL;
+ return ((~(flags>>29))&7);
+}
+
+
/* all arguments to this function must be checked for validity in caller */
static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
@@ -221,6 +230,7 @@
struct list_head *tmp;
char *full_path = NULL;
int desiredAccess;
+ int desiredShare;
int disposition;
__u16 netfid;
FILE_ALL_INFO *buf = NULL;
@@ -277,6 +287,7 @@
cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
inode, file->f_flags, full_path));
desiredAccess = cifs_convert_flags(file->f_flags);
+ desiredShare = cifs_get_share_flags(file->f_flags);
/*********************************************************************
* open flag mapping table:
@@ -326,7 +337,7 @@
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
- desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
+ desiredAccess, desiredShare, CREATE_NOT_DIR, &netfid, &oplock, buf,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR);
else
@@ -414,6 +425,7 @@
struct inode *inode;
char *full_path = NULL;
int desiredAccess;
+ int desiredShare;
int disposition = FILE_OPEN;
__u16 netfid;
@@ -489,7 +501,8 @@
cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
inode, file->f_flags, full_path));
desiredAccess = cifs_convert_flags(file->f_flags);
+ desiredShare = cifs_get_share_flags(file->f_flags);
if (oplockEnabled)
oplock = REQ_OPLOCK;
@@ -502,7 +514,7 @@
and server version of file size can be stale. If we knew for sure
that inode was not dirty locally we could do this */
- rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
+ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, desiredShare,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
diff -Naur -k-orig150 cifs-orig150/inode.c cifs/inode.c
--- cifs-orig150/inode.c 2007-09-14 14:45:12 +0400
+++ cifs/inode.c 2007-09-14 15:45:41 +0400
@@ -256,7 +256,7 @@
return -EINVAL; /* EOPNOTSUPP? */
}
- rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
+ rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, FILE_SHARE_ALL,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
@@ -665,8 +665,8 @@
int oplock = FALSE;
__u16 netfid;
- rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
- CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
+ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, FILE_SHARE_ALL,
+ CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
&netfid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -708,8 +709,7 @@
/* BB could scan to see if we already have it open
and pass in pid of opener to function */
rc = CIFSSMBOpen(xid, pTcon, full_path,
- FILE_OPEN, SYNCHRONIZE |
- FILE_WRITE_ATTRIBUTES, 0,
+ FILE_OPEN, SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, FILE_SHARE_ALL, 0,
&netfid, &oplock, NULL,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
@@ -736,7 +736,7 @@
__u16 netfid;
rc = CIFSSMBOpen(xid, pTcon, full_path,
- FILE_OPEN, DELETE,
+ FILE_OPEN, DELETE, FILE_SHARE_ALL,
CREATE_NOT_DIR |
CREATE_DELETE_ON_CLOSE,
&netfid, &oplock, NULL,
@@ -1200,7 +1200,7 @@
/* if renaming directory - we should not say CREATE_NOT_DIR,
need to test renaming open directory, also GENERIC_READ
might not right be right access to request */
- rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
+ rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, FILE_SHARE_ALL,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
cifs_sb_source->local_nls,
cifs_sb_source->mnt_cifs_flags &
@@ -1264,7 +1264,7 @@
direntry->d_inode->i_count.counter, direntry,
direntry->d_time, jiffies));
- if (cifsInode->time == 0) {
+ if (cifsInode->time == 0 || cifsInode->needForceInvalidate ) {
/* was set to zero previously to force revalidate */
} else if (time_before(jiffies, cifsInode->time + HZ) &&
lookupCacheEnabled) {
@@ -1306,18 +1306,19 @@
/* if not oplocked, we invalidate inode pages if mtime or file size
had changed on server */
- if (timespec_equal(&local_mtime, &direntry->d_inode->i_mtime) &&
- (local_size == direntry->d_inode->i_size)) {
- cFYI(1, ("cifs_revalidate - inode unchanged"));
+ if (!cifsInode->needForceInvalidate &&
+ timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
+ (local_size == direntry->d_inode->i_size) ) {
+ cFYI(1, ("***************************** cifs_revalidate - inode unchanged"));
} else {
/* file may have changed on server */
if (cifsInode->clientCanCacheRead) {
/* no need to invalidate inode pages since we were the
only ones who could have modified the file and the
server copy is staler than ours */
- } else {
+ } else
invalidate_inode = TRUE;
- }
+
}
/* can not grab this sem since kernel filesys locking documentation
@@ -1336,10 +1337,17 @@
/* if (S_ISDIR(direntry->d_inode->i_mode))
shrink_dcache_parent(direntry); */
if (S_ISREG(direntry->d_inode->i_mode)) {
+ /* (pv): filemap_fdatawait
+ . */
if (direntry->d_inode->i_mapping)
filemap_fdatawait(direntry->d_inode->i_mapping);
+
+ if( cifsInode->needForceInvalidate ) {
+ cFYI(1, ("Force invalidating."));
+ invalidate_remote_inode(direntry->d_inode);
+ cifsInode->needForceInvalidate = 0;
/* may eventually have to do this for open files too */
- if (list_empty(&(cifsInode->openFileList))) {
+ } else if (list_empty(&(cifsInode->openFileList))) {
/* changed on server - flush read ahead pages */
cFYI(1, ("Invalidating read ahead data on "
"closed file"));
@@ -1665,7 +1677,7 @@
/* BB we could scan to see if we already have it open
and pass in pid of opener to function */
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
- SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
+ SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, FILE_SHARE_ALL,
CREATE_NOT_DIR, &netfid, &oplock,
NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
diff -Naur -k-orig150 cifs-orig150/link.c cifs/link.c
--- cifs-orig150/link.c 2007-09-14 14:45:12 +0400
+++ cifs/link.c 2007-09-14 15:22:17 +0400
@@ -298,7 +298,7 @@
cERROR(1, ("SFU style symlinks not implemented yet"));
/* add open and read as in fs/cifs/inode.c */
} else {
- rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
+ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, FILE_SHARE_ALL,
OPEN_REPARSE_POINT, &fid, &oplock, NULL,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
diff -Naur -k-orig150 cifs-orig150/sess.c cifs/sess.c
--- cifs-orig150/sess.c 2007-09-14 14:45:12 +0400
+++ cifs/sess.c 2007-09-14 15:44:32 +0400
@@ -30,6 +30,7 @@
#include "ntlmssp.h"
#include "nterr.h"
#include <linux/utsname.h>
+#include <linux/autoconf.h>
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);
@@ -118,7 +119,7 @@
bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
nls_cp);
bcc_ptr += 2 * bytes_ret;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release,
32, nls_cp);
#else
@@ -168,7 +169,7 @@
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) || defined CONFIG_VE
strcpy(bcc_ptr, init_utsname()->release);
bcc_ptr += strlen(init_utsname()->release) + 1;
#else
--- cifs/cifsfs.c.orig 2007-12-28 22:06:19 +0300
+++ cifs/cifsfs.c 2007-12-28 23:13:36 +0300
@@ -201,7 +201,8 @@ cifs_put_super(struct super_block *sb)
}
#endif
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)
+/* Hack for too updated SUSE kernel 2.6.16.46 */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)) || defined (CONFIG_SLE_SP)
static int
cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
# against warning
diff -up new-cifs-backport.old/connect.c new-cifs-backport/connect.c
--- new-cifs-backport.old/connect.c 2007-12-21 23:16:18 +0300
+++ new-cifs-backport/connect.c 2007-12-21 23:18:33 +0300
@@ -1832,16 +1832,17 @@ void reset_cifs_unix_caps(int xid, struc
cFYI(1, ("very large write cap"));
#endif /* CIFS_DEBUG2 */
if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
- if (vol_info == NULL)
+ if (vol_info == NULL) {
cFYI(1, ("resetting capabilities failed"));
- else
+ }
+ else {
cERROR(1, ("Negotiating Unix capabilities "
"with the server failed. Consider "
"mounting with the Unix Extensions\n"
"disabled, if problems are found, "
"by specifying the nounix mount "
"option."));
-
+ }
}
}
}
# use independent module name
--- new-cifs-backport/Makefile.orig 2007-07-14 09:27:36 +0400
+++ new-cifs-backport/Makefile 2008-01-27 18:39:37 +0300
@@ -1,6 +1,6 @@
#
# Makefile for Linux CIFS VFS client
#
-obj-$(CONFIG_CIFS) += cifs.o
+obj-$(CONFIG_CIFS) += etercifs.o
-cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o export.o
+etercifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o export.o
# change name due backport to 2.6.18 some newest functions
/usr/src/kernels/2.6.18-53.1.6.el5-PAE-i686
/home/lav/RPM/BUILD/linux-cifs-1.50c/new-cifs-backport/inode.c:46: : redefinition of inc_nlink
include/linux/fs.h:1203: : previous definition of inc_nlink was here
--- new-cifs-backport/inode.c.orig 2008-01-27 18:38:40 +0300
+++ new-cifs-backport/inode.c 2008-01-31 13:48:00 +0300
@@ -41,12 +41,12 @@ static inline void drop_nlink(struct ino
{
inode->i_nlink--;
}
+#endif
-static inline void inc_nlink(struct inode *inode)
+static inline void fc8_inc_nlink(struct inode *inode)
{
inode->i_nlink++;
}
-#endif
int cifs_get_inode_info_unix(struct inode **pinode,
@@ -958,7 +958,7 @@ int cifs_mkdir(struct inode *inode, stru
}
/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
to set uid/gid */
- inc_nlink(inode);
+ fc8_inc_nlink(inode);
if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops;
else
@@ -1008,7 +1008,7 @@ mkdir_retry_old:
d_drop(direntry);
} else {
mkdir_get_info:
- inc_nlink(inode);
+ fc8_inc_nlink(inode);
if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb, xid);
#!/bin/sh #!/bin/sh
# Author: Vitaly Lipatov <lav@etersoft.ru> # Author: Vitaly Lipatov <lav@etersoft.ru>
# 2006, 2007 Public domain # 2006, 2007, 2008 Public domain
# Multiplatform init script # Multiplatform init script
# linux-cifs - CIFS support for Linux kernel # linux-cifs - CIFS support for Linux kernel
# #
...@@ -9,14 +9,15 @@ ...@@ -9,14 +9,15 @@
# #
# modulename: cifs # modulename: cifs
# #
RMMOD=/sbin/rmmod
MODPROBE=/sbin/modprobe
INSMOD=/sbin/insmod
MODULENAME=cifs ORIGMODULENAME=cifs
MODULENAME=etercifs
# current module or manually built # current module or manually built
DEFMODULEPATH=/lib/modules/linux-cifs/$(uname -r)/$MODULENAME.ko #MODULEPATH=`echo /lib/modules/$(uname -r)/kernel/fs/cifs/$MODULENAME.*`
MANMODULEPATH=/lib/modules/linux-cifs/$MODULENAME.ko
# use manually build if exists
[ -r "$MANMODULEPATH" ] && DEFMODULEPATH=$MANMODULEPATH
OUTFORMAT=/etc/init.d/outformat OUTFORMAT=/etc/init.d/outformat
[ -x $OUTFORMAT ] || OUTFORMAT=/etc/init.d/linux-cifs.outformat [ -x $OUTFORMAT ] || OUTFORMAT=/etc/init.d/linux-cifs.outformat
...@@ -71,6 +72,7 @@ get_pid() ...@@ -71,6 +72,7 @@ get_pid()
else else
dpid="$(ps axh | grep $1 | grep -v grep | sed -e 's/ *\(.*\)/\1/' -e 's/ \+/ /g' | grep -v " /bin/sh " | grep -v "^$$ " | cut -f1 -d\ | head -1)" dpid="$(ps axh | grep $1 | grep -v grep | sed -e 's/ *\(.*\)/\1/' -e 's/ \+/ /g' | grep -v " /bin/sh " | grep -v "^$$ " | cut -f1 -d\ | head -1)"
fi fi
return $dpid
} }
is_loaded() is_loaded()
...@@ -81,7 +83,12 @@ is_loaded() ...@@ -81,7 +83,12 @@ is_loaded()
is_moduled() is_moduled()
{ {
lsmod | grep $MODULENAME > /dev/null lsmod | grep "^$MODULENAME" > /dev/null
}
is_origmoduled()
{
lsmod | grep "^$ORIGMODULENAME" > /dev/null
} }
umount_cifs() umount_cifs()
...@@ -91,34 +98,37 @@ umount_cifs() ...@@ -91,34 +98,37 @@ umount_cifs()
WASCIFS=1 WASCIFS=1
fi fi
echo -n "Unmounting CIFS resources... " echo -n "Unmounting CIFS resources... "
umount -t cifs -a || { failure ; return ; } umount -t cifs -a || { failure ; return 1; }
success
} }
mount_cifs() mount_cifs()
{ {
echo -n "Mounting CIFS resources... " echo -n "Mounting CIFS resources... "
mount -t cifs -a || { failure ; return ; } mount -t cifs -a || { failure ; return 1; }
success
} }
load_module() load_module()
{ {
local i local i
if is_moduled ; then if is_origmoduled ; then
#test -r /proc/fs/cifs/Etersoft && { passed ; return ; } #test -r /proc/fs/cifs/Etersoft && { passed ; return ; }
umount_cifs umount_cifs
echo -n "Removing CIFS kernel module... " echo -n "Removing CIFS kernel module... "
rmmod $MODULENAME || { failure ; return ; } $RMMOD $ORIGMODULENAME || { failure ; return ; }
fi fi
# Preload module dependencies # Preload module dependencies
modprobe nls_base 2>/dev/null #$MODPROBE nls_base 2>/dev/null
# kernel depends # kernel depends
# || { echo -n "nls_base is not loaded" ; failure ; } # || { echo -n "nls_base is not loaded" ; failure ; }
echo -n "Loading CIFS kernel module... " echo -n "Loading CIFS kernel module... "
if [ -r "$DEFMODULEPATH" ] ; then $MODPROBE $MODULENAME && { success ; return ; }
insmod $DEFMODULEPATH && { echo ; echo -n " insmod $DEFMODULEPATH" ; success ; return ; } #if [ -r "$MODULEPATH" ] ; then
echo -n "Incorrect module. Your system: " ; uname -a ; dmesg | tail -n2 # $INSMOD $MODULEPATH && { echo ; echo -n " insmod $MODULEPATH" ; success ; return ; }
fi # echo -n "Incorrect module. Your system: " ; uname -a ; dmesg | tail -n2
#fi
echo -n "$MODULENAME from Etersoft is not found," echo -n "$MODULENAME from Etersoft is not found,"
echo -n "you can try compile it with 'service linux-cifs build' command." echo -n "you can try compile it with 'service linux-cifs build' command."
failure failure
...@@ -133,7 +143,7 @@ start() ...@@ -133,7 +143,7 @@ start()
echo 1 > /proc/fs/cifs/Etersoft && success || failure echo 1 > /proc/fs/cifs/Etersoft && success || failure
echo -n "Disable Linux extensions for CIFS..." echo -n "Disable Linux extensions for CIFS..."
echo 0 > /proc/fs/cifs/LinuxExtensionsEnabled && success || failure echo 0 > /proc/fs/cifs/LinuxExtensionsEnabled && success || failure
test -n "$WASCIFS" && mount_cifs test -n "$WASCIFS" && mount_cifs || :
else else
failure failure
fi fi
...@@ -141,10 +151,10 @@ start() ...@@ -141,10 +151,10 @@ start()
stop() stop()
{ {
echo -n "Unloading CIFS kernel module... "
umount_cifs umount_cifs
echo -n "Unloading CIFS kernel module... "
is_moduled || { passed ; return ; } is_moduled || { passed ; return ; }
rmmod $MODULENAME || { failure ; echo "You have to umount all CIFS resources."; return ; } $RMMOD $MODULENAME || { failure ; echo "You have to umount all CIFS resources."; return ; }
success success
} }
...@@ -159,6 +169,9 @@ status() ...@@ -159,6 +169,9 @@ status()
#else #else
# PRECOMP="precompiled" # PRECOMP="precompiled"
#fi #fi
if is_origmoduled ; then
echo " origin kernel module $ORIGMODULENAME loaded, Etersoft extensions missed"
fi
if is_moduled ; then if is_moduled ; then
#echo " kernel module $MODULENAME is loaded ($PRECOMP)" #echo " kernel module $MODULENAME is loaded ($PRECOMP)"
test -d /proc/fs/cifs/ 2>/dev/null || { echo -n "Can't locale /proc/fs/cifs... " ; failure ; } test -d /proc/fs/cifs/ 2>/dev/null || { echo -n "Can't locale /proc/fs/cifs... " ; failure ; }
...@@ -168,7 +181,20 @@ status() ...@@ -168,7 +181,20 @@ status()
echo -n "Unix extensions for CIFS disabled..." echo -n "Unix extensions for CIFS disabled..."
test "`cat /proc/fs/cifs/LinuxExtensionsEnabled 2>/dev/null`" = "1" && failure || success test "`cat /proc/fs/cifs/LinuxExtensionsEnabled 2>/dev/null`" = "1" && failure || success
else else
echo " kernel module $MODULENAME is not loaded ($PRECOMP)" echo " kernel module $MODULENAME is not loaded"
fi
}
build_module()
{
#DKMS=/sbin/dkms
# && [ -x $DKMS ]
# Need name-version for it
if [ -r @SRC_DIR/dkms.conf ] ; then
echo "TODO: use dkms build/install for build"
else
cd @SRC_DIR@
sh buildmodule.sh
fi fi
} }
...@@ -184,15 +210,14 @@ case "$1" in ...@@ -184,15 +210,14 @@ case "$1" in
start start
;; ;;
build) build)
cd /usr/src/linux-cifs build_module
sh buildmodule.sh
;; ;;
status) status)
status status
;; ;;
condrestart) condrestart)
# remove manual built module # remove manual built module
rm -f $MANMODULEPATH # rm -f $MANMODULEPATH
if [ "`cat /proc/fs/cifs/Etersoft 2>/dev/null`" = "1" ] ; then if [ "`cat /proc/fs/cifs/Etersoft 2>/dev/null`" = "1" ] ; then
stop stop
start start
...@@ -201,6 +226,6 @@ case "$1" in ...@@ -201,6 +226,6 @@ case "$1" in
fi fi
;; ;;
*) *)
echo "Usage: linux-cifs {start|stop|restart|condrestart|condstop|status}" echo "Usage: linux-cifs {start|stop|restart|build|condrestart|condstop|status}"
esac esac
...@@ -18,17 +18,19 @@ update_from_cvs ...@@ -18,17 +18,19 @@ update_from_cvs
SPECNAME=linux-cifs.spec SPECNAME=linux-cifs.spec
prepare_tarball prepare_tarball
echo "build_srpm"
build_rpms_name $SPECNAME build_rpms_name $SPECNAME
test -z "$BASENAME" && fatal "BASENAME is empty" test -z "$BASENAME" && fatal "BASENAME is empty"
#NAMEVER=$BASENAME-$VERSION #NAMEVER=$BASENAME-$VERSION
#rpmbb $SPECNAME || fatal "Can't build" #rpmbb $SPECNAME || fatal "Can't build"
if [ -n "$WINEPUB_PATH" -a $USER = "lav" ] ; then if [ -n "$WINEPUB_PATH" ] ; then
#-a $USER = "lav" ] ; then
# Path to local publishing # Path to local publishing
ETERDESTSRPM=$WINEPUB_PATH/sources ETERDESTSRPM=$WINEPUB_PATH/sources
cp -f $RPMSOURCEDIR/$TARNAME $ETERDESTSRPM/tarball/ cp -f $RPMSOURCEDIR/$TARNAME $ETERDESTSRPM/tarball/
echo "publish_srpm"
publish_srpm publish_srpm
fi fi
...@@ -43,3 +45,20 @@ fi ...@@ -43,3 +45,20 @@ fi
#cd gentoo #cd gentoo
#./release_port.sh #./release_port.sh
#cd - #cd -
SPECNAME=dkms-linux-cifs.spec
prepare_tarball
echo "build_srpm"
build_rpms_name $SPECNAME
test -z "$BASENAME" && fatal "BASENAME is empty"
if [ -n "$WINEPUB_PATH" ] ; then
# Path to local publishing
ETERDESTSRPM=$WINEPUB_PATH/sources
cp -f $RPMSOURCEDIR/$TARNAME $ETERDESTSRPM/tarball/
echo "publish_srpm"
publish_srpm
fi
# Etersoft (c) 2007 # Etersoft (c) 2007, 2008
# Multiplatform spec for autobuild system # Multiplatform spec for autobuild system
# in kernel build dir you can have gcc_version.inc file with export GCC_VERSION=x.xx # in kernel build dir you can have gcc_version.inc file with export GCC_VERSION=x.xx
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
# kernel-source-XXXX for Slackware / MOPSLinux # kernel-source-XXXX for Slackware / MOPSLinux
Name: linux-cifs Name: linux-cifs
Version: 1.48a Version: 1.50c
%define relnum 7 Release: alt4
Summary: Advanced Common Internet File System for Linux with Etersoft extension Summary: Advanced Common Internet File System for Linux with Etersoft extension
...@@ -26,27 +26,19 @@ Url: http://linux-cifs.samba.org/ ...@@ -26,27 +26,19 @@ Url: http://linux-cifs.samba.org/
Source: ftp://updates.etersoft.ru/pub/Etersoft/WINE@Etersoft/sources/tarball/%name-%version.tar.bz2 Source: ftp://updates.etersoft.ru/pub/Etersoft/WINE@Etersoft/sources/tarball/%name-%version.tar.bz2
Source1: http://pserver.samba.org/samba/ftp/cifs-cvs/cifs-%version.tar.bz2 Source1: http://pserver.samba.org/samba/ftp/cifs-cvs/cifs-%version.tar.bz2
BuildRequires: rpm-build-compat >= 0.97
# Spec part for ALT Linux # Spec part for ALT Linux
%if %_vendor == "alt" %if %_vendor == "alt"
Release: alt%relnum
BuildRequires: rpm-build-compat >= 0.7
BuildRequires: kernel-build-tools BuildRequires: kernel-build-tools
BuildRequires: kernel-headers-modules-std-smp kernel-headers-modules-wks-smp kernel-headers-modules-ovz-smp BuildRequires: kernel-headers-modules-std-smp kernel-headers-modules-wks-smp kernel-headers-modules-ovz-smp
# do not work?
%ifarch x86_64 %ifarch x86_64
# Don't know if ifnarch exist # Don't know if ifnarch exist
BuildRequires: kernel-headers-modules-std-smp BuildRequires: kernel-headers-modules-std-smp
%else %else
BuildRequires: kernel-headers-modules-std-pae BuildRequires: kernel-headers-modules-std-pae
%endif %endif
%else
Release: eter%relnum%_vendor
BuildRequires: rpm-build-altlinux-compat >= 0.7
%endif
# FIXME: ifndef broken in Ubuntu
#ifndef buildroot
%if %{undefined buildroot}
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
%endif %endif
%if %_vendor == "suse" %if %_vendor == "suse"
...@@ -82,32 +74,56 @@ though. ...@@ -82,32 +74,56 @@ though.
This package has Etersoft's patches for WINE@Etersoft sharing access support. This package has Etersoft's patches for WINE@Etersoft sharing access support.
#cifs-bld-tmp/fs/cifs
%define intdir new-cifs-backport
%prep %prep
%setup -q %setup -q
tar xfj %SOURCE1 tar xfj %SOURCE1
patch -s -p1 -d cifs-bld-tmp/fs/cifs <%name-shared.patch patch -s -p1 -d %intdir <%name-shared-%version.patch
%install %install
#export KBUILD_VERBOSE=1 #export KBUILD_VERBOSE=1
MAN_DIR=%buildroot%_mandir/ INIT_DIR=%buildroot%_initdir/ SBIN_DIR=%buildroot%_sbindir/ INSTALL_MOD_PATH=%buildroot%module_dir ./build.sh MAN_DIR=%buildroot%_mandir/ INIT_DIR=%buildroot%_initdir/ SBIN_DIR=%buildroot%_sbindir/ \
INSTALL_MOD_PATH=%buildroot/lib/modules BUILDDIR=`pwd`/%intdir \
DESTDIR=%buildroot SRC_DIR=%_usrsrc/%name-%version ./build.sh
# Debian, Suse, Slackware do not have command service
# start service if first time install
%post %post
%post_service %name %post_service %name
[ "$1" = "1" ] && %_initdir/%name start || : %start_service %name
%preun %preun
%preun_service %name %preun_service %name
%files %files
%defattr(-,root,root)
%_initdir/%name %_initdir/%name
%_initdir/%name.outformat %_initdir/%name.outformat
%module_dir/ /lib/modules/*
/usr/src/%name/ %_usrsrc/%name-%version/
%changelog %changelog
* Thu Jan 31 2008 Vitaly Lipatov <lav@altlinux.ru> 1.50c-alt4
- fix build on Fedora 8 (2.6.18-53)
* Sun Jan 27 2008 Vitaly Lipatov <lav@altlinux.ru> 1.50c-alt3
- move modules placement
- move src files to name-version for dkms compatibility
- change module name to etercifs.ko
* Fri Dec 28 2007 Vitaly Lipatov <lav@altlinux.ru> 1.50c-alt2
- add fix for SLED10 kernel 2.6.16.46
- fix warnings, add missed access setting in reopen file func
* Tue Nov 06 2007 Vitaly Lipatov <lav@altlinux.ru> 1.50c-alt1
- update version
- fix spec according to Korinf build system
* Fri Oct 12 2007 Vitaly Lipatov <lav@altlinux.ru> 1.50-alt1
- update version
* Fri Sep 14 2007 Sergey Lebedev <barabashka@altlinux.ru> 1.50-alt0
- new version cifs 1.50
* Fri Jul 27 2007 Vitaly Lipatov <lav@altlinux.ru> 1.48a-alt7 * Fri Jul 27 2007 Vitaly Lipatov <lav@altlinux.ru> 1.48a-alt7
- fix build on 2.6.22 kernels - fix build on 2.6.22 kernels
- fix scripts for Debian/Ubuntu - fix scripts for Debian/Ubuntu
......
Verison 1.48 Version 1.50
------------
Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is
done with "serverino" mount option). Add support for POSIX Unlink
(helps with certain sharing violation cases when server such as
Samba supports newer POSIX CIFS Protocol Extensions). Add "nounix"
mount option to allow disabling the CIFS Unix Extensions for just
that mount. Fix hang on spinlock in find_writable_file (race when
reopening file after session crash). Byte range unlock request to
windows server could unlock more bytes (on server copy of file)
than intended if start of unlock request is well before start of
a previous byte range lock that we issued.
Version 1.49
------------
IPv6 support. Enable ipv6 addresses to be passed on mount (put the ipv6
address after the "ip=" mount option, at least until mount.cifs is fixed to
handle DNS host to ipv6 name translation). Accept override of uid or gid
on mount even when Unix Extensions are negotiated (it used to be ignored
when Unix Extensions were ignored). This allows users to override the
default uid and gid for files when they are certain that the uids or
gids on the server do not match those of the client. Make "sec=none"
mount override username (so that null user connection is attempted)
to match what documentation said. Support for very large reads, over 127K,
available to some newer servers (such as Samba 3.0.26 and later but
note that it also requires setting CIFSMaxBufSize at module install
time to a larger value which may hurt performance in some cases).
Make sign option force signing (or fail if server does not support it).
Version 1.48
------------ ------------
Fix mtime bouncing around from local idea of last write times to remote time. Fix mtime bouncing around from local idea of last write times to remote time.
Fix hang (in i_size_read) when simultaneous size update of same remote file Fix hang (in i_size_read) when simultaneous size update of same remote file
...@@ -9,7 +38,13 @@ from read-only back to read-write, reflect this change in default file mode ...@@ -9,7 +38,13 @@ from read-only back to read-write, reflect this change in default file mode
(we had been leaving a file's mode read-only until the inode were reloaded). (we had been leaving a file's mode read-only until the inode were reloaded).
Allow setting of attribute back to ATTR_NORMAL (removing readonly dos attribute Allow setting of attribute back to ATTR_NORMAL (removing readonly dos attribute
when archive dos attribute not set and we are changing mode back to writeable when archive dos attribute not set and we are changing mode back to writeable
on server which does not support the Unix Extensions). on server which does not support the Unix Extensions). Remove read only dos
attribute on chmod when adding any write permission (ie on any of
user/group/other (not all of user/group/other ie 0222) when
mounted to windows. Add support for POSIX MkDir (slight performance
enhancement and eliminates the network race between the mkdir and set
path info of the mode).
Version 1.47 Version 1.47
------------ ------------
...@@ -17,7 +52,12 @@ Fix oops in list_del during mount caused by unaligned string. ...@@ -17,7 +52,12 @@ Fix oops in list_del during mount caused by unaligned string.
Fix file corruption which could occur on some large file Fix file corruption which could occur on some large file
copies caused by writepages page i/o completion bug. copies caused by writepages page i/o completion bug.
Seek to SEEK_END forces check for update of file size for non-cached Seek to SEEK_END forces check for update of file size for non-cached
files. files. Allow file size to be updated on remote extend of locally open,
non-cached file. Fix reconnect to newer Samba servers (or other servers
which support the CIFS Unix/POSIX extensions) so that we again tell the
server the Unix/POSIX cifs capabilities which we support (SetFSInfo).
Add experimental support for new POSIX Open/Mkdir (which returns
stat information on the open, and allows setting the mode).
Version 1.46 Version 1.46
------------ ------------
...@@ -246,7 +286,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call. ...@@ -246,7 +286,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call.
Version 1.25 Version 1.25
------------ ------------
Fix internationalization problem in cifs readdir with filenames that map to Fix internationalization problem in cifs readdir with filenames that map to
longer UTF8 strings than the string on the wire was in Unicode. Add workaround longer UTF-8 strings than the string on the wire was in Unicode. Add workaround
for readdir to netapp servers. Fix search rewind (seek into readdir to return for readdir to netapp servers. Fix search rewind (seek into readdir to return
non-consecutive entries). Do not do readdir when server negotiates non-consecutive entries). Do not do readdir when server negotiates
buffer size to small to fit filename. Add support for reading POSIX ACLs from buffer size to small to fit filename. Add support for reading POSIX ACLs from
......
...@@ -257,19 +257,25 @@ A partial list of the supported mount options follows: ...@@ -257,19 +257,25 @@ A partial list of the supported mount options follows:
mount. mount.
domain Set the SMB/CIFS workgroup name prepended to the domain Set the SMB/CIFS workgroup name prepended to the
username during CIFS session establishment username during CIFS session establishment
uid If CIFS Unix extensions are not supported by the server uid Set the default uid for inodes. For mounts to servers
this overrides the default uid for inodes. For mounts to which do support the CIFS Unix extensions, such as a
servers which do support the CIFS Unix extensions, such properly configured Samba server, the server provides
as a properly configured Samba server, the server provides the uid, gid and mode so this parameter should not be
the uid, gid and mode. For servers which do not support specified unless the server and clients uid and gid
the Unix extensions, the default uid (and gid) returned on numbering differ. If the server and client are in the
lookup of existing files is the uid (gid) of the person same domain (e.g. running winbind or nss_ldap) and
the server supports the Unix Extensions then the uid
and gid can be retrieved from the server (and uid
and gid would not have to be specifed on the mount.
For servers which do not support the CIFS Unix
extensions, the default uid (and gid) returned on lookup
of existing files will be the uid (gid) of the person
who executed the mount (root, except when mount.cifs who executed the mount (root, except when mount.cifs
is configured setuid for user mounts) unless the "uid=" is configured setuid for user mounts) unless the "uid="
(gid) mount option is specified. For the uid (gid) of newly (gid) mount option is specified. For the uid (gid) of newly
created files and directories, ie files created since created files and directories, ie files created since
the last mount of the server share, the expected uid the last mount of the server share, the expected uid
(gid) is cached as as long as the inode remains in (gid) is cached as long as the inode remains in
memory on the client. Also note that permission memory on the client. Also note that permission
checks (authorization checks) on accesses to a file occur checks (authorization checks) on accesses to a file occur
at the server, but there are cases in which an administrator at the server, but there are cases in which an administrator
...@@ -281,8 +287,7 @@ A partial list of the supported mount options follows: ...@@ -281,8 +287,7 @@ A partial list of the supported mount options follows:
the client. Note that the mount.cifs helper must be the client. Note that the mount.cifs helper must be
at version 1.10 or higher to support specifying the uid at version 1.10 or higher to support specifying the uid
(or gid) in non-numberic form. (or gid) in non-numberic form.
gid If CIFS Unix extensions are not supported by the server gid Set the default gid for inodes (similar to above).
this overrides the default gid for inodes.
file_mode If CIFS Unix extensions are not supported by the server file_mode If CIFS Unix extensions are not supported by the server
this overrides the default mode for file inodes. this overrides the default mode for file inodes.
dir_mode If CIFS Unix extensions are not supported by the server dir_mode If CIFS Unix extensions are not supported by the server
...@@ -296,10 +301,21 @@ A partial list of the supported mount options follows: ...@@ -296,10 +301,21 @@ A partial list of the supported mount options follows:
during the local client kernel build will be used. during the local client kernel build will be used.
If server does not support Unicode, this parameter is If server does not support Unicode, this parameter is
unused. unused.
rsize default read size (usually 16K) rsize default read size (usually 16K). The client currently
wsize default write size (usually 16K, 32K is often better over GigE) can not use rsize larger than CIFSMaxBufSize. CIFSMaxBufSize
maximum wsize currently allowed by CIFS is 57344 (14 4096 byte defaults to 16K and may be changed (from 8K to the maximum
pages) kmalloc size allowed by your kernel) at module install time
for cifs.ko. Setting CIFSMaxBufSize to a very large value
will cause cifs to use more memory and may reduce performance
in some cases. To use rsize greater than 127K (the original
cifs protocol maximum) also requires that the server support
a new Unix Capability flag (for very large read) which some
newer servers (e.g. Samba 3.0.26 or later) do. rsize can be
set from a minimum of 2048 to a maximum of 130048 (127K or
CIFSMaxBufSize, whichever is smaller)
wsize default write size (default 57344)
maximum wsize currently allowed by CIFS is 57344 (fourteen
4096 byte pages)
rw mount the network share read-write (note that the rw mount the network share read-write (note that the
server may still consider the share read-only) server may still consider the share read-only)
ro mount network share read-only ro mount network share read-only
...@@ -354,7 +370,7 @@ A partial list of the supported mount options follows: ...@@ -354,7 +370,7 @@ A partial list of the supported mount options follows:
Note that this does not affect the normal ACL check on the Note that this does not affect the normal ACL check on the
target machine done by the server software (of the server target machine done by the server software (of the server
ACL against the user name provided at mount time). ACL against the user name provided at mount time).
serverino Use servers inode numbers instead of generating automatically serverino Use server's inode numbers instead of generating automatically
incrementing inode numbers on the client. Although this will incrementing inode numbers on the client. Although this will
make it easier to spot hardlinked files (as they will have make it easier to spot hardlinked files (as they will have
the same inode numbers) and inode numbers may be persistent, the same inode numbers) and inode numbers may be persistent,
...@@ -362,12 +378,11 @@ A partial list of the supported mount options follows: ...@@ -362,12 +378,11 @@ A partial list of the supported mount options follows:
are unique if multiple server side mounts are exported under a are unique if multiple server side mounts are exported under a
single share (since inode numbers on the servers might not single share (since inode numbers on the servers might not
be unique if multiple filesystems are mounted under the same be unique if multiple filesystems are mounted under the same
shared higher level directory). Note that this requires that shared higher level directory). Note that some older
the server support the CIFS Unix Extensions as other servers (e.g. pre-Windows 2000) do not support returning UniqueIDs
do not return a unique IndexNumber on SMB FindFirst (most or the CIFS Unix Extensions equivalent and for those
servers return zero as the IndexNumber). Parameter has no this mount option will have no effect. Exporting cifs mounts
effect to Windows servers and others which do not support the under nfsd requires this mount option on the cifs mount.
CIFS Unix Extensions.
noserverino Client generates inode numbers (rather than using the actual one noserverino Client generates inode numbers (rather than using the actual one
from the server) by default. from the server) by default.
setuids If the CIFS Unix extensions are negotiated with the server setuids If the CIFS Unix extensions are negotiated with the server
...@@ -375,7 +390,7 @@ A partial list of the supported mount options follows: ...@@ -375,7 +390,7 @@ A partial list of the supported mount options follows:
the local process on newly created files, directories, and the local process on newly created files, directories, and
devices (create, mkdir, mknod). If the CIFS Unix Extensions devices (create, mkdir, mknod). If the CIFS Unix Extensions
are not negotiated, for newly created files and directories are not negotiated, for newly created files and directories
instead of using the default uid and gid specified on the instead of using the default uid and gid specified on
the mount, cache the new file's uid and gid locally which means the mount, cache the new file's uid and gid locally which means
that the uid for the file can change when the inode is that the uid for the file can change when the inode is
reloaded (or the user remounts the share). reloaded (or the user remounts the share).
...@@ -429,6 +444,13 @@ A partial list of the supported mount options follows: ...@@ -429,6 +444,13 @@ A partial list of the supported mount options follows:
noposixpaths If CIFS Unix extensions are supported, do not request noposixpaths If CIFS Unix extensions are supported, do not request
posix path name support (this may cause servers to posix path name support (this may cause servers to
reject creatingfile with certain reserved characters). reject creatingfile with certain reserved characters).
nounix Disable the CIFS Unix Extensions for this mount (tree
connection). This is rarely needed, but it may be useful
in order to turn off multiple settings all at once (ie
posix acls, posix locks, posix paths, symlink support
and retrieving uids/gids/mode from the server) or to
work around a bug in server which implement the Unix
Extensions.
nobrl Do not send byte range lock requests to the server. nobrl Do not send byte range lock requests to the server.
This is necessary for certain applications that break This is necessary for certain applications that break
with cifs style mandatory byte range locks (and most with cifs style mandatory byte range locks (and most
...@@ -436,11 +458,17 @@ A partial list of the supported mount options follows: ...@@ -436,11 +458,17 @@ A partial list of the supported mount options follows:
byte range locks). byte range locks).
remount remount the share (often used to change from ro to rw mounts remount remount the share (often used to change from ro to rw mounts
or vice versa) or vice versa)
servern Specify the server 's netbios name (RFC1001 name) to use
when attempting to setup a session to the server. This is
This is needed for mounting to some older servers (such
as OS/2 or Windows 98 and Windows ME) since they do not
support a default server name. A server name can be up
to 15 characters long and is usually uppercased.
sfu When the CIFS Unix Extensions are not negotiated, attempt to sfu When the CIFS Unix Extensions are not negotiated, attempt to
create device files and fifos in a format compatible with create device files and fifos in a format compatible with
Services for Unix (SFU). In addition retrieve bits 10-12 Services for Unix (SFU). In addition retrieve bits 10-12
of the mode via the SETFILEBITS extended attribute (as of the mode via the SETFILEBITS extended attribute (as
SFU does). In the future the bottom 9 bits of the mode SFU does). In the future the bottom 9 bits of the
mode also will be emulated using queries of the security mode also will be emulated using queries of the security
descriptor (ACL). descriptor (ACL).
sign Must use packet signing (helps avoid unwanted data modification sign Must use packet signing (helps avoid unwanted data modification
...@@ -467,7 +495,7 @@ including: ...@@ -467,7 +495,7 @@ including:
-V print mount.cifs version -V print mount.cifs version
-? display simple usage information -? display simple usage information
With recent 2.6 kernel versions of modutils, the version of the cifs kernel With most 2.6 kernel versions of modutils, the version of the cifs kernel
module can be displayed via modinfo. module can be displayed via modinfo.
Misc /proc/fs/cifs Flags and Debug Info Misc /proc/fs/cifs Flags and Debug Info
...@@ -516,8 +544,22 @@ SecurityFlags Flags which control security negotiation and ...@@ -516,8 +544,22 @@ SecurityFlags Flags which control security negotiation and
must use plaintext passwords 0x20020 must use plaintext passwords 0x20020
(reserved for future packet encryption) 0x00040 (reserved for future packet encryption) 0x00040
cifsFYI If set to one, additional debug information is cifsFYI If set to non-zero value, additional debug information
logged to the system error log. (default 0) will be logged to the system error log. This field
contains three flags controlling different classes of
debugging entries. The maximum value it can be set
to is 7 which enables all debugging points (default 0).
Some debugging statements are not compiled into the
cifs kernel unless CONFIG_CIFS_DEBUG2 is enabled in the
kernel configuration. cifsFYI may be set to one or
nore of the following flags (7 sets them all):
log cifs informational messages 0x01
log return codes from cifs entry points 0x02
log slow responses (ie which take longer than 1 second)
CONFIG_CIFS_STATS2 must be enabled in .config 0x04
traceSMB If set to one, debug information is logged to the traceSMB If set to one, debug information is logged to the
system error log with the start of smb requests system error log with the start of smb requests
and responses (default 0) and responses (default 0)
...@@ -563,10 +605,10 @@ the start of smb requests and responses can be enabled via: ...@@ -563,10 +605,10 @@ the start of smb requests and responses can be enabled via:
echo 1 > /proc/fs/cifs/traceSMB echo 1 > /proc/fs/cifs/traceSMB
Two other experimental features are under development and to test Two other experimental features are under development. To test these
require enabling CONFIG_CIFS_EXPERIMENTAL requires enabling CONFIG_CIFS_EXPERIMENTAL
More efficient write operations ipv6 enablement
DNOTIFY fcntl: needed for support of directory change DNOTIFY fcntl: needed for support of directory change
notification and perhaps later for file leases) notification and perhaps later for file leases)
......
Version 1.39 November 30, 2005 Version 1.49 April 26, 2007
A Partial List of Missing Features A Partial List of Missing Features
================================== ==================================
...@@ -18,64 +18,53 @@ better) ...@@ -18,64 +18,53 @@ better)
d) Kerberos/SPNEGO session setup support - (started) d) Kerberos/SPNEGO session setup support - (started)
e) NTLMv2 authentication (mostly implemented - double check e) Cleanup now unneeded SessSetup code in
that NTLMv2 signing works, also need to cleanup now unneeded SessSetup code in fs/cifs/connect.c and add back in NTLMSSP code if any servers
fs/cifs/connect.c) need it
f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup
used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
and raw NTLMSSP already. This is important when enabling and raw NTLMSSP already. This is important when enabling
extended security and mounting to Windows 2003 Servers extended security and mounting to Windows 2003 Servers
f) Directory entry caching relies on a 1 second timer, rather than g) Directory entry caching relies on a 1 second timer, rather than
using FindNotify or equivalent. - (started) using FindNotify or equivalent. - (started)
g) A few byte range testcases fail due to POSIX vs. Windows/CIFS h) quota support (needs minor kernel change since quota calls
style byte range lock differences. Save byte range locks so
reconnect can replay them.
h) Support unlock all (unlock 0,MAX_OFFSET)
by unlocking all known byte range locks that we locked on the file.
i) quota support (needs minor kernel change since quota calls
to make it to network filesystems or deviceless filesystems) to make it to network filesystems or deviceless filesystems)
j) investigate sync behavior (including syncpage) and check i) investigate sync behavior (including syncpage) and check
for proper behavior of intr/nointr for proper behavior of intr/nointr
k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
extra copy in/out of the socket buffers in some cases. extra copy in/out of the socket buffers in some cases.
l) finish support for IPv6. This is mostly complete but k) Better optimize open (and pathbased setfilesize) to reduce the
needs a simple conversion of ipv6 to sin6_addr from the
address in string representation.
m) Better optimize open (and pathbased setfilesize) to reduce the
oplock breaks coming from windows srv. Piggyback identical file oplock breaks coming from windows srv. Piggyback identical file
opens on top of each other by incrementing reference count rather opens on top of each other by incrementing reference count rather
than resending (helps reduce server resource utilization and avoid than resending (helps reduce server resource utilization and avoid
spurious oplock breaks). spurious oplock breaks).
o) Improve performance of readpages by sending more than one read l) Improve performance of readpages by sending more than one read
at a time when 8 pages or more are requested. In conjuntion at a time when 8 pages or more are requested. In conjuntion
add support for async_cifs_readpages. add support for async_cifs_readpages.
p) Add support for storing symlink info to Windows servers m) Add support for storing symlink info to Windows servers
in the Extended Attribute format their SFU clients would recognize. in the Extended Attribute format their SFU clients would recognize.
q) Finish fcntl D_NOTIFY support so kde and gnome file list windows n) Finish fcntl D_NOTIFY support so kde and gnome file list windows
will autorefresh (partially complete by Asser). Needs minor kernel will autorefresh (partially complete by Asser). Needs minor kernel
vfs change to support removing D_NOTIFY on a file. vfs change to support removing D_NOTIFY on a file.
r) Add GUI tool to configure /proc/fs/cifs settings and for display of o) Add GUI tool to configure /proc/fs/cifs settings and for display of
the CIFS statistics (started) the CIFS statistics (started)
s) implement support for security and trusted categories of xattrs p) implement support for security and trusted categories of xattrs
(requires minor protocol extension) to enable better support for SELINUX (requires minor protocol extension) to enable better support for SELINUX
t) Implement O_DIRECT flag on open (already supported on mount) q) Implement O_DIRECT flag on open (already supported on mount)
u) Create UID mapping facility so server UIDs can be mapped on a per r) Create UID mapping facility so server UIDs can be mapped on a per
mount or a per server basis to client UIDs or nobody if no mapping mount or a per server basis to client UIDs or nobody if no mapping
exists. This is helpful when Unix extensions are negotiated to exists. This is helpful when Unix extensions are negotiated to
allow better permission checking when UIDs differ on the server allow better permission checking when UIDs differ on the server
...@@ -83,19 +72,25 @@ and client. Add new protocol request to the CIFS protocol ...@@ -83,19 +72,25 @@ and client. Add new protocol request to the CIFS protocol
standard for asking the server for the corresponding name of a standard for asking the server for the corresponding name of a
particular uid. particular uid.
v) Add support for CIFS Unix and also the newer POSIX extensions to the s) Add support for CIFS Unix and also the newer POSIX extensions to the
server side for Samba 4. server side for Samba 4.
w) Finish up the dos time conversion routines needed to return old server t) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers)
time to the client (default time, of now or time 0 is used now for these
very old servers)
x) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers)
need to add ability to set time to server (utimes command) need to add ability to set time to server (utimes command)
y) Finish testing of Windows 9x/Windows ME server support (started). u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
v) mount check for unmatched uids
KNOWN BUGS (updated February 26, 2007) w) Add support for new vfs entry points for setlease and fallocate
x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of
processes can proceed better in parallel (on the server)
y) Fix Samba 3 to handle reads/writes over 127K (and remove the cifs mount
restriction of wsize max being 127K)
KNOWN BUGS (updated April 24, 2007)
==================================== ====================================
See http://bugzilla.samba.org - search on product "CifsVFS" for See http://bugzilla.samba.org - search on product "CifsVFS" for
current bug list. current bug list.
...@@ -110,6 +105,12 @@ but recognizes them ...@@ -110,6 +105,12 @@ but recognizes them
succeed but still return access denied (appears to be Windows succeed but still return access denied (appears to be Windows
server not cifs client problem) and has not been reproduced recently. server not cifs client problem) and has not been reproduced recently.
NTFS partitions do not have this problem. NTFS partitions do not have this problem.
4) Unix/POSIX capabilities are reset after reconnection, and affect
a few fields in the tree connection but we do do not know which
superblocks to apply these changes to. We should probably walk
the list of superblocks to set these. Also need to check the
flags on the second mount to the same share, and see if we
can do the same trick that NFS does to remount duplicate shares.
Misc testing to do Misc testing to do
================== ==================
...@@ -126,3 +127,4 @@ negotiated size) and send larger write sizes to modern servers. ...@@ -126,3 +127,4 @@ negotiated size) and send larger write sizes to modern servers.
4) More exhaustively test against less common servers. More testing 4) More exhaustively test against less common servers. More testing
against Windows 9x, Windows ME servers. against Windows 9x, Windows ME servers.
...@@ -388,10 +388,9 @@ asn1_oid_decode(struct asn1_ctx *ctx, ...@@ -388,10 +388,9 @@ asn1_oid_decode(struct asn1_ctx *ctx,
unsigned long *optr; unsigned long *optr;
size = eoc - ctx->pointer + 1; size = eoc - ctx->pointer + 1;
*oid = kmalloc(size * sizeof (unsigned long), GFP_ATOMIC); *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC);
if (*oid == NULL) { if (*oid == NULL)
return 0; return 0;
}
optr = *oid; optr = *oid;
...@@ -462,7 +461,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, ...@@ -462,7 +461,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
unsigned int cls, con, tag, oidlen, rc; unsigned int cls, con, tag, oidlen, rc;
int use_ntlmssp = FALSE; int use_ntlmssp = FALSE;
*secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default */ *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/
/* cifs_dump_mem(" Received SecBlob ", security_blob, length); */ /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */
...@@ -501,7 +500,8 @@ decode_negTokenInit(unsigned char *security_blob, int length, ...@@ -501,7 +500,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
return 0; return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON) } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|| (tag != ASN1_EOC)) { || (tag != ASN1_EOC)) {
cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 0", cFYI(1,
("cls = %d con = %d tag = %d end = %p (%d) exit 0",
cls, con, tag, end, *end)); cls, con, tag, end, *end));
return 0; return 0;
} }
...@@ -511,7 +511,8 @@ decode_negTokenInit(unsigned char *security_blob, int length, ...@@ -511,7 +511,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
return 0; return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_CON) } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|| (tag != ASN1_SEQ)) { || (tag != ASN1_SEQ)) {
cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 1", cFYI(1,
("cls = %d con = %d tag = %d end = %p (%d) exit 1",
cls, con, tag, end, *end)); cls, con, tag, end, *end));
return 0; return 0;
} }
...@@ -543,32 +544,34 @@ decode_negTokenInit(unsigned char *security_blob, int length, ...@@ -543,32 +544,34 @@ decode_negTokenInit(unsigned char *security_blob, int length,
rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
if (!rc) { if (!rc) {
cFYI(1, cFYI(1,
("Error 1 decoding negTokenInit header exit 2")); ("Error decoding negTokenInit hdr exit2"));
return 0; return 0;
} }
if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
rc = asn1_oid_decode(&ctx, end, &oid, &oidlen); rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
if(rc) { if (rc) {
cFYI(1, cFYI(1,
("OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx", ("OID len = %d oid = 0x%lx 0x%lx "
oidlen, *oid, *(oid + 1), *(oid + 2), "0x%lx 0x%lx",
*(oid + 3))); oidlen, *oid, *(oid + 1),
rc = compare_oid(oid, oidlen, NTLMSSP_OID, *(oid + 2), *(oid + 3)));
NTLMSSP_OID_LEN); rc = compare_oid(oid, oidlen,
NTLMSSP_OID, NTLMSSP_OID_LEN);
kfree(oid); kfree(oid);
if (rc) if (rc)
use_ntlmssp = TRUE; use_ntlmssp = TRUE;
} }
} else { } else {
cFYI(1,("This should be an oid what is going on? ")); cFYI(1, ("Should be an oid what is going on?"));
} }
} }
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, cFYI(1,
("Error decoding last part of negTokenInit exit 3")); ("Error decoding last part negTokenInit exit3"));
return 0; return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { /* tag = 3 indicating mechListMIC */ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
/* tag = 3 indicating mechListMIC */
cFYI(1, cFYI(1,
("Exit 4 cls = %d con = %d tag = %d end = %p (%d)", ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)",
cls, con, tag, end, *end)); cls, con, tag, end, *end));
...@@ -576,18 +579,17 @@ decode_negTokenInit(unsigned char *security_blob, int length, ...@@ -576,18 +579,17 @@ decode_negTokenInit(unsigned char *security_blob, int length,
} }
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, cFYI(1,
("Error decoding last part of negTokenInit exit 5")); ("Error decoding last part negTokenInit exit5"));
return 0; return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_CON) } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|| (tag != ASN1_SEQ)) { || (tag != ASN1_SEQ)) {
cFYI(1, cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)",
("Exit 6 cls = %d con = %d tag = %d end = %p (%d)",
cls, con, tag, end, *end)); cls, con, tag, end, *end));
} }
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, cFYI(1,
("Error decoding last part of negTokenInit exit 7")); ("Error decoding last part negTokenInit exit 7"));
return 0; return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
cFYI(1, cFYI(1,
...@@ -597,16 +599,17 @@ decode_negTokenInit(unsigned char *security_blob, int length, ...@@ -597,16 +599,17 @@ decode_negTokenInit(unsigned char *security_blob, int length,
} }
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1, cFYI(1,
("Error decoding last part of negTokenInit exit 9")); ("Error decoding last part negTokenInit exit9"));
return 0; return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_PRI) } else if ((cls != ASN1_UNI) || (con != ASN1_PRI)
|| (tag != ASN1_GENSTR)) { || (tag != ASN1_GENSTR)) {
cFYI(1, cFYI(1,
("Exit 10 cls = %d con = %d tag = %d end = %p (%d)", ("Exit10 cls = %d con = %d tag = %d end = %p (%d)",
cls, con, tag, end, *end)); cls, con, tag, end, *end));
return 0; return 0;
} }
cFYI(1, ("Need to call asn1_octets_decode() function for this %s", ctx.pointer)); /* is this UTF-8 or ASCII? */ cFYI(1, ("Need to call asn1_octets_decode() function for %s",
ctx.pointer)); /* is this UTF-8 or ASCII? */
} }
/* if (use_kerberos) /* if (use_kerberos)
......
...@@ -58,50 +58,49 @@ cifs_dump_mem(char *label, void *data, int length) ...@@ -58,50 +58,49 @@ cifs_dump_mem(char *label, void *data, int length)
} }
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
void cifs_dump_detail(struct smb_hdr * smb) void cifs_dump_detail(struct smb_hdr *smb)
{ {
cERROR(1,("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d", cERROR(1, ("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
smb->Command, smb->Status.CifsError, smb->Command, smb->Status.CifsError,
smb->Flags, smb->Flags2, smb->Mid, smb->Pid)); smb->Flags, smb->Flags2, smb->Mid, smb->Pid));
cERROR(1,("smb buf %p len %d", smb, smbCalcSize_LE(smb))); cERROR(1, ("smb buf %p len %d", smb, smbCalcSize_LE(smb)));
} }
void cifs_dump_mids(struct TCP_Server_Info * server) void cifs_dump_mids(struct TCP_Server_Info *server)
{ {
struct list_head *tmp; struct list_head *tmp;
struct mid_q_entry * mid_entry; struct mid_q_entry *mid_entry;
if(server == NULL) if (server == NULL)
return; return;
cERROR(1,("Dump pending requests:")); cERROR(1, ("Dump pending requests:"));
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
list_for_each(tmp, &server->pending_mid_q) { list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead); mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
if(mid_entry) { if (mid_entry) {
cERROR(1,("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", cERROR(1, ("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
mid_entry->midState, mid_entry->midState,
(int)mid_entry->command, (int)mid_entry->command,
mid_entry->pid, mid_entry->pid,
mid_entry->tsk, mid_entry->tsk,
mid_entry->mid)); mid_entry->mid));
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
cERROR(1,("IsLarge: %d buf: %p time rcv: %ld now: %ld", cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld",
mid_entry->largeBuf, mid_entry->largeBuf,
mid_entry->resp_buf, mid_entry->resp_buf,
mid_entry->when_received, mid_entry->when_received,
jiffies)); jiffies));
#endif /* STATS2 */ #endif /* STATS2 */
cERROR(1,("IsMult: %d IsEnd: %d", mid_entry->multiRsp, cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
mid_entry->multiEnd)); mid_entry->multiEnd));
if(mid_entry->resp_buf) { if (mid_entry->resp_buf) {
cifs_dump_detail(mid_entry->resp_buf); cifs_dump_detail(mid_entry->resp_buf);
cifs_dump_mem("existing buf: ", cifs_dump_mem("existing buf: ",
mid_entry->resp_buf, mid_entry->resp_buf,
62 /* fixme */); 62 /* fixme */);
} }
} }
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -115,12 +114,12 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -115,12 +114,12 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
{ {
struct list_head *tmp; struct list_head *tmp;
struct list_head *tmp1; struct list_head *tmp1;
struct mid_q_entry * mid_entry; struct mid_q_entry *mid_entry;
struct cifsSesInfo *ses; struct cifsSesInfo *ses;
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
int i; int i;
int length = 0; int length = 0;
char * original_buf = buf; char *original_buf = buf;
*beginBuffer = buf + offset; *beginBuffer = buf + offset;
...@@ -129,9 +128,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -129,9 +128,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
"Display Internal CIFS Data Structures for Debugging\n" "Display Internal CIFS Data Structures for Debugging\n"
"---------------------------------------------------\n"); "---------------------------------------------------\n");
buf += length; buf += length;
length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION); length = sprintf(buf, "CIFS Version %s\n", CIFS_VERSION);
buf += length; buf += length;
length = sprintf(buf,"Active VFS Requests: %d\n", GlobalTotalActiveXid); length = sprintf(buf,
"Active VFS Requests: %d\n", GlobalTotalActiveXid);
buf += length; buf += length;
length = sprintf(buf, "Servers:"); length = sprintf(buf, "Servers:");
buf += length; buf += length;
...@@ -141,23 +141,25 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -141,23 +141,25 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
list_for_each(tmp, &GlobalSMBSessionList) { list_for_each(tmp, &GlobalSMBSessionList) {
i++; i++;
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
if((ses->serverDomain == NULL) || (ses->serverOS == NULL) || if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
(ses->serverNOS == NULL)) { (ses->serverNOS == NULL)) {
buf += sprintf(buf, "\nentry for %s not fully " buf += sprintf(buf, "\nentry for %s not fully "
"displayed\n\t", ses->serverName); "displayed\n\t", ses->serverName);
} else { } else {
length = length =
sprintf(buf, sprintf(buf,
"\n%d) Name: %s Domain: %s Mounts: %d OS: %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB session status: %d\t", "\n%d) Name: %s Domain: %s Mounts: %d OS:"
" %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB"
" session status: %d\t",
i, ses->serverName, ses->serverDomain, i, ses->serverName, ses->serverDomain,
atomic_read(&ses->inUse), atomic_read(&ses->inUse),
ses->serverOS, ses->serverNOS, ses->serverOS, ses->serverNOS,
ses->capabilities,ses->status); ses->capabilities, ses->status);
buf += length; buf += length;
} }
if(ses->server) { if (ses->server) {
buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d", buf += sprintf(buf, "TCP status: %d\n\tLocal Users To "
"Server: %d SecMode: 0x%x Req On Wire: %d",
ses->server->tcpStatus, ses->server->tcpStatus,
atomic_read(&ses->server->socketUseCount), atomic_read(&ses->server->socketUseCount),
ses->server->secMode, ses->server->secMode,
...@@ -177,8 +179,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -177,8 +179,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
mid_entry = list_entry(tmp1, struct mid_entry = list_entry(tmp1, struct
mid_q_entry, mid_q_entry,
qhead); qhead);
if(mid_entry) { if (mid_entry) {
length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n", length = sprintf(buf,
"State: %d com: %d pid:"
" %d tsk: %p mid %d\n",
mid_entry->midState, mid_entry->midState,
(int)mid_entry->command, (int)mid_entry->command,
mid_entry->pid, mid_entry->pid,
...@@ -205,12 +209,16 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -205,12 +209,16 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
i++; i++;
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
length = length = sprintf(buf, "\n%d) %s Uses: %d ", i,
sprintf(buf, tcon->treeName, atomic_read(&tcon->useCount));
"\n%d) %s Uses: %d Type: %s DevInfo: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", buf += length;
i, tcon->treeName, if (tcon->nativeFileSystem) {
atomic_read(&tcon->useCount), length = sprintf(buf, "Type: %s ",
tcon->nativeFileSystem, tcon->nativeFileSystem);
buf += length;
}
length = sprintf(buf, "DevInfo: 0x%x Attributes: 0x%x"
"\nPathComponentMax: %d Status: %d",
le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
le32_to_cpu(tcon->fsAttrInfo.Attributes), le32_to_cpu(tcon->fsAttrInfo.Attributes),
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
...@@ -224,7 +232,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -224,7 +232,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
length = length =
sprintf(buf, " type: %d ", dev_type); sprintf(buf, " type: %d ", dev_type);
buf += length; buf += length;
if(tcon->tidStatus == CifsNeedReconnect) { if (tcon->tidStatus == CifsNeedReconnect) {
buf += sprintf(buf, "\tDISCONNECTED "); buf += sprintf(buf, "\tDISCONNECTED ");
length += 14; length += 14;
} }
...@@ -238,9 +246,9 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -238,9 +246,9 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
/* Now calculate total size of returned data */ /* Now calculate total size of returned data */
length = buf - original_buf; length = buf - original_buf;
if(offset + count >= length) if (offset + count >= length)
*eof = 1; *eof = 1;
if(length < offset) { if (length < offset) {
*eof = 1; *eof = 1;
return 0; return 0;
} else { } else {
...@@ -304,7 +312,7 @@ static int ...@@ -304,7 +312,7 @@ static int
cifs_stats_read(char *buf, char **beginBuffer, off_t offset, cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
int count, int *eof, void *data) int count, int *eof, void *data)
{ {
int item_length,i,length; int item_length, i, length;
struct list_head *tmp; struct list_head *tmp;
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
...@@ -315,19 +323,19 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, ...@@ -315,19 +323,19 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
sesInfoAllocCount.counter); sesInfoAllocCount.counter);
buf += length; buf += length;
item_length = item_length =
sprintf(buf,"Share (unique mount targets): %d\n", sprintf(buf, "Share (unique mount targets): %d\n",
tconInfoAllocCount.counter); tconInfoAllocCount.counter);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
item_length = item_length =
sprintf(buf,"SMB Request/Response Buffer: %d Pool size: %d\n", sprintf(buf, "SMB Request/Response Buffer: %d Pool size: %d\n",
bufAllocCount.counter, bufAllocCount.counter,
cifs_min_rcv + tcpSesAllocCount.counter); cifs_min_rcv + tcpSesAllocCount.counter);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
item_length = item_length =
sprintf(buf,"SMB Small Req/Resp Buffer: %d Pool size: %d\n", sprintf(buf, "SMB Small Req/Resp Buffer: %d Pool size: %d\n",
smBufAllocCount.counter,cifs_min_small); smBufAllocCount.counter, cifs_min_small);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
...@@ -339,19 +347,19 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, ...@@ -339,19 +347,19 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
#endif /* CONFIG_CIFS_STATS2 */ #endif /* CONFIG_CIFS_STATS2 */
item_length = item_length =
sprintf(buf,"Operations (MIDs): %d\n", sprintf(buf, "Operations (MIDs): %d\n",
midCount.counter); midCount.counter);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
item_length = sprintf(buf, item_length = sprintf(buf,
"\n%d session %d share reconnects\n", "\n%d session %d share reconnects\n",
tcpSesReconnectCount.counter,tconInfoReconnectCount.counter); tcpSesReconnectCount.counter, tconInfoReconnectCount.counter);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
item_length = sprintf(buf, item_length = sprintf(buf,
"Total vfs operations: %d maximum at one time: %d\n", "Total vfs operations: %d maximum at one time: %d\n",
GlobalCurrentXid,GlobalMaxActiveXid); GlobalCurrentXid, GlobalMaxActiveXid);
length += item_length; length += item_length;
buf += item_length; buf += item_length;
...@@ -360,10 +368,10 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, ...@@ -360,10 +368,10 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
list_for_each(tmp, &GlobalTreeConnectionList) { list_for_each(tmp, &GlobalTreeConnectionList) {
i++; i++;
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
item_length = sprintf(buf,"\n%d) %s",i, tcon->treeName); item_length = sprintf(buf, "\n%d) %s", i, tcon->treeName);
buf += item_length; buf += item_length;
length += item_length; length += item_length;
if(tcon->tidStatus == CifsNeedReconnect) { if (tcon->tidStatus == CifsNeedReconnect) {
buf += sprintf(buf, "\tDISCONNECTED "); buf += sprintf(buf, "\tDISCONNECTED ");
length += 14; length += 14;
} }
...@@ -415,12 +423,12 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, ...@@ -415,12 +423,12 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
buf += sprintf(buf,"\n"); buf += sprintf(buf, "\n");
length++; length++;
if(offset + count >= length) if (offset + count >= length)
*eof = 1; *eof = 1;
if(length < offset) { if (length < offset) {
*eof = 1; *eof = 1;
return 0; return 0;
} else { } else {
...@@ -547,11 +555,11 @@ cifs_proc_clean(void) ...@@ -547,11 +555,11 @@ cifs_proc_clean(void)
remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("MultiuserMount", proc_fs_cifs);
remove_proc_entry("OplockEnabled", proc_fs_cifs); remove_proc_entry("OplockEnabled", proc_fs_cifs);
/* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */ /* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
remove_proc_entry("SecurityFlags",proc_fs_cifs); remove_proc_entry("SecurityFlags", proc_fs_cifs);
/* remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */ /* remove_proc_entry("PacketSigningEnabled", proc_fs_cifs); */
remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
remove_proc_entry("Experimental",proc_fs_cifs); remove_proc_entry("Experimental", proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
remove_proc_entry("cifs", proc_root_fs); remove_proc_entry("cifs", proc_root_fs);
} }
...@@ -590,7 +598,7 @@ cifsFYI_write(struct file *file, const char __user *buffer, ...@@ -590,7 +598,7 @@ cifsFYI_write(struct file *file, const char __user *buffer,
cifsFYI = 0; cifsFYI = 0;
else if (c == '1' || c == 'y' || c == 'Y') else if (c == '1' || c == 'y' || c == 'Y')
cifsFYI = 1; cifsFYI = 1;
else if((c > '1') && (c <= '9')) else if ((c > '1') && (c <= '9'))
cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */ cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */
return count; return count;
...@@ -860,15 +868,15 @@ security_flags_write(struct file *file, const char __user *buffer, ...@@ -860,15 +868,15 @@ security_flags_write(struct file *file, const char __user *buffer,
char flags_string[12]; char flags_string[12];
char c; char c;
if((count < 1) || (count > 11)) if ((count < 1) || (count > 11))
return -EINVAL; return -EINVAL;
memset(flags_string, 0, 12); memset(flags_string, 0, 12);
if(copy_from_user(flags_string, buffer, count)) if (copy_from_user(flags_string, buffer, count))
return -EFAULT; return -EFAULT;
if(count < 3) { if (count < 3) {
/* single char or single char followed by null */ /* single char or single char followed by null */
c = flags_string[0]; c = flags_string[0];
if (c == '0' || c == 'n' || c == 'N') if (c == '0' || c == 'n' || c == 'N')
...@@ -881,104 +889,28 @@ security_flags_write(struct file *file, const char __user *buffer, ...@@ -881,104 +889,28 @@ security_flags_write(struct file *file, const char __user *buffer,
flags = simple_strtoul(flags_string, NULL, 0); flags = simple_strtoul(flags_string, NULL, 0);
cFYI(1,("sec flags 0x%x", flags)); cFYI(1, ("sec flags 0x%x", flags));
if(flags <= 0) { if (flags <= 0) {
cERROR(1,("invalid security flags %s",flags_string)); cERROR(1, ("invalid security flags %s", flags_string));
return -EINVAL; return -EINVAL;
} }
if(flags & ~CIFSSEC_MASK) { if (flags & ~CIFSSEC_MASK) {
cERROR(1,("attempt to set unsupported security flags 0x%x", cERROR(1, ("attempt to set unsupported security flags 0x%x",
flags & ~CIFSSEC_MASK)); flags & ~CIFSSEC_MASK));
return -EINVAL; return -EINVAL;
} }
/* flags look ok - update the global security flags for cifs module */ /* flags look ok - update the global security flags for cifs module */
extended_security = flags; extended_security = flags;
if (extended_security & CIFSSEC_MUST_SIGN) {
/* requiring signing implies signing is allowed */
extended_security |= CIFSSEC_MAY_SIGN;
cFYI(1, ("packet signing now required"));
} else if ((extended_security & CIFSSEC_MAY_SIGN) == 0) {
cFYI(1, ("packet signing disabled"));
}
/* BB should we turn on MAY flags for other MUST options? */
return count; return count;
} }
/* static int
ntlmv2_enabled_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len;
len = sprintf(page, "%d\n", ntlmv2_support);
len -= off;
*start = page + off;
if (len > count)
len = count;
else
*eof = 1;
if (len < 0)
len = 0;
return len;
}
static int
ntlmv2_enabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
int rc;
rc = get_user(c, buffer);
if (rc)
return rc;
if (c == '0' || c == 'n' || c == 'N')
ntlmv2_support = 0;
else if (c == '1' || c == 'y' || c == 'Y')
ntlmv2_support = 1;
else if (c == '2')
ntlmv2_support = 2;
return count;
}
static int
packet_signing_enabled_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int len;
len = sprintf(page, "%d\n", sign_CIFS_PDUs);
len -= off;
*start = page + off;
if (len > count)
len = count;
else
*eof = 1;
if (len < 0)
len = 0;
return len;
}
static int
packet_signing_enabled_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
char c;
int rc;
rc = get_user(c, buffer);
if (rc)
return rc;
if (c == '0' || c == 'n' || c == 'N')
sign_CIFS_PDUs = 0;
else if (c == '1' || c == 'y' || c == 'Y')
sign_CIFS_PDUs = 1;
else if (c == '2')
sign_CIFS_PDUs = 2;
return count;
} */
#endif #endif
/*
* fs/cifs/cifs_dfs_ref.c
*
* Copyright (C) International Business Machines Corp., 2007
* Author(s): Steve French (sfrench@us.ibm.com)
* Igor Mammedov (niallain@gmail.com)
* Contains the CIFS DFS upcall routines
*
* 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
*/
#include <linux/dcache.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/vfs.h>
#include <linux/fs.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)
#ifdef CONFIG_CIFS_EXPERIMENTAL
LIST_HEAD(cifs_dfs_automount_list);
static void cifs_resolver_describe(const struct key *key, struct seq_file *m)
{
cFYI(1, ("%s: key->description: %s", __FUNCTION__, key->description ));
seq_puts(m, key->description);
seq_printf(m, ": %u", key->datalen);
}
static int cifs_resolver_match(const struct key *key, const void *description)
{
cFYI(1, ("%s: key->description: %s ; desc: %s ", __FUNCTION__,
key->description, (char *)description ));
return strcmp(key->description, description) == 0;
}
static int cifs_resolver_instantiate(struct key *key, const void *data,
size_t datalen)
{
char *ip = NULL;
int rc;
struct in_addr ip_addr;
/* convert dot ip addr to numeric form */
/* BB Do we have to pass datalen? Are we guaranteed that the key
* is null terminated? */
rc = cifs_inet_pton(AF_INET, (char *)data, &(ip_addr.s_addr));
if (rc <= 0) {
ip = kmalloc(datalen+1, GFP_KERNEL);
if (ip == NULL) {
return -ENOMEM;
}
strncpy( ip, (char *)data, datalen);
ip[datalen] = 0;
cFYI(1, ("%s: failed to convert ip to binary: %s",
__FUNCTION__, ip));
kfree(ip);
rc = -EINVAL;
return rc;
}
rc = 0;
key->payload.value = ip_addr.s_addr;
return rc;
}
struct key_type key_type_cifs_resolver =
{
.name = "cifs_resolver",
.def_datalen = sizeof(struct in_addr),
.describe = cifs_resolver_describe,
.instantiate = cifs_resolver_instantiate,
.match = cifs_resolver_match,
};
int
cifs_resolve_server_name_to_ip(const char *unc, struct in_addr *ip_addr) {
int rc = -EAGAIN;
struct key *rkey;
char *name;
int len;
if ((!ip_addr) || (!unc)) {
return -EINVAL;
}
/* search for server name delimiter */
len = strlen( unc);
if (len < 3) {
cFYI(1, ("%s: unc is too short: %s",
__FUNCTION__, unc ));
return -EINVAL;
}
len -= 2;
name = memchr(unc+2, '\\', len);
if (!name) {
cFYI(1, ("%s: probably server name is whole unc: %s",
__FUNCTION__, unc ));
} else {
len = (name - unc) - 2/* leading // */;
}
name = kmalloc( len+1, GFP_KERNEL);
if (name == NULL) {
rc = -ENOMEM;
return rc;
}
memcpy( name, unc+2, len);
name[len] = 0;
rkey = request_key(&key_type_cifs_resolver, name, "");
if (!IS_ERR(rkey)) {
ip_addr->s_addr = rkey->payload.value;
cFYI(1, ("%s: resolved: %s to %u.%u.%u.%u", __FUNCTION__,
rkey->description,
NIPQUAD(ip_addr->s_addr)
));
key_put(rkey);
rc = 0;
} else {
cERROR(1, ("%s: unable to resolve: %s", __FUNCTION__, name));
}
kfree(name);
return rc;
}
char *
cifs_get_share_name(const char *node_name)
{
int len;
char *UNC;
char *pSep;
len = strlen(node_name);
UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */,
GFP_KERNEL);
if (!UNC) {
return NULL;
}
/* get share name and server name */
if (node_name[1] != '\\'){
UNC[0] = '\\';
strncpy(UNC+1, node_name, len);
len++;
UNC[len] = 0;
} else {
strncpy(UNC, node_name, len);
UNC[len] = 0;
}
/* find server name end */
pSep = memchr(UNC+2, '\\', len-2);
if (!pSep) {
cERROR(1, ("%s: no server name end in node name: %s",
__FUNCTION__, node_name ));
kfree(UNC);
return NULL;
}
/* find sharename end */
pSep++;
pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
if (!pSep) {
cERROR(1, ("%s:2 cant find share name in node name: %s",
__FUNCTION__, node_name ));
kfree(UNC);
return NULL;
}
/* trim path up to sharename end
* * now we have share name in UNC */
*pSep = 0;
len = pSep-UNC;
return UNC;
}
struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent,
struct dentry *dentry, char *ref_unc)
{
int rc;
struct cifs_sb_info *cifs_sb;
struct sockaddr_in sin_server;
struct vfsmount *mnt = ERR_PTR(-ENOENT);
char *mountdata;
int md_len;
char *devname;
char *tkn_e;
char srvIP[16];
char sep = ',';
int off, noff;
cFYI(1, ("in %s", __FUNCTION__ ));
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
if ( cifs_sb->mountdata == NULL ) {
return ERR_PTR(-EINVAL);
}
devname = cifs_get_share_name(ref_unc);
rc = cifs_resolve_server_name_to_ip( devname, &(sin_server.sin_addr));
snprintf(srvIP, sizeof(srvIP), "%u.%u.%u.%u",
NIPQUAD(sin_server.sin_addr));
if (rc != 0) {
if (devname) kfree(devname);
cERROR(1, ("%s: failed to resolve server part of %s to IP",
__FUNCTION__, devname ));
rc = -EINVAL;
return ERR_PTR(rc);
}
srvIP[sizeof(srvIP)-1] = '\0';
md_len = strlen(cifs_sb->mountdata) + sizeof(srvIP) +
strlen(ref_unc) + 3;
mountdata = kzalloc(md_len+1, GFP_KERNEL);
/* copy all options except unc,ip,prefixpath */
off = 0;
if (strncmp(cifs_sb->mountdata, "sep=", 4) == 0) {
sep = cifs_sb->mountdata[4];
strncpy(mountdata, cifs_sb->mountdata, 5);
off += 5;
}
while ( (tkn_e = strchr(cifs_sb->mountdata+off, sep)) ) {
noff = (tkn_e - (cifs_sb->mountdata+off)) + 1;
if (strnicmp(cifs_sb->mountdata+off, "unc=", 4) == 0) {
off += noff;
continue;
}
if (strnicmp(cifs_sb->mountdata+off, "ip=", 3) == 0) {
off += noff;
continue;
}
if (strnicmp(cifs_sb->mountdata+off, "prefixpath=", 3) == 0) {
off += noff;
continue;
}
strncat(mountdata, cifs_sb->mountdata+off, noff);
off += noff;
}
strcat(mountdata, cifs_sb->mountdata+off);
mountdata[md_len] = '\0';
strcat(mountdata, ", ip="); strcat(mountdata, srvIP);
strcat(mountdata, ", unc="); strcat(mountdata, devname);
/* find prefixpath */
tkn_e = strchr(ref_unc+2, '\\');
if ( tkn_e ) {
tkn_e = strchr(tkn_e+1, '\\');
if ( tkn_e ) {
strcat(mountdata, ",prefixpath=");
strcat(mountdata, tkn_e);
}
}
/*cFYI(1,("%s: old mountdata: %s", __FUNCTION__,cifs_sb->mountdata));*/
/*cFYI(1, ("%s: new mountdata: %s", __FUNCTION__, mountdata ));*/
mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata);
if (devname)
kfree(devname);
if (mountdata)
kfree(mountdata);
cFYI(1, ("leaving %s", __FUNCTION__ ));
return mnt;
}
static char *build_full_dfs_path_from_dentry(struct dentry *dentry)
{
char *full_path = NULL;
char *search_path;
char *tmp_path;
size_t l_max_len;
struct cifs_sb_info *cifs_sb;
if ( dentry->d_inode == NULL ) {
return NULL;
}
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
if ( cifs_sb->tcon == NULL ) {
return NULL;
}
search_path = build_path_from_dentry(dentry);
if (search_path == NULL) {
return NULL;
}
if (cifs_sb->tcon->Flags & 0x2) {
/* we should use full path name to correct working with DFS */
l_max_len = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1)
+ strnlen(search_path, MAX_PATHCONF) + 1;
tmp_path = kmalloc(l_max_len, GFP_KERNEL);
if (tmp_path == NULL) {
kfree(search_path);
return NULL;
}
strncpy(tmp_path, cifs_sb->tcon->treeName, l_max_len);
strcat(tmp_path, search_path);
tmp_path[l_max_len-1] = 0;
full_path = tmp_path;
kfree(search_path);
} else {
full_path = search_path;
}
return full_path;
}
static void *cifs_dfs_follow_mountpoint(struct dentry *dentry,
struct nameidata *nd)
{
DFS_INFO3_PARAM *referrals = NULL;
unsigned int num_referrals = 0;
struct cifs_sb_info *cifs_sb;
struct cifsSesInfo *ses;
char *full_path = NULL;
int xid, i;
int rc = 0;
struct vfsmount *mnt = ERR_PTR(-ENOENT);
cFYI(1, ("in %s", __FUNCTION__ ));
BUG_ON(IS_ROOT(dentry));
xid = GetXid();
dput(nd->dentry);
nd->dentry = dget(dentry);
if (d_mountpoint(nd->dentry)) {
goto out_follow;
}
if ( dentry->d_inode == NULL ) {
rc = -EINVAL;
goto out_err;
}
cifs_sb = CIFS_SB(dentry->d_inode->i_sb);
ses = cifs_sb->tcon->ses;
if ( !ses ) {
rc = -EINVAL;
goto out_err;
}
full_path = build_full_dfs_path_from_dentry(dentry);
if ( full_path == NULL ) {
rc = -ENOMEM;
goto out_err;
}
rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls,
&num_referrals, &referrals,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
for (i = 0; i < num_referrals; i++) {
cFYI(1, ("%s: ref path: %s", __FUNCTION__,
referrals[i].path_name));
cFYI(1, ("%s: node path: %s", __FUNCTION__,
referrals[i].node_name ));
cFYI(1, ("%s: fl: %hd, serv_type: %hd, ref_flags: %hd, "
"path_consumed: %hd", __FUNCTION__,
referrals[i].flags, referrals[i].server_type,
referrals[i].ref_flag, referrals[i].PathConsumed));
/* connect to storage node */
if (referrals[i].flags & DFSREF_STORAGE_SERVER) {
int len;
len = strlen(referrals[i].node_name);
if (len < 2) {
cERROR(1, ("%s: Net Address path too short: %s",
__FUNCTION__, referrals[i].node_name ));
rc = -EINVAL;
goto out_err;
} else {
mnt = cifs_dfs_do_refmount(nd->mnt,
nd->dentry,
referrals[i].node_name);
cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
__FUNCTION__,
referrals[i].node_name, mnt));
if ( !rc ) {
/* have server so stop here & return */
break;
}
}
}
}
rc = PTR_ERR(mnt);
if (IS_ERR(mnt))
goto out_err;
mntget(mnt);
rc = do_add_mount(mnt, nd, nd->mnt->mnt_flags,
&cifs_dfs_automount_list);
if (rc < 0) {
mntput(mnt);
if (rc == -EBUSY)
goto out_follow;
goto out_err;
}
mntput(nd->mnt);
dput(nd->dentry);
nd->mnt = mnt;
nd->dentry = dget(mnt->mnt_root);
out:
FreeXid(xid);
free_dfs_info_array(referrals, num_referrals);
cFYI(1, ("leaving %s", __FUNCTION__ ));
return ERR_PTR(rc);
out_err:
if ( full_path ) kfree(full_path);
path_release(nd);
goto out;
out_follow:
while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
;
rc = 0;
goto out;
}
struct inode_operations cifs_dfs_referral_inode_operations = {
.follow_link = cifs_dfs_follow_mountpoint,
};
#endif /* CONFIG_CIFS_EXPERIMENTAL */
#endif /* Kernel version 2.6.18 or higher */
\ No newline at end of file
...@@ -24,10 +24,12 @@ ...@@ -24,10 +24,12 @@
#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */ #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible*/
#define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */ #define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */
#define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */ #define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */
#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */ #define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */
#define CIFS_MOUNT_OVERR_UID 0x400 /* override uid returned from server */
#define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */
struct cifs_sb_info { struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */ struct cifsTconInfo *tcon; /* primary mount */
...@@ -41,6 +43,6 @@ struct cifs_sb_info { ...@@ -41,6 +43,6 @@ struct cifs_sb_info {
mode_t mnt_dir_mode; mode_t mnt_dir_mode;
int mnt_cifs_flags; int mnt_cifs_flags;
int prepathlen; int prepathlen;
char * prepath; char *prepath;
}; };
#endif /* _CIFS_FS_SB_H */ #endif /* _CIFS_FS_SB_H */
...@@ -66,7 +66,7 @@ cifs_strtoUCS(__le16 * to, const char *from, int len, ...@@ -66,7 +66,7 @@ cifs_strtoUCS(__le16 * to, const char *from, int len,
{ {
int charlen; int charlen;
int i; int i;
wchar_t * wchar_to = (wchar_t *)to; /* needed to quiet sparse */ wchar_t *wchar_to = (wchar_t *)to; /* needed to quiet sparse */
for (i = 0; len && *from; i++, from += charlen, len -= charlen) { for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Convert a unicode character to upper or lower case using * Convert a unicode character to upper or lower case using
* compressed tables. * compressed tables.
* *
* Copyright (c) International Business Machines Corp., 2000,2005555555555555555555555555555555555555555555555555555555 * Copyright (c) International Business Machines Corp., 2000,2007
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -58,15 +58,19 @@ extern signed char UniLowerTable[512]; ...@@ -58,15 +58,19 @@ extern signed char UniLowerTable[512];
extern struct UniCaseRange UniLowerRange[]; extern struct UniCaseRange UniLowerRange[];
#endif /* UNIUPR_NOLOWER */ #endif /* UNIUPR_NOLOWER */
#ifdef __KERNEL__
#ifndef __le16 #ifndef __le16
int cifs_strfromUCS_le(char *, const __u16 *, int, const struct nls_table *); #define __le16 __u16
int cifs_strtoUCS(__u16 *, const char *, int, const struct nls_table *); #define __le32 __u32
#else #define __le64 __u64
#define __be16 __u16
#define __be32 __u32
#define __be64 __u64
#endif
#ifdef __KERNEL__
int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *); int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *);
int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *);
#endif #endif
#endif
/* /*
* UniStrcat: Concatenate the second string to the first * UniStrcat: Concatenate the second string to the first
...@@ -75,7 +79,7 @@ int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); ...@@ -75,7 +79,7 @@ int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *);
* Address of the first string * Address of the first string
*/ */
static inline wchar_t * static inline wchar_t *
UniStrcat(wchar_t * ucs1, const wchar_t * ucs2) UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
{ {
wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */ wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
...@@ -93,7 +97,7 @@ UniStrcat(wchar_t * ucs1, const wchar_t * ucs2) ...@@ -93,7 +97,7 @@ UniStrcat(wchar_t * ucs1, const wchar_t * ucs2)
* or NULL if the character is not in the string * or NULL if the character is not in the string
*/ */
static inline wchar_t * static inline wchar_t *
UniStrchr(const wchar_t * ucs, wchar_t uc) UniStrchr(const wchar_t *ucs, wchar_t uc)
{ {
while ((*ucs != uc) && *ucs) while ((*ucs != uc) && *ucs)
ucs++; ucs++;
...@@ -112,7 +116,7 @@ UniStrchr(const wchar_t * ucs, wchar_t uc) ...@@ -112,7 +116,7 @@ UniStrchr(const wchar_t * ucs, wchar_t uc)
* > 0: First string is greater than second * > 0: First string is greater than second
*/ */
static inline int static inline int
UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2) UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
{ {
while ((*ucs1 == *ucs2) && *ucs1) { while ((*ucs1 == *ucs2) && *ucs1) {
ucs1++; ucs1++;
...@@ -125,7 +129,7 @@ UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2) ...@@ -125,7 +129,7 @@ UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2)
* UniStrcpy: Copy a string * UniStrcpy: Copy a string
*/ */
static inline wchar_t * static inline wchar_t *
UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2) UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
{ {
wchar_t *anchor = ucs1; /* save the start of result string */ wchar_t *anchor = ucs1; /* save the start of result string */
...@@ -137,7 +141,7 @@ UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2) ...@@ -137,7 +141,7 @@ UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2)
* UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes) * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
*/ */
static inline size_t static inline size_t
UniStrlen(const wchar_t * ucs1) UniStrlen(const wchar_t *ucs1)
{ {
int i = 0; int i = 0;
...@@ -147,10 +151,11 @@ UniStrlen(const wchar_t * ucs1) ...@@ -147,10 +151,11 @@ UniStrlen(const wchar_t * ucs1)
} }
/* /*
* UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a string (length limited) * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
* string (length limited)
*/ */
static inline size_t static inline size_t
UniStrnlen(const wchar_t * ucs1, int maxlen) UniStrnlen(const wchar_t *ucs1, int maxlen)
{ {
int i = 0; int i = 0;
...@@ -166,7 +171,7 @@ UniStrnlen(const wchar_t * ucs1, int maxlen) ...@@ -166,7 +171,7 @@ UniStrnlen(const wchar_t * ucs1, int maxlen)
* UniStrncat: Concatenate length limited string * UniStrncat: Concatenate length limited string
*/ */
static inline wchar_t * static inline wchar_t *
UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n) UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
{ {
wchar_t *anchor = ucs1; /* save pointer to string 1 */ wchar_t *anchor = ucs1; /* save pointer to string 1 */
...@@ -184,7 +189,7 @@ UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n) ...@@ -184,7 +189,7 @@ UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
* UniStrncmp: Compare length limited string * UniStrncmp: Compare length limited string
*/ */
static inline int static inline int
UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
{ {
if (!n) if (!n)
return 0; /* Null strings are equal */ return 0; /* Null strings are equal */
...@@ -199,7 +204,7 @@ UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) ...@@ -199,7 +204,7 @@ UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
* UniStrncmp_le: Compare length limited string - native to little-endian * UniStrncmp_le: Compare length limited string - native to little-endian
*/ */
static inline int static inline int
UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
{ {
if (!n) if (!n)
return 0; /* Null strings are equal */ return 0; /* Null strings are equal */
...@@ -214,7 +219,7 @@ UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) ...@@ -214,7 +219,7 @@ UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
* UniStrncpy: Copy length limited string with pad * UniStrncpy: Copy length limited string with pad
*/ */
static inline wchar_t * static inline wchar_t *
UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n) UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
{ {
wchar_t *anchor = ucs1; wchar_t *anchor = ucs1;
...@@ -231,7 +236,7 @@ UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n) ...@@ -231,7 +236,7 @@ UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
* UniStrncpy_le: Copy length limited string with pad to little-endian * UniStrncpy_le: Copy length limited string with pad to little-endian
*/ */
static inline wchar_t * static inline wchar_t *
UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n) UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
{ {
wchar_t *anchor = ucs1; wchar_t *anchor = ucs1;
...@@ -252,7 +257,7 @@ UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n) ...@@ -252,7 +257,7 @@ UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
* NULL if no matching string is found * NULL if no matching string is found
*/ */
static inline wchar_t * static inline wchar_t *
UniStrstr(const wchar_t * ucs1, const wchar_t * ucs2) UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
{ {
const wchar_t *anchor1 = ucs1; const wchar_t *anchor1 = ucs1;
const wchar_t *anchor2 = ucs2; const wchar_t *anchor2 = ucs2;
...@@ -302,7 +307,7 @@ UniToupper(register wchar_t uc) ...@@ -302,7 +307,7 @@ UniToupper(register wchar_t uc)
* UniStrupr: Upper case a unicode string * UniStrupr: Upper case a unicode string
*/ */
static inline wchar_t * static inline wchar_t *
UniStrupr(register wchar_t * upin) UniStrupr(register wchar_t *upin)
{ {
register wchar_t *up; register wchar_t *up;
...@@ -343,7 +348,7 @@ UniTolower(wchar_t uc) ...@@ -343,7 +348,7 @@ UniTolower(wchar_t uc)
* UniStrlwr: Lower case a unicode string * UniStrlwr: Lower case a unicode string
*/ */
static inline wchar_t * static inline wchar_t *
UniStrlwr(register wchar_t * upin) UniStrlwr(register wchar_t *upin)
{ {
register wchar_t *up; register wchar_t *up;
......
...@@ -31,8 +31,8 @@ struct cifs_sid { ...@@ -31,8 +31,8 @@ struct cifs_sid {
} __attribute__((packed)); } __attribute__((packed));
/* everyone */ /* everyone */
extern const struct cifs_sid sid_everyone; /* extern const struct cifs_sid sid_everyone;*/
/* group users */ /* group users */
extern const struct cifs_sid sid_user; /* extern const struct cifs_sid sid_user;*/
#endif /* _CIFSACL_H */ #endif /* _CIFSACL_H */
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/random.h> #include <linux/random.h>
/* Calculate and return the CIFS signature based on the mac key and the smb pdu */ /* Calculate and return the CIFS signature based on the mac key and SMB PDU */
/* the 16 byte signature must be allocated by the caller */ /* the 16 byte signature must be allocated by the caller */
/* Note we only use the 1st eight bytes */ /* Note we only use the 1st eight bytes */
/* Note that the smb header signature field on input contains the /* Note that the smb header signature field on input contains the
...@@ -40,43 +40,46 @@ extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); ...@@ -40,43 +40,46 @@ extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24); unsigned char *p24);
static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
const char * key, char * signature) const struct mac_key *key, char *signature)
{ {
struct MD5Context context; struct MD5Context context;
if((cifs_pdu == NULL) || (signature == NULL)) if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL))
return -EINVAL; return -EINVAL;
MD5Init(&context); MD5Init(&context);
MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); MD5Update(&context, (char *)&key->data, key->len);
MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); MD5Update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length);
MD5Final(signature,&context);
MD5Final(signature, &context);
return 0; return 0;
} }
int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server, int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
__u32 * pexpected_response_sequence_number) __u32 *pexpected_response_sequence_number)
{ {
int rc = 0; int rc = 0;
char smb_signature[20]; char smb_signature[20];
if((cifs_pdu == NULL) || (server == NULL)) if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL; return -EINVAL;
if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
return rc; return rc;
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number); cifs_pdu->Signature.Sequence.SequenceNumber =
cpu_to_le32(server->sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0; cifs_pdu->Signature.Sequence.Reserved = 0;
*pexpected_response_sequence_number = server->sequence_number++; *pexpected_response_sequence_number = server->sequence_number++;
server->sequence_number++; server->sequence_number++;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature); rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key,
if(rc) smb_signature);
if (rc)
memset(cifs_pdu->Signature.SecuritySignature, 0, 8); memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
else else
memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
...@@ -84,50 +87,51 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server, ...@@ -84,50 +87,51 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
return rc; return rc;
} }
static int cifs_calc_signature2(const struct kvec * iov, int n_vec, static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
const char * key, char * signature) const struct mac_key *key, char *signature)
{ {
struct MD5Context context; struct MD5Context context;
int i; int i;
if((iov == NULL) || (signature == NULL)) if ((iov == NULL) || (signature == NULL) || (key == NULL))
return -EINVAL; return -EINVAL;
MD5Init(&context); MD5Init(&context);
MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); MD5Update(&context, (char *)&key->data, key->len);
for(i=0;i<n_vec;i++) { for (i = 0; i < n_vec; i++) {
if(iov[i].iov_base == NULL) { if (iov[i].iov_base == NULL) {
cERROR(1,("null iovec entry")); cERROR(1, ("null iovec entry"));
return -EIO; return -EIO;
} else if(iov[i].iov_len == 0) } else if (iov[i].iov_len == 0)
break; /* bail out if we are sent nothing to sign */ break; /* bail out if we are sent nothing to sign */
/* The first entry includes a length field (which does not get /* The first entry includes a length field (which does not get
signed that occupies the first 4 bytes before the header */ signed that occupies the first 4 bytes before the header */
if(i==0) { if (i == 0) {
if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */ if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */
break; /* nothing to sign or corrupt header */ break; /* nothing to sign or corrupt header */
MD5Update(&context,iov[0].iov_base+4, iov[0].iov_len-4); MD5Update(&context, iov[0].iov_base+4,
iov[0].iov_len-4);
} else } else
MD5Update(&context,iov[i].iov_base, iov[i].iov_len); MD5Update(&context, iov[i].iov_base, iov[i].iov_len);
} }
MD5Final(signature,&context); MD5Final(signature, &context);
return 0; return 0;
} }
int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server, int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
__u32 * pexpected_response_sequence_number) __u32 * pexpected_response_sequence_number)
{ {
int rc = 0; int rc = 0;
char smb_signature[20]; char smb_signature[20];
struct smb_hdr * cifs_pdu = iov[0].iov_base; struct smb_hdr *cifs_pdu = iov[0].iov_base;
if((cifs_pdu == NULL) || (server == NULL)) if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL; return -EINVAL;
if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
return rc; return rc;
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
...@@ -139,60 +143,63 @@ int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server, ...@@ -139,60 +143,63 @@ int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server,
server->sequence_number++; server->sequence_number++;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
rc = cifs_calc_signature2(iov, n_vec, server->mac_signing_key, rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key,
smb_signature); smb_signature);
if(rc) if (rc)
memset(cifs_pdu->Signature.SecuritySignature, 0, 8); memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
else else
memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
return rc; return rc;
} }
int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, int cifs_verify_signature(struct smb_hdr *cifs_pdu,
const struct mac_key *mac_key,
__u32 expected_sequence_number) __u32 expected_sequence_number)
{ {
unsigned int rc; unsigned int rc;
char server_response_sig[8]; char server_response_sig[8];
char what_we_think_sig_should_be[20]; char what_we_think_sig_should_be[20];
if((cifs_pdu == NULL) || (mac_key == NULL)) if ((cifs_pdu == NULL) || (mac_key == NULL))
return -EINVAL; return -EINVAL;
if (cifs_pdu->Command == SMB_COM_NEGOTIATE) if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
return 0; return 0;
if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu; struct smb_com_lock_req *pSMB =
if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) (struct smb_com_lock_req *)cifs_pdu;
if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
return 0; return 0;
} }
/* BB what if signatures are supposed to be on for session but server does not /* BB what if signatures are supposed to be on for session but
send one? BB */ server does not send one? BB */
/* Do not need to verify session setups with signature "BSRSPYL " */ /* Do not need to verify session setups with signature "BSRSPYL " */
if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0) if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command)); cFYI(1, ("dummy signature received for smb command 0x%x",
cifs_pdu->Command));
/* save off the origiginal signature so we can modify the smb and check /* save off the origiginal signature so we can modify the smb and check
its signature against what the server sent */ its signature against what the server sent */
memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8); memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(expected_sequence_number); cifs_pdu->Signature.Sequence.SequenceNumber =
cpu_to_le32(expected_sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0; cifs_pdu->Signature.Sequence.Reserved = 0;
rc = cifs_calculate_signature(cifs_pdu, mac_key, rc = cifs_calculate_signature(cifs_pdu, mac_key,
what_we_think_sig_should_be); what_we_think_sig_should_be);
if(rc) if (rc)
return rc; return rc;
/* cifs_dump_mem("what we think it should be: ",
what_we_think_sig_should_be, 16); */
/* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */ if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
if(memcmp(server_response_sig, what_we_think_sig_should_be, 8))
return -EACCES; return -EACCES;
else else
return 0; return 0;
...@@ -200,89 +207,94 @@ int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, ...@@ -200,89 +207,94 @@ int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
} }
/* We fill in key by putting in 40 byte array which was allocated by caller */ /* We fill in key by putting in 40 byte array which was allocated by caller */
int cifs_calculate_mac_key(char * key, const char * rn, const char * password) int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
const char *password)
{ {
char temp_key[16]; char temp_key[16];
if ((key == NULL) || (rn == NULL)) if ((key == NULL) || (rn == NULL))
return -EINVAL; return -EINVAL;
E_md4hash(password, temp_key); E_md4hash(password, temp_key);
mdfour(key,temp_key,16); mdfour(key->data.ntlm, temp_key, 16);
memcpy(key+16,rn, CIFS_SESS_KEY_SIZE); memcpy(key->data.ntlm+16, rn, CIFS_SESS_KEY_SIZE);
key->len = 40;
return 0; return 0;
} }
int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses,
const struct nls_table * nls_info) const struct nls_table *nls_info)
{ {
char temp_hash[16]; char temp_hash[16];
struct HMACMD5Context ctx; struct HMACMD5Context ctx;
char * ucase_buf; char *ucase_buf;
__le16 * unicode_buf; __le16 *unicode_buf;
unsigned int i,user_name_len,dom_name_len; unsigned int i, user_name_len, dom_name_len;
if(ses == NULL) if (ses == NULL)
return -EINVAL; return -EINVAL;
E_md4hash(ses->password, temp_hash); E_md4hash(ses->password, temp_hash);
hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); hmac_md5_init_limK_to_64(temp_hash, 16, &ctx);
user_name_len = strlen(ses->userName); user_name_len = strlen(ses->userName);
if(user_name_len > MAX_USERNAME_SIZE) if (user_name_len > MAX_USERNAME_SIZE)
return -EINVAL; return -EINVAL;
if(ses->domainName == NULL) if (ses->domainName == NULL)
return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ return -EINVAL; /* BB should we use CIFS_LINUX_DOM */
dom_name_len = strlen(ses->domainName); dom_name_len = strlen(ses->domainName);
if(dom_name_len > MAX_USERNAME_SIZE) if (dom_name_len > MAX_USERNAME_SIZE)
return -EINVAL; return -EINVAL;
ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL);
if(ucase_buf == NULL) if (ucase_buf == NULL)
return -ENOMEM; return -ENOMEM;
unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL);
if(unicode_buf == NULL) { if (unicode_buf == NULL) {
kfree(ucase_buf); kfree(ucase_buf);
return -ENOMEM; return -ENOMEM;
} }
for(i=0;i<user_name_len;i++) for (i = 0; i < user_name_len; i++)
ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]]; ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]];
ucase_buf[i] = 0; ucase_buf[i] = 0;
user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf,
MAX_USERNAME_SIZE*2, nls_info);
unicode_buf[user_name_len] = 0; unicode_buf[user_name_len] = 0;
user_name_len++; user_name_len++;
for(i=0;i<dom_name_len;i++) for (i = 0; i < dom_name_len; i++)
ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]]; ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]];
ucase_buf[i] = 0; ucase_buf[i] = 0;
dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf,
MAX_USERNAME_SIZE*2, nls_info);
unicode_buf[user_name_len + dom_name_len] = 0; unicode_buf[user_name_len + dom_name_len] = 0;
hmac_md5_update((const unsigned char *) unicode_buf, hmac_md5_update((const unsigned char *) unicode_buf,
(user_name_len+dom_name_len)*2,&ctx); (user_name_len+dom_name_len)*2, &ctx);
hmac_md5_final(ses->server->mac_signing_key,&ctx); hmac_md5_final(ses->server->ntlmv2_hash, &ctx);
kfree(ucase_buf); kfree(ucase_buf);
kfree(unicode_buf); kfree(unicode_buf);
return 0; return 0;
} }
#ifdef CONFIG_CIFS_WEAK_PW_HASH #ifdef CONFIG_CIFS_WEAK_PW_HASH
void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
{ {
int i; int i;
char password_with_pad[CIFS_ENCPWD_SIZE]; char password_with_pad[CIFS_ENCPWD_SIZE];
if(ses->server == NULL) if (ses->server == NULL)
return; return;
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
if(ses->password) if (ses->password)
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
if(extended_security & CIFSSEC_MAY_PLNTXT) { if (extended_security & CIFSSEC_MAY_PLNTXT) {
memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); memcpy(lnm_session_key, password_with_pad,
CIFS_ENCPWD_SIZE);
return; return;
} }
...@@ -297,7 +309,7 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) ...@@ -297,7 +309,7 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
utf8 and other multibyte codepages each need their own strupper utf8 and other multibyte codepages each need their own strupper
function since a byte at a time will ont work. */ function since a byte at a time will ont work. */
for(i = 0; i < CIFS_ENCPWD_SIZE; i++) { for (i = 0; i < CIFS_ENCPWD_SIZE; i++) {
password_with_pad[i] = toupper(password_with_pad[i]); password_with_pad[i] = toupper(password_with_pad[i]);
} }
...@@ -308,18 +320,18 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) ...@@ -308,18 +320,18 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
#endif /* CIFS_WEAK_PW_HASH */ #endif /* CIFS_WEAK_PW_HASH */
static int calc_ntlmv2_hash(struct cifsSesInfo *ses, static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
const struct nls_table * nls_cp) const struct nls_table *nls_cp)
{ {
int rc = 0; int rc = 0;
int len; int len;
char nt_hash[16]; char nt_hash[16];
struct HMACMD5Context * pctxt; struct HMACMD5Context *pctxt;
wchar_t * user; wchar_t *user;
wchar_t * domain; wchar_t *domain;
pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL);
if(pctxt == NULL) if (pctxt == NULL)
return -ENOMEM; return -ENOMEM;
/* calculate md4 hash of password */ /* calculate md4 hash of password */
...@@ -331,21 +343,24 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, ...@@ -331,21 +343,24 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
/* convert ses->userName to unicode and uppercase */ /* convert ses->userName to unicode and uppercase */
len = strlen(ses->userName); len = strlen(ses->userName);
user = kmalloc(2 + (len * 2), GFP_KERNEL); user = kmalloc(2 + (len * 2), GFP_KERNEL);
if(user == NULL) if (user == NULL)
goto calc_exit_2; goto calc_exit_2;
len = cifs_strtoUCS(user, ses->userName, len, nls_cp); len = cifs_strtoUCS(user, ses->userName, len, nls_cp);
UniStrupr(user); UniStrupr(user);
hmac_md5_update((char *)user, 2*len, pctxt); hmac_md5_update((char *)user, 2*len, pctxt);
/* convert ses->domainName to unicode and uppercase */ /* convert ses->domainName to unicode and uppercase */
if(ses->domainName) { if (ses->domainName) {
len = strlen(ses->domainName); len = strlen(ses->domainName);
domain = kmalloc(2 + (len * 2), GFP_KERNEL); domain = kmalloc(2 + (len * 2), GFP_KERNEL);
if(domain == NULL) if (domain == NULL)
goto calc_exit_1; goto calc_exit_1;
len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp); len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp);
UniStrupr(domain); /* the following line was removed since it didn't work well
with lower cased domain name that passed as an option.
Maybe converting the domain name earlier makes sense */
/* UniStrupr(domain); */
hmac_md5_update((char *)domain, 2*len, pctxt); hmac_md5_update((char *)domain, 2*len, pctxt);
...@@ -356,16 +371,17 @@ calc_exit_1: ...@@ -356,16 +371,17 @@ calc_exit_1:
calc_exit_2: calc_exit_2:
/* BB FIXME what about bytes 24 through 40 of the signing key? /* BB FIXME what about bytes 24 through 40 of the signing key?
compare with the NTLM example */ compare with the NTLM example */
hmac_md5_final(ses->server->mac_signing_key, pctxt); hmac_md5_final(ses->server->ntlmv2_hash, pctxt);
return rc; return rc;
} }
void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
const struct nls_table * nls_cp) const struct nls_table *nls_cp)
{ {
int rc; int rc;
struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf;
struct HMACMD5Context context;
buf->blob_signature = cpu_to_le32(0x00000101); buf->blob_signature = cpu_to_le32(0x00000101);
buf->reserved = 0; buf->reserved = 0;
...@@ -379,21 +395,31 @@ void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, ...@@ -379,21 +395,31 @@ void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf,
/* calculate buf->ntlmv2_hash */ /* calculate buf->ntlmv2_hash */
rc = calc_ntlmv2_hash(ses, nls_cp); rc = calc_ntlmv2_hash(ses, nls_cp);
if(rc) if (rc)
cERROR(1,("could not get v2 hash rc %d",rc)); cERROR(1, ("could not get v2 hash rc %d", rc));
CalcNTLMv2_response(ses, resp_buf); CalcNTLMv2_response(ses, resp_buf);
/* now calculate the MAC key for NTLMv2 */
hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
hmac_md5_update(resp_buf, 16, &context);
hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context);
memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf,
sizeof(struct ntlmv2_resp));
ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp);
} }
void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response) void CalcNTLMv2_response(const struct cifsSesInfo *ses,
char *v2_session_response)
{ {
struct HMACMD5Context context; struct HMACMD5Context context;
/* rest of v2 struct already generated */ /* rest of v2 struct already generated */
memcpy(v2_session_response + 8, ses->server->cryptKey,8); memcpy(v2_session_response + 8, ses->server->cryptKey, 8);
hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context); hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
hmac_md5_update(v2_session_response+8, hmac_md5_update(v2_session_response+8,
sizeof(struct ntlmv2_resp) - 8, &context); sizeof(struct ntlmv2_resp) - 8, &context);
hmac_md5_final(v2_session_response,&context); hmac_md5_final(v2_session_response, &context);
/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
} }
...@@ -27,8 +27,6 @@ extern void mdfour(unsigned char *out, unsigned char *in, int n); ...@@ -27,8 +27,6 @@ extern void mdfour(unsigned char *out, unsigned char *in, int n);
/* smbdes.c */ /* smbdes.c */
extern void E_P16(unsigned char *p14, unsigned char *p16); extern void E_P16(unsigned char *p14, unsigned char *p16);
extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24); extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
extern void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
extern void E_old_pw_hash(unsigned char *, unsigned char *, unsigned char *);
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/mempool.h> #include <linux/mempool.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/kthread.h>
#include "cifsfs.h" #include "cifsfs.h"
#include "cifspdu.h" #include "cifspdu.h"
#define DECLARE_GLOBALS_HERE #define DECLARE_GLOBALS_HERE
...@@ -68,31 +69,33 @@ unsigned int multiuser_mount = 0; ...@@ -68,31 +69,33 @@ unsigned int multiuser_mount = 0;
unsigned int extended_security = CIFSSEC_DEF; unsigned int extended_security = CIFSSEC_DEF;
/* unsigned int ntlmv2_support = 0; */ /* unsigned int ntlmv2_support = 0; */
unsigned int sign_CIFS_PDUs = 1; unsigned int sign_CIFS_PDUs = 1;
extern struct task_struct * oplockThread; /* remove sparse warning */ extern struct task_struct *oplockThread; /* remove sparse warning */
struct task_struct * oplockThread = NULL; struct task_struct *oplockThread = NULL;
/* extern struct task_struct * dnotifyThread; remove sparse warning */ /* extern struct task_struct * dnotifyThread; remove sparse warning */
static struct task_struct * dnotifyThread = NULL; static struct task_struct *dnotifyThread = NULL;
static const struct super_operations cifs_super_ops;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
module_param(CIFSMaxBufSize, int, 0); module_param(CIFSMaxBufSize, int, 0);
MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header). "
"Default: 16384 Range: 8192 to 130048");
unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL; unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL;
module_param(cifs_min_rcv, int, 0); module_param(cifs_min_rcv, int, 0);
MODULE_PARM_DESC(cifs_min_rcv,"Network buffers in pool. Default: 4 Range: 1 to 64"); MODULE_PARM_DESC(cifs_min_rcv, "Network buffers in pool. Default: 4 Range: "
"1 to 64");
unsigned int cifs_min_small = 30; unsigned int cifs_min_small = 30;
module_param(cifs_min_small, int, 0); module_param(cifs_min_small, int, 0);
MODULE_PARM_DESC(cifs_min_small,"Small network buffers in pool. Default: 30 Range: 2 to 256"); MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
"Range: 2 to 256");
unsigned int cifs_max_pending = CIFS_MAX_REQ; unsigned int cifs_max_pending = CIFS_MAX_REQ;
module_param(cifs_max_pending, int, 0); module_param(cifs_max_pending, int, 0);
MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
"Default: 50 Range: 2 to 256");
static DECLARE_COMPLETION(cifs_oplock_exited);
static DECLARE_COMPLETION(cifs_dnotify_exited);
extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_req_poolp;
extern mempool_t *cifs_mid_poolp; extern mempool_t *cifs_mid_poolp;
extern kmem_cache_t *cifs_oplock_cachep; extern struct kmem_cache *cifs_oplock_cachep;
static int static int
cifs_read_super(struct super_block *sb, void *data, cifs_read_super(struct super_block *sb, void *data,
...@@ -104,9 +107,9 @@ cifs_read_super(struct super_block *sb, void *data, ...@@ -104,9 +107,9 @@ cifs_read_super(struct super_block *sb, void *data,
/* BB should we make this contingent on mount parm? */ /* BB should we make this contingent on mount parm? */
sb->s_flags |= MS_NODIRATIME | MS_NOATIME; sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info),GFP_KERNEL); sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
cifs_sb = CIFS_SB(sb); cifs_sb = CIFS_SB(sb);
if(cifs_sb == NULL) if (cifs_sb == NULL)
return -ENOMEM; return -ENOMEM;
rc = cifs_mount(sb, cifs_sb, data, devname); rc = cifs_mount(sb, cifs_sb, data, devname);
...@@ -120,12 +123,9 @@ cifs_read_super(struct super_block *sb, void *data, ...@@ -120,12 +123,9 @@ cifs_read_super(struct super_block *sb, void *data,
sb->s_magic = CIFS_MAGIC_NUMBER; sb->s_magic = CIFS_MAGIC_NUMBER;
sb->s_op = &cifs_super_ops; sb->s_op = &cifs_super_ops;
#ifdef CONFIG_CIFS_EXPERIMENTAL /* if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
if(experimEnabled != 0) sb->s_blocksize =
sb->s_export_op = &cifs_export_ops; cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
#endif /* EXPERIMENTAL */
/* 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; */
#ifdef CONFIG_CIFS_QUOTA #ifdef CONFIG_CIFS_QUOTA
sb->s_qcop = &cifs_quotactl_ops; sb->s_qcop = &cifs_quotactl_ops;
#endif #endif
...@@ -145,6 +145,13 @@ cifs_read_super(struct super_block *sb, void *data, ...@@ -145,6 +145,13 @@ cifs_read_super(struct super_block *sb, void *data,
goto out_no_root; goto out_no_root;
} }
#ifdef CONFIG_CIFS_EXPERIMENTAL
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
cFYI(1, ("export ops supported"));
sb->s_export_op = &cifs_export_ops;
}
#endif /* EXPERIMENTAL */
return 0; return 0;
out_no_root: out_no_root:
...@@ -153,8 +160,8 @@ out_no_root: ...@@ -153,8 +160,8 @@ out_no_root:
iput(inode); iput(inode);
out_mount_failed: out_mount_failed:
if(cifs_sb) { if (cifs_sb) {
if(cifs_sb->local_nls) if (cifs_sb->local_nls)
unload_nls(cifs_sb->local_nls); unload_nls(cifs_sb->local_nls);
kfree(cifs_sb); kfree(cifs_sb);
} }
...@@ -169,8 +176,8 @@ cifs_put_super(struct super_block *sb) ...@@ -169,8 +176,8 @@ cifs_put_super(struct super_block *sb)
cFYI(1, ("In cifs_put_super")); cFYI(1, ("In cifs_put_super"));
cifs_sb = CIFS_SB(sb); cifs_sb = CIFS_SB(sb);
if(cifs_sb == NULL) { if (cifs_sb == NULL) {
cFYI(1,("Empty cifs superblock info passed to unmount")); cFYI(1, ("Empty cifs superblock info passed to unmount"));
return; return;
} }
rc = cifs_umount(sb, cifs_sb); rc = cifs_umount(sb, cifs_sb);
...@@ -182,7 +189,7 @@ cifs_put_super(struct super_block *sb) ...@@ -182,7 +189,7 @@ cifs_put_super(struct super_block *sb)
return; return;
} }
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15)
void * kzalloc(size_t size, unsigned flgs) void * kzalloc(size_t size, unsigned flgs)
{ {
void * buf; void * buf;
...@@ -199,6 +206,13 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -199,6 +206,13 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
{ {
struct super_block *sb = dentry->d_sb; struct super_block *sb = dentry->d_sb;
#else #else
static inline mempool_t *
mempool_create_slab_pool(int min_nr, struct kmem_cache *kc)
{
return mempool_create(min_nr, mempool_alloc_slab, mempool_free_slab,
(void *) kc);
}
static int static int
cifs_statfs(struct super_block *sb, struct kstatfs *buf) cifs_statfs(struct super_block *sb, struct kstatfs *buf)
{ {
...@@ -231,17 +245,16 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) ...@@ -231,17 +245,16 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
/* Only need to call the old QFSInfo if failed /* Only need to call the old QFSInfo if failed
on newer one */ on newer one */
if(rc) if (rc)
if(pTcon->ses->capabilities & CAP_NT_SMBS) if (pTcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */ rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */
/* Some old Windows servers also do not support level 103, retry with /* Some old Windows servers also do not support level 103, retry with
older level one if old server failed the previous call or we older level one if old server failed the previous call or we
bypassed it because we detected that this was an older LANMAN sess */ bypassed it because we detected that this was an older LANMAN sess */
if(rc) if (rc)
rc = SMBOldQFSInfo(xid, pTcon, buf); rc = SMBOldQFSInfo(xid, pTcon, buf);
/* /* int f_type;
int f_type;
__fsid_t f_fsid; __fsid_t f_fsid;
int f_namelen; */ int f_namelen; */
/* BB get from info in tcon struct at mount time call to QFSAttrInfo */ /* BB get from info in tcon struct at mount time call to QFSAttrInfo */
...@@ -250,15 +263,15 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) ...@@ -250,15 +263,15 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
longer available? */ longer available? */
} }
static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd) static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd)
{ {
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
return 0; return 0;
} else /* file mode might have been restricted at mount time else /* file mode might have been restricted at mount time
on the client (above and beyond ACL on servers) for on the client (above and beyond ACL on servers) for
servers which do not support setting and viewing mode bits, servers which do not support setting and viewing mode bits,
so allowing client to check permissions is useful */ so allowing client to check permissions is useful */
...@@ -266,14 +279,14 @@ static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd) ...@@ -266,14 +279,14 @@ static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd)
return vfs_permission(inode, mask); return vfs_permission(inode, mask);
#else #else
return generic_permission(inode, mask, NULL); return generic_permission(inode, mask, NULL);
#endif /* LINUX version */ #endif
} }
static kmem_cache_t *cifs_inode_cachep; static struct kmem_cache *cifs_inode_cachep;
static kmem_cache_t *cifs_req_cachep; static struct kmem_cache *cifs_req_cachep;
static kmem_cache_t *cifs_mid_cachep; static struct kmem_cache *cifs_mid_cachep;
kmem_cache_t *cifs_oplock_cachep; struct kmem_cache *cifs_oplock_cachep;
static kmem_cache_t *cifs_sm_req_cachep; static struct kmem_cache *cifs_sm_req_cachep;
mempool_t *cifs_sm_req_poolp; mempool_t *cifs_sm_req_poolp;
mempool_t *cifs_req_poolp; mempool_t *cifs_req_poolp;
mempool_t *cifs_mid_poolp; mempool_t *cifs_mid_poolp;
...@@ -282,7 +295,7 @@ static struct inode * ...@@ -282,7 +295,7 @@ static struct inode *
cifs_alloc_inode(struct super_block *sb) cifs_alloc_inode(struct super_block *sb)
{ {
struct cifsInodeInfo *cifs_inode; struct cifsInodeInfo *cifs_inode;
cifs_inode = kmem_cache_alloc(cifs_inode_cachep, SLAB_KERNEL); cifs_inode = kmem_cache_alloc(cifs_inode_cachep, GFP_KERNEL);
if (!cifs_inode) if (!cifs_inode)
return NULL; return NULL;
cifs_inode->cifsAttrs = 0x20; /* default */ cifs_inode->cifsAttrs = 0x20; /* default */
...@@ -293,7 +306,7 @@ cifs_alloc_inode(struct super_block *sb) ...@@ -293,7 +306,7 @@ cifs_alloc_inode(struct super_block *sb)
file data or metadata */ file data or metadata */
cifs_inode->clientCanCacheRead = FALSE; cifs_inode->clientCanCacheRead = FALSE;
cifs_inode->clientCanCacheAll = FALSE; cifs_inode->clientCanCacheAll = FALSE;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE;
#endif #endif
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
...@@ -331,59 +344,67 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) ...@@ -331,59 +344,67 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
if (cifs_sb->tcon->ses->userName) if (cifs_sb->tcon->ses->userName)
seq_printf(s, ",username=%s", seq_printf(s, ",username=%s",
cifs_sb->tcon->ses->userName); cifs_sb->tcon->ses->userName);
if(cifs_sb->tcon->ses->domainName) if (cifs_sb->tcon->ses->domainName)
seq_printf(s, ",domain=%s", seq_printf(s, ",domain=%s",
cifs_sb->tcon->ses->domainName); cifs_sb->tcon->ses->domainName);
} }
} }
seq_printf(s, ",rsize=%d",cifs_sb->rsize); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
seq_printf(s, ",wsize=%d",cifs_sb->wsize); seq_printf(s, ",posixpaths");
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
!(cifs_sb->tcon->unix_ext))
seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
!(cifs_sb->tcon->unix_ext))
seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
seq_printf(s, ",rsize=%d", cifs_sb->rsize);
seq_printf(s, ",wsize=%d", cifs_sb->wsize);
} }
return 0; return 0;
} }
#ifdef CONFIG_CIFS_QUOTA #ifdef CONFIG_CIFS_QUOTA
int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid, int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid,
struct fs_disk_quota * pdquota) struct fs_disk_quota *pdquota)
{ {
int xid; int xid;
int rc = 0; int rc = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
if(cifs_sb) if (cifs_sb)
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
else else
return -EIO; return -EIO;
xid = GetXid(); xid = GetXid();
if(pTcon) { if (pTcon) {
cFYI(1,("set type: 0x%x id: %d",quota_type,qid)); cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
} else { } else {
return -EIO; rc = -EIO;
} }
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid, int cifs_xquota_get(struct super_block *sb, int quota_type, qid_t qid,
struct fs_disk_quota * pdquota) struct fs_disk_quota *pdquota)
{ {
int xid; int xid;
int rc = 0; int rc = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
if(cifs_sb) if (cifs_sb)
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
else else
return -EIO; return -EIO;
xid = GetXid(); xid = GetXid();
if(pTcon) { if (pTcon) {
cFYI(1,("set type: 0x%x id: %d",quota_type,qid)); cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
} else { } else {
rc = -EIO; rc = -EIO;
} }
...@@ -392,21 +413,21 @@ int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid, ...@@ -392,21 +413,21 @@ int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid,
return rc; return rc;
} }
int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation) int cifs_xstate_set(struct super_block *sb, unsigned int flags, int operation)
{ {
int xid; int xid;
int rc = 0; int rc = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
if(cifs_sb) if (cifs_sb)
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
else else
return -EIO; return -EIO;
xid = GetXid(); xid = GetXid();
if(pTcon) { if (pTcon) {
cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation)); cFYI(1, ("flags: 0x%x operation: 0x%x", flags, operation));
} else { } else {
rc = -EIO; rc = -EIO;
} }
...@@ -415,21 +436,21 @@ int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation) ...@@ -415,21 +436,21 @@ int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation)
return rc; return rc;
} }
int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats) int cifs_xstate_get(struct super_block *sb, struct fs_quota_stat *qstats)
{ {
int xid; int xid;
int rc = 0; int rc = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
if(cifs_sb) { if (cifs_sb) {
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
} else { } else {
return -EIO; return -EIO;
} }
xid = GetXid(); xid = GetXid();
if(pTcon) { if (pTcon) {
cFYI(1,("pqstats %p",qstats)); cFYI(1, ("pqstats %p", qstats));
} else { } else {
rc = -EIO; rc = -EIO;
} }
...@@ -447,13 +468,13 @@ static struct quotactl_ops cifs_quotactl_ops = { ...@@ -447,13 +468,13 @@ static struct quotactl_ops cifs_quotactl_ops = {
#endif #endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 16) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 16)
static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags) static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags)
#else #else
static void cifs_umount_begin(struct super_block * sblock) static void cifs_umount_begin(struct super_block * sblock)
#endif #endif
{ {
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo * tcon; struct cifsTconInfo *tcon;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 16) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 16)
if (!(flags & MNT_FORCE)) if (!(flags & MNT_FORCE))
...@@ -462,11 +483,11 @@ static void cifs_umount_begin(struct super_block * sblock) ...@@ -462,11 +483,11 @@ static void cifs_umount_begin(struct super_block * sblock)
#else #else
cifs_sb = CIFS_SB(sblock); cifs_sb = CIFS_SB(sblock);
#endif #endif
if(cifs_sb == NULL) if (cifs_sb == NULL)
return; return;
tcon = cifs_sb->tcon; tcon = cifs_sb->tcon;
if(tcon == NULL) if (tcon == NULL)
return; return;
down(&tcon->tconSem); down(&tcon->tconSem);
if (atomic_read(&tcon->useCount) == 1) if (atomic_read(&tcon->useCount) == 1)
...@@ -475,9 +496,8 @@ static void cifs_umount_begin(struct super_block * sblock) ...@@ -475,9 +496,8 @@ static void cifs_umount_begin(struct super_block * sblock)
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
/* cancel_notify_requests(tcon); */ /* cancel_notify_requests(tcon); */
if(tcon->ses && tcon->ses->server) if (tcon->ses && tcon->ses->server) {
{ cFYI(1, ("wake up tasks now - umount begin not complete"));
cFYI(1,("wake up tasks now - umount begin not complete"));
wake_up_all(&tcon->ses->server->request_q); wake_up_all(&tcon->ses->server->request_q);
wake_up_all(&tcon->ses->server->response_q); wake_up_all(&tcon->ses->server->response_q);
msleep(1); /* yield */ msleep(1); /* yield */
...@@ -490,27 +510,46 @@ static void cifs_umount_begin(struct super_block * sblock) ...@@ -490,27 +510,46 @@ static void cifs_umount_begin(struct super_block * sblock)
return; return;
} }
#ifdef CONFIG_CIFS_STATS2
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)
static int cifs_show_stats(struct seq_file *s, struct vfsmount *mnt)
{
/* BB FIXME */
return 0;
}
#endif
#endif
static int cifs_remount(struct super_block *sb, int *flags, char *data) static int cifs_remount(struct super_block *sb, int *flags, char *data)
{ {
*flags |= MS_NODIRATIME; *flags |= MS_NODIRATIME;
return 0; return 0;
} }
struct super_operations cifs_super_ops = { static const struct super_operations cifs_super_ops = {
.read_inode = cifs_read_inode, .read_inode = cifs_read_inode,
.put_super = cifs_put_super, .put_super = cifs_put_super,
.statfs = cifs_statfs, .statfs = cifs_statfs,
.alloc_inode = cifs_alloc_inode, .alloc_inode = cifs_alloc_inode,
.destroy_inode = cifs_destroy_inode, .destroy_inode = cifs_destroy_inode,
/* .drop_inode = generic_delete_inode, /* .drop_inode = generic_delete_inode,
.delete_inode = cifs_delete_inode, *//* Do not need the above two functions .delete_inode = cifs_delete_inode, */ /* Do not need above two
unless later we add lazy close of inodes or unless the kernel forgets to call functions unless later we add lazy close of inodes or unless the
us with the same number of releases (closes) as opens */ kernel forgets to call us with the same number of releases (closes)
as opens */
.show_options = cifs_show_options, .show_options = cifs_show_options,
.umount_begin = cifs_umount_begin, .umount_begin = cifs_umount_begin,
.remount_fs = cifs_remount, .remount_fs = cifs_remount,
#ifdef CONFIG_CIFS_STATS2
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)
.show_stats = cifs_show_stats,
#endif
#endif
}; };
#ifndef MS_SILENT
#define MS_SILENT MS_VERBOSE
#endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)
static int static int
...@@ -536,7 +575,7 @@ cifs_get_sb(struct file_system_type *fs_type, ...@@ -536,7 +575,7 @@ cifs_get_sb(struct file_system_type *fs_type,
sb->s_flags = flags; sb->s_flags = flags;
rc = cifs_read_super(sb, data, dev_name, flags & MS_VERBOSE ? 1 : 0); rc = cifs_read_super(sb, data, dev_name, flags & MS_SILENT ? 1 : 0);
if (rc) { if (rc) {
up_write(&sb->s_umount); up_write(&sb->s_umount);
deactivate_super(sb); deactivate_super(sb);
...@@ -558,12 +597,11 @@ cifs_get_sb(struct file_system_type *fs_type, ...@@ -558,12 +597,11 @@ cifs_get_sb(struct file_system_type *fs_type,
static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos) unsigned long nr_segs, loff_t pos)
{ {
struct inode *inode = iocb->ki_filp->f_dentry->d_inode; struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode;
ssize_t written; ssize_t written;
written = generic_file_aio_write(iocb, iov, nr_segs, pos); written = generic_file_aio_write(iocb, iov, nr_segs, pos);
#else #else
static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov, static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov,
unsigned long nr_segs, loff_t *ppos) unsigned long nr_segs, loff_t *ppos)
{ {
...@@ -599,7 +637,6 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) ...@@ -599,7 +637,6 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
way so we must seek to end on non-oplocked files by way so we must seek to end on non-oplocked files by
setting the revalidate time to zero */ setting the revalidate time to zero */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19)
if(file->f_path.dentry->d_inode)
CIFS_I(file->f_path.dentry->d_inode)->time = 0; CIFS_I(file->f_path.dentry->d_inode)->time = 0;
retval = cifs_revalidate(file->f_path.dentry); retval = cifs_revalidate(file->f_path.dentry);
...@@ -621,7 +658,7 @@ static struct file_system_type cifs_fs_type = { ...@@ -621,7 +658,7 @@ static struct file_system_type cifs_fs_type = {
.kill_sb = kill_anon_super, .kill_sb = kill_anon_super,
/* .fs_flags */ /* .fs_flags */
}; };
struct inode_operations cifs_dir_inode_ops = { const struct inode_operations cifs_dir_inode_ops = {
.create = cifs_create, .create = cifs_create,
.lookup = cifs_lookup, .lookup = cifs_lookup,
.getattr = cifs_getattr, .getattr = cifs_getattr,
...@@ -643,7 +680,7 @@ struct inode_operations cifs_dir_inode_ops = { ...@@ -643,7 +680,7 @@ struct inode_operations cifs_dir_inode_ops = {
#endif #endif
}; };
struct inode_operations cifs_file_inode_ops = { const struct inode_operations cifs_file_inode_ops = {
/* revalidate:cifs_revalidate, */ /* revalidate:cifs_revalidate, */
.setattr = cifs_setattr, .setattr = cifs_setattr,
.getattr = cifs_getattr, /* do we need this anymore? */ .getattr = cifs_getattr, /* do we need this anymore? */
...@@ -657,7 +694,7 @@ struct inode_operations cifs_file_inode_ops = { ...@@ -657,7 +694,7 @@ struct inode_operations cifs_file_inode_ops = {
#endif #endif
}; };
struct inode_operations cifs_symlink_inode_ops = { const struct inode_operations cifs_symlink_inode_ops = {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
.readlink = cifs_readlink, .readlink = cifs_readlink,
#else #else
...@@ -692,7 +729,11 @@ const struct file_operations cifs_file_ops = { ...@@ -692,7 +729,11 @@ const struct file_operations cifs_file_ops = {
.fsync = cifs_fsync, .fsync = cifs_fsync,
.flush = cifs_flush, .flush = cifs_flush,
.mmap = cifs_file_mmap, .mmap = cifs_file_mmap,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
.sendfile = generic_file_sendfile, .sendfile = generic_file_sendfile,
#else
.splice_read = generic_file_splice_read,
#endif
.llseek = cifs_llseek, .llseek = cifs_llseek,
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl, .ioctl = cifs_ioctl,
...@@ -713,7 +754,11 @@ const struct file_operations cifs_file_direct_ops = { ...@@ -713,7 +754,11 @@ const struct file_operations cifs_file_direct_ops = {
.lock = cifs_lock, .lock = cifs_lock,
.fsync = cifs_fsync, .fsync = cifs_fsync,
.flush = cifs_flush, .flush = cifs_flush,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
.sendfile = generic_file_sendfile, /* BB removeme BB */ .sendfile = generic_file_sendfile, /* BB removeme BB */
#else
.splice_read = generic_file_splice_read,
#endif
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl, .ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
...@@ -722,7 +767,6 @@ const struct file_operations cifs_file_direct_ops = { ...@@ -722,7 +767,6 @@ const struct file_operations cifs_file_direct_ops = {
.dir_notify = cifs_dir_notify, .dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */ #endif /* CONFIG_CIFS_EXPERIMENTAL */
}; };
const struct file_operations cifs_file_nobrl_ops = { const struct file_operations cifs_file_nobrl_ops = {
.read = do_sync_read, .read = do_sync_read,
.write = do_sync_write, .write = do_sync_write,
...@@ -737,7 +781,11 @@ const struct file_operations cifs_file_nobrl_ops = { ...@@ -737,7 +781,11 @@ const struct file_operations cifs_file_nobrl_ops = {
.fsync = cifs_fsync, .fsync = cifs_fsync,
.flush = cifs_flush, .flush = cifs_flush,
.mmap = cifs_file_mmap, .mmap = cifs_file_mmap,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
.sendfile = generic_file_sendfile, .sendfile = generic_file_sendfile,
#else
.splice_read = generic_file_splice_read,
#endif
.llseek = cifs_llseek, .llseek = cifs_llseek,
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl, .ioctl = cifs_ioctl,
...@@ -757,7 +805,11 @@ const struct file_operations cifs_file_direct_nobrl_ops = { ...@@ -757,7 +805,11 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
.release = cifs_close, .release = cifs_close,
.fsync = cifs_fsync, .fsync = cifs_fsync,
.flush = cifs_flush, .flush = cifs_flush,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
.sendfile = generic_file_sendfile, /* BB removeme BB */ .sendfile = generic_file_sendfile, /* BB removeme BB */
#else
.splice_read = generic_file_splice_read,
#endif
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
.ioctl = cifs_ioctl, .ioctl = cifs_ioctl,
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
...@@ -777,25 +829,31 @@ const struct file_operations cifs_dir_ops = { ...@@ -777,25 +829,31 @@ const struct file_operations cifs_dir_ops = {
.ioctl = cifs_ioctl, .ioctl = cifs_ioctl,
}; };
#ifndef SLAB_MEM_SPREAD
#define SLAB_MEM_SPREAD 0
#endif
static void static void
cifs_init_once(void *inode, kmem_cache_t * cachep, unsigned long flags) cifs_init_once(void *inode, struct kmem_cache *cachep, unsigned long flags)
{ {
struct cifsInodeInfo *cifsi = inode; struct cifsInodeInfo *cifsi = inode;
if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR) {
inode_init_once(&cifsi->vfs_inode); inode_init_once(&cifsi->vfs_inode);
INIT_LIST_HEAD(&cifsi->lockList); INIT_LIST_HEAD(&cifsi->lockList);
}
} }
static int static int
cifs_init_inodecache(void) cifs_init_inodecache(void)
{ {
cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", cifs_inode_cachep = kmem_cache_create("cifs_inode_cache",
sizeof (struct cifsInodeInfo), sizeof(struct cifsInodeInfo),
0, SLAB_RECLAIM_ACCOUNT, 0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
cifs_init_once);
#else
cifs_init_once, NULL); cifs_init_once, NULL);
#endif
if (cifs_inode_cachep == NULL) if (cifs_inode_cachep == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -811,7 +869,7 @@ cifs_destroy_inodecache(void) ...@@ -811,7 +869,7 @@ cifs_destroy_inodecache(void)
static int static int
cifs_init_request_bufs(void) cifs_init_request_bufs(void)
{ {
if(CIFSMaxBufSize < 8192) { if (CIFSMaxBufSize < 8192) {
/* Buffer size can not be smaller than 2 * PATH_MAX since maximum /* Buffer size can not be smaller than 2 * PATH_MAX since maximum
Unicode path name has to fit in any SMB/CIFS path based frames */ Unicode path name has to fit in any SMB/CIFS path based frames */
CIFSMaxBufSize = 8192; CIFSMaxBufSize = 8192;
...@@ -824,23 +882,25 @@ cifs_init_request_bufs(void) ...@@ -824,23 +882,25 @@ cifs_init_request_bufs(void)
cifs_req_cachep = kmem_cache_create("cifs_request", cifs_req_cachep = kmem_cache_create("cifs_request",
CIFSMaxBufSize + CIFSMaxBufSize +
MAX_CIFS_HDR_SIZE, 0, MAX_CIFS_HDR_SIZE, 0,
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
SLAB_HWCACHE_ALIGN, NULL);
#else
SLAB_HWCACHE_ALIGN, NULL, NULL); SLAB_HWCACHE_ALIGN, NULL, NULL);
#endif
if (cifs_req_cachep == NULL) if (cifs_req_cachep == NULL)
return -ENOMEM; return -ENOMEM;
if(cifs_min_rcv < 1) if (cifs_min_rcv < 1)
cifs_min_rcv = 1; cifs_min_rcv = 1;
else if (cifs_min_rcv > 64) { else if (cifs_min_rcv > 64) {
cifs_min_rcv = 64; cifs_min_rcv = 64;
cERROR(1,("cifs_min_rcv set to maximum (64)")); cERROR(1, ("cifs_min_rcv set to maximum (64)"));
} }
cifs_req_poolp = mempool_create(cifs_min_rcv, cifs_req_poolp = mempool_create_slab_pool(cifs_min_rcv,
mempool_alloc_slab,
mempool_free_slab,
cifs_req_cachep); cifs_req_cachep);
if(cifs_req_poolp == NULL) { if (cifs_req_poolp == NULL) {
kmem_cache_destroy(cifs_req_cachep); kmem_cache_destroy(cifs_req_cachep);
return -ENOMEM; return -ENOMEM;
} }
...@@ -854,26 +914,28 @@ cifs_init_request_bufs(void) ...@@ -854,26 +914,28 @@ cifs_init_request_bufs(void)
alloc of large cifs buffers even when page debugging is on */ alloc of large cifs buffers even when page debugging is on */
cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq", cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq",
MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN, MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN,
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
NULL);
#else
NULL, NULL); NULL, NULL);
#endif
if (cifs_sm_req_cachep == NULL) { if (cifs_sm_req_cachep == NULL) {
mempool_destroy(cifs_req_poolp); mempool_destroy(cifs_req_poolp);
kmem_cache_destroy(cifs_req_cachep); kmem_cache_destroy(cifs_req_cachep);
return -ENOMEM; return -ENOMEM;
} }
if(cifs_min_small < 2) if (cifs_min_small < 2)
cifs_min_small = 2; cifs_min_small = 2;
else if (cifs_min_small > 256) { else if (cifs_min_small > 256) {
cifs_min_small = 256; cifs_min_small = 256;
cFYI(1,("cifs_min_small set to maximum (256)")); cFYI(1, ("cifs_min_small set to maximum (256)"));
} }
cifs_sm_req_poolp = mempool_create(cifs_min_small, cifs_sm_req_poolp = mempool_create_slab_pool(cifs_min_small,
mempool_alloc_slab,
mempool_free_slab,
cifs_sm_req_cachep); cifs_sm_req_cachep);
if(cifs_sm_req_poolp == NULL) { if (cifs_sm_req_poolp == NULL) {
mempool_destroy(cifs_req_poolp); mempool_destroy(cifs_req_poolp);
kmem_cache_destroy(cifs_req_cachep); kmem_cache_destroy(cifs_req_cachep);
kmem_cache_destroy(cifs_sm_req_cachep); kmem_cache_destroy(cifs_sm_req_cachep);
...@@ -896,26 +958,32 @@ static int ...@@ -896,26 +958,32 @@ static int
cifs_init_mids(void) cifs_init_mids(void)
{ {
cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids",
sizeof (struct mid_q_entry), 0, sizeof(struct mid_q_entry), 0,
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
SLAB_HWCACHE_ALIGN, NULL);
#else
SLAB_HWCACHE_ALIGN, NULL, NULL); SLAB_HWCACHE_ALIGN, NULL, NULL);
#endif
if (cifs_mid_cachep == NULL) if (cifs_mid_cachep == NULL)
return -ENOMEM; return -ENOMEM;
cifs_mid_poolp = mempool_create(3 /* a reasonable min simultan opers */, /* 3 is a reasonable minimum number of simultaneous operations */
mempool_alloc_slab, cifs_mid_poolp = mempool_create_slab_pool(3, cifs_mid_cachep);
mempool_free_slab, if (cifs_mid_poolp == NULL) {
cifs_mid_cachep);
if(cifs_mid_poolp == NULL) {
kmem_cache_destroy(cifs_mid_cachep); kmem_cache_destroy(cifs_mid_cachep);
return -ENOMEM; return -ENOMEM;
} }
cifs_oplock_cachep = kmem_cache_create("cifs_oplock_structs", cifs_oplock_cachep = kmem_cache_create("cifs_oplock_structs",
sizeof (struct oplock_q_entry), 0, sizeof(struct oplock_q_entry), 0,
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
SLAB_HWCACHE_ALIGN, NULL);
#else
SLAB_HWCACHE_ALIGN, NULL, NULL); SLAB_HWCACHE_ALIGN, NULL, NULL);
#endif
if (cifs_oplock_cachep == NULL) { if (cifs_oplock_cachep == NULL) {
kmem_cache_destroy(cifs_mid_cachep);
mempool_destroy(cifs_mid_poolp); mempool_destroy(cifs_mid_poolp);
kmem_cache_destroy(cifs_mid_cachep);
return -ENOMEM; return -ENOMEM;
} }
...@@ -930,18 +998,17 @@ cifs_destroy_mids(void) ...@@ -930,18 +998,17 @@ cifs_destroy_mids(void)
kmem_cache_destroy(cifs_oplock_cachep); kmem_cache_destroy(cifs_oplock_cachep);
} }
static int cifs_oplock_thread(void * dummyarg) static int cifs_oplock_thread(void *dummyarg)
{ {
struct oplock_q_entry * oplock_item; struct oplock_q_entry *oplock_item;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode * inode; struct inode *inode;
__u16 netfid; __u16 netfid;
int rc; int rc;
daemonize("cifsoplockd"); #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
allow_signal(SIGTERM); set_freezable();
#endif
oplockThread = current;
do { do {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12)
if (try_to_freeze()) if (try_to_freeze())
...@@ -949,15 +1016,15 @@ static int cifs_oplock_thread(void * dummyarg) ...@@ -949,15 +1016,15 @@ static int cifs_oplock_thread(void * dummyarg)
#endif #endif
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if(list_empty(&GlobalOplock_Q)) { if (list_empty(&GlobalOplock_Q)) {
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(39*HZ); schedule_timeout(39*HZ);
} else { } else {
oplock_item = list_entry(GlobalOplock_Q.next, oplock_item = list_entry(GlobalOplock_Q.next,
struct oplock_q_entry, qhead); struct oplock_q_entry, qhead);
if(oplock_item) { if (oplock_item) {
cFYI(1,("found oplock item to write out")); cFYI(1, ("found oplock item to write out"));
pTcon = oplock_item->tcon; pTcon = oplock_item->tcon;
inode = oplock_item->pinode; inode = oplock_item->pinode;
netfid = oplock_item->netfid; netfid = oplock_item->netfid;
...@@ -969,8 +1036,10 @@ static int cifs_oplock_thread(void * dummyarg) ...@@ -969,8 +1036,10 @@ static int cifs_oplock_thread(void * dummyarg)
the call */ the call */
/* mutex_lock(&inode->i_mutex);*/ /* mutex_lock(&inode->i_mutex);*/
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
rc = filemap_fdatawrite(inode->i_mapping); rc =
if(CIFS_I(inode)->clientCanCacheRead == 0) { filemap_fdatawrite(inode->i_mapping);
if (CIFS_I(inode)->clientCanCacheRead
== 0) {
filemap_fdatawait(inode->i_mapping); filemap_fdatawait(inode->i_mapping);
invalidate_remote_inode(inode); invalidate_remote_inode(inode);
} }
...@@ -979,40 +1048,37 @@ static int cifs_oplock_thread(void * dummyarg) ...@@ -979,40 +1048,37 @@ static int cifs_oplock_thread(void * dummyarg)
/* mutex_unlock(&inode->i_mutex);*/ /* mutex_unlock(&inode->i_mutex);*/
if (rc) if (rc)
CIFS_I(inode)->write_behind_rc = rc; CIFS_I(inode)->write_behind_rc = rc;
cFYI(1,("Oplock flush inode %p rc %d",inode,rc)); cFYI(1, ("Oplock flush inode %p rc %d",
inode, rc));
/* releasing a stale oplock after recent reconnection /* releasing stale oplock after recent reconnect
of smb session using a now incorrect file of smb session using a now incorrect file
handle is not a data integrity issue but do handle is not a data integrity issue but do
not bother sending an oplock release if session not bother sending an oplock release if session
to server still is disconnected since oplock to server still is disconnected since oplock
already released by the server in that case */ already released by the server in that case */
if(pTcon->tidStatus != CifsNeedReconnect) { if (pTcon->tidStatus != CifsNeedReconnect) {
rc = CIFSSMBLock(0, pTcon, netfid, rc = CIFSSMBLock(0, pTcon, netfid,
0 /* len */ , 0 /* offset */, 0, 0 /* len */ , 0 /* offset */, 0,
0, LOCKING_ANDX_OPLOCK_RELEASE, 0, LOCKING_ANDX_OPLOCK_RELEASE,
0 /* wait flag */); 0 /* wait flag */);
cFYI(1,("Oplock release rc = %d ",rc)); cFYI(1, ("Oplock release rc = %d", rc));
} }
} else } else
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1); /* yield in case q were corrupt */ schedule_timeout(1); /* yield in case q were corrupt */
} }
} while(!signal_pending(current)); } while (!kthread_should_stop());
oplockThread = NULL;
complete_and_exit (&cifs_oplock_exited, 0); return 0;
} }
static int cifs_dnotify_thread(void * dummyarg) static int cifs_dnotify_thread(void *dummyarg)
{ {
struct list_head *tmp; struct list_head *tmp;
struct cifsSesInfo *ses; struct cifsSesInfo *ses;
daemonize("cifsdnotifyd");
allow_signal(SIGTERM);
dnotifyThread = current;
do { do {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12)
if (try_to_freeze()) if (try_to_freeze())
...@@ -1027,13 +1093,14 @@ static int cifs_dnotify_thread(void * dummyarg) ...@@ -1027,13 +1093,14 @@ static int cifs_dnotify_thread(void * dummyarg)
list_for_each(tmp, &GlobalSMBSessionList) { list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo, ses = list_entry(tmp, struct cifsSesInfo,
cifsSessionList); cifsSessionList);
if(ses && ses->server && if (ses && ses->server &&
atomic_read(&ses->server->inFlight)) atomic_read(&ses->server->inFlight))
wake_up_all(&ses->server->response_q); wake_up_all(&ses->server->response_q);
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
} while(!signal_pending(current)); } while (!kthread_should_stop());
complete_and_exit (&cifs_dnotify_exited, 0);
return 0;
} }
static int __init static int __init
...@@ -1056,7 +1123,7 @@ init_cifs(void) ...@@ -1056,7 +1123,7 @@ init_cifs(void)
*/ */
atomic_set(&sesInfoAllocCount, 0); atomic_set(&sesInfoAllocCount, 0);
atomic_set(&tconInfoAllocCount, 0); atomic_set(&tconInfoAllocCount, 0);
atomic_set(&tcpSesAllocCount,0); atomic_set(&tcpSesAllocCount, 0);
atomic_set(&tcpSesReconnectCount, 0); atomic_set(&tcpSesReconnectCount, 0);
atomic_set(&tconInfoReconnectCount, 0); atomic_set(&tconInfoReconnectCount, 0);
...@@ -1071,44 +1138,61 @@ init_cifs(void) ...@@ -1071,44 +1138,61 @@ init_cifs(void)
GlobalCurrentXid = 0; GlobalCurrentXid = 0;
GlobalTotalActiveXid = 0; GlobalTotalActiveXid = 0;
GlobalMaxActiveXid = 0; GlobalMaxActiveXid = 0;
memset(Local_System_Name, 0, 15);
rwlock_init(&GlobalSMBSeslock); rwlock_init(&GlobalSMBSeslock);
spin_lock_init(&GlobalMid_Lock); spin_lock_init(&GlobalMid_Lock);
if(cifs_max_pending < 2) { if (cifs_max_pending < 2) {
cifs_max_pending = 2; cifs_max_pending = 2;
cFYI(1,("cifs_max_pending set to min of 2")); cFYI(1, ("cifs_max_pending set to min of 2"));
} else if(cifs_max_pending > 256) { } else if (cifs_max_pending > 256) {
cifs_max_pending = 256; cifs_max_pending = 256;
cFYI(1,("cifs_max_pending set to max of 256")); cFYI(1, ("cifs_max_pending set to max of 256"));
} }
rc = cifs_init_inodecache(); rc = cifs_init_inodecache();
if (!rc) { if (rc)
goto out_clean_proc;
rc = cifs_init_mids(); rc = cifs_init_mids();
if (!rc) { if (rc)
goto out_destroy_inodecache;
rc = cifs_init_request_bufs(); rc = cifs_init_request_bufs();
if (!rc) { if (rc)
goto out_destroy_mids;
rc = register_filesystem(&cifs_fs_type); rc = register_filesystem(&cifs_fs_type);
if (!rc) { if (rc)
rc = (int)kernel_thread(cifs_oplock_thread, NULL, goto out_destroy_request_bufs;
CLONE_FS | CLONE_FILES | CLONE_VM);
if(rc > 0) { oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
rc = (int)kernel_thread(cifs_dnotify_thread, NULL, if (IS_ERR(oplockThread)) {
CLONE_FS | CLONE_FILES | CLONE_VM); rc = PTR_ERR(oplockThread);
if(rc > 0) cERROR(1, ("error %d create oplock thread", rc));
return 0; goto out_unregister_filesystem;
else
cERROR(1,("error %d create dnotify thread", rc));
} else {
cERROR(1,("error %d create oplock thread",rc));
} }
dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
if (IS_ERR(dnotifyThread)) {
rc = PTR_ERR(dnotifyThread);
cERROR(1, ("error %d create dnotify thread", rc));
goto out_stop_oplock_thread;
} }
return 0;
out_stop_oplock_thread:
kthread_stop(oplockThread);
out_unregister_filesystem:
unregister_filesystem(&cifs_fs_type);
out_destroy_request_bufs:
cifs_destroy_request_bufs(); cifs_destroy_request_bufs();
} out_destroy_mids:
cifs_destroy_mids(); cifs_destroy_mids();
} out_destroy_inodecache:
cifs_destroy_inodecache(); cifs_destroy_inodecache();
} out_clean_proc:
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
cifs_proc_clean(); cifs_proc_clean();
#endif #endif
...@@ -1118,7 +1202,7 @@ init_cifs(void) ...@@ -1118,7 +1202,7 @@ init_cifs(void)
static void __exit static void __exit
exit_cifs(void) exit_cifs(void)
{ {
cFYI(0, ("In unregister ie exit_cifs")); cFYI(0, ("exit_cifs"));
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
cifs_proc_clean(); cifs_proc_clean();
#endif #endif
...@@ -1126,20 +1210,15 @@ exit_cifs(void) ...@@ -1126,20 +1210,15 @@ exit_cifs(void)
cifs_destroy_inodecache(); cifs_destroy_inodecache();
cifs_destroy_mids(); cifs_destroy_mids();
cifs_destroy_request_bufs(); cifs_destroy_request_bufs();
if(oplockThread) { kthread_stop(oplockThread);
send_sig(SIGTERM, oplockThread, 1); kthread_stop(dnotifyThread);
wait_for_completion(&cifs_oplock_exited);
}
if(dnotifyThread) {
send_sig(SIGTERM, dnotifyThread, 1);
wait_for_completion(&cifs_dnotify_exited);
}
} }
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */
MODULE_DESCRIPTION MODULE_DESCRIPTION
("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows"); ("VFS to access servers complying with the SNIA CIFS Specification "
"e.g. Samba and Windows");
MODULE_VERSION(CIFS_VERSION); MODULE_VERSION(CIFS_VERSION);
module_init(init_cifs) module_init(init_cifs)
module_exit(exit_cifs) module_exit(exit_cifs)
...@@ -32,10 +32,6 @@ ...@@ -32,10 +32,6 @@
#define TRUE 1 #define TRUE 1
#endif #endif
#ifndef __user
#define __user
#endif
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
#define current_fs_time(arg) CURRENT_TIME #define current_fs_time(arg) CURRENT_TIME
...@@ -69,13 +65,13 @@ extern const struct address_space_operations cifs_addr_ops; ...@@ -69,13 +65,13 @@ extern const struct address_space_operations cifs_addr_ops;
extern const struct address_space_operations cifs_addr_ops_smallbuf; extern const struct address_space_operations cifs_addr_ops_smallbuf;
/* Functions related to super block operations */ /* Functions related to super block operations */
extern struct super_operations cifs_super_ops; /* extern const struct super_operations cifs_super_ops;*/
extern void cifs_read_inode(struct inode *); extern void cifs_read_inode(struct inode *);
/*extern void cifs_delete_inode(struct inode *);*/ /* BB not needed yet */ /*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_write_inode(struct inode *); */ /* BB not needed yet */
/* Functions related to inodes */ /* Functions related to inodes */
extern struct inode_operations cifs_dir_inode_ops; extern const struct inode_operations cifs_dir_inode_ops;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
extern int cifs_create(struct inode *, struct dentry *, int, extern int cifs_create(struct inode *, struct dentry *, int,
struct nameidata *); struct nameidata *);
...@@ -97,21 +93,21 @@ extern int cifs_rename(struct inode *, struct dentry *, struct inode *, ...@@ -97,21 +93,21 @@ extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
extern int cifs_revalidate(struct dentry *); extern int cifs_revalidate(struct dentry *);
extern int cifs_setattr(struct dentry *, struct iattr *); extern int cifs_setattr(struct dentry *, struct iattr *);
extern struct inode_operations cifs_file_inode_ops; extern const struct inode_operations cifs_file_inode_ops;
extern struct inode_operations cifs_symlink_inode_ops; extern const struct inode_operations cifs_symlink_inode_ops;
/* Functions related to files and directories */ /* Functions related to files and directories */
extern const struct file_operations cifs_file_ops; extern const struct file_operations cifs_file_ops;
extern const struct file_operations cifs_file_direct_ops; /* if directio mount */ extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */
extern const struct file_operations cifs_file_nobrl_ops; extern const struct file_operations cifs_file_nobrl_ops;
extern const struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */ extern const struct file_operations cifs_file_direct_nobrl_ops; /* no brlocks */
extern int cifs_open(struct inode *inode, struct file *file); extern int cifs_open(struct inode *inode, struct file *file);
extern int cifs_close(struct inode *inode, struct file *file); extern int cifs_close(struct inode *inode, struct file *file);
extern int cifs_closedir(struct inode *inode, struct file *file); extern int cifs_closedir(struct inode *inode, struct file *file);
extern ssize_t cifs_user_read(struct file *file, char __user *read_data, extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
size_t read_size, loff_t * poffset); size_t read_size, loff_t *poffset);
extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
size_t write_size, loff_t * poffset); size_t write_size, loff_t *poffset);
extern int cifs_lock(struct file *, int, struct file_lock *); extern int cifs_lock(struct file *, int, struct file_lock *);
extern int cifs_fsync(struct file *, struct dentry *, int); extern int cifs_fsync(struct file *, struct dentry *, int);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)
...@@ -132,7 +128,8 @@ extern struct dentry_operations cifs_ci_dentry_ops; ...@@ -132,7 +128,8 @@ extern struct dentry_operations cifs_ci_dentry_ops;
/* Functions related to symlinks */ /* Functions related to symlinks */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)
extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *); extern void cifs_put_link(struct dentry *direntry,
struct nameidata *nd, void *);
#else #else
extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd); extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd); extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd);
...@@ -146,7 +143,7 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *, ...@@ -146,7 +143,7 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
size_t, int); size_t, int);
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern int cifs_ioctl (struct inode * inode, struct file * filep, extern int cifs_ioctl(struct inode *inode, struct file *filep,
unsigned int command, unsigned long arg); unsigned int command, unsigned long arg);
#define CIFS_VERSION "1.47" #define CIFS_VERSION "1.51"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
/* /*
* fs/cifs/cifsglob.h * fs/cifs/cifsglob.h
* *
* Copyright (C) International Business Machines Corp., 2002,2006 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* Jeremy Allison (jra@samba.org) * Jeremy Allison (jra@samba.org)
* *
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1 #define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1
#define MAX_SERVER_SIZE 15 #define MAX_SERVER_SIZE 15
#define MAX_SHARE_SIZE 64 /* used to be 20 - this should still be enough */ #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */
#define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null
termination then *2 for unicode versions */ termination then *2 for unicode versions */
#define MAX_PASSWORD_SIZE 16 #define MAX_PASSWORD_SIZE 16
...@@ -113,6 +113,17 @@ enum protocolEnum { ...@@ -113,6 +113,17 @@ enum protocolEnum {
/* Netbios frames protocol not supported at this time */ /* Netbios frames protocol not supported at this time */
}; };
struct mac_key {
unsigned int len;
union {
char ntlm[CIFS_SESS_KEY_SIZE + 16];
struct {
char key[16];
struct ntlmv2_resp resp;
} ntlmv2;
} data;
};
/* /*
***************************************************************** *****************************************************************
* Except the CIFS PDUs themselves all the * Except the CIFS PDUs themselves all the
...@@ -168,7 +179,8 @@ struct TCP_Server_Info { ...@@ -168,7 +179,8 @@ struct TCP_Server_Info {
/* 16th byte of RFC1001 workstation name is always null */ /* 16th byte of RFC1001 workstation name is always null */
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
__u32 sequence_number; /* needed for CIFS PDU signature */ __u32 sequence_number; /* needed for CIFS PDU signature */
char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; struct mac_key mac_signing_key;
char ntlmv2_hash[16];
unsigned long lstrp; /* when we got last response from this server */ unsigned long lstrp; /* when we got last response from this server */
}; };
...@@ -209,8 +221,8 @@ struct cifsSesInfo { ...@@ -209,8 +221,8 @@ struct cifsSesInfo {
char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
TCP names - will ipv6 and sctp addresses fit? */ TCP names - will ipv6 and sctp addresses fit? */
char userName[MAX_USERNAME_SIZE + 1]; char userName[MAX_USERNAME_SIZE + 1];
char * domainName; char *domainName;
char * password; char *password;
}; };
/* no more than one of the following three session flags may be set */ /* no more than one of the following three session flags may be set */
#define CIFS_SES_NT4 1 #define CIFS_SES_NT4 1
...@@ -278,7 +290,9 @@ struct cifsTconInfo { ...@@ -278,7 +290,9 @@ struct cifsTconInfo {
FILE_SYSTEM_UNIX_INFO fsUnixInfo; FILE_SYSTEM_UNIX_INFO fsUnixInfo;
unsigned retry:1; unsigned retry:1;
unsigned nocase:1; unsigned nocase:1;
/* BB add field for back pointer to sb struct? */ unsigned unix_ext:1; /* if off disable Linux extensions to CIFS protocol
for this mount even if server would support */
/* BB add field for back pointer to sb struct(s)? */
}; };
/* /*
...@@ -300,9 +314,9 @@ struct cifs_search_info { ...@@ -300,9 +314,9 @@ struct cifs_search_info {
__u16 entries_in_buffer; __u16 entries_in_buffer;
__u16 info_level; __u16 info_level;
__u32 resume_key; __u32 resume_key;
char * ntwrk_buf_start; char *ntwrk_buf_start;
char * srch_entries_start; char *srch_entries_start;
char * presume_name; char *presume_name;
unsigned int resume_name_len; unsigned int resume_name_len;
unsigned endOfSearch:1; unsigned endOfSearch:1;
unsigned emptyDir:1; unsigned emptyDir:1;
...@@ -318,15 +332,19 @@ struct cifsFileInfo { ...@@ -318,15 +332,19 @@ struct cifsFileInfo {
__u16 netfid; /* file id from remote */ __u16 netfid; /* file id from remote */
/* BB add lock scope info here if needed */ ; /* BB add lock scope info here if needed */ ;
/* lock scope id (0 if none) */ /* lock scope id (0 if none) */
struct file * pfile; /* needed for writepage */ struct file *pfile; /* needed for writepage */
struct inode * pInode; /* needed for oplock break */ struct inode *pInode; /* needed for oplock break */
struct semaphore lock_sem; #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)
struct mutex lock_mutex;
#else
struct semaphore lock_mutex;
#endif
struct list_head llist; /* list of byte range locks we have. */ struct list_head llist; /* list of byte range locks we have. */
unsigned closePend:1; /* file is marked to close */ unsigned closePend:1; /* file is marked to close */
unsigned invalidHandle:1; /* file closed via session abend */ unsigned invalidHandle:1; /* file closed via session abend */
atomic_t wrtPending; /* handle in use - defer close */ atomic_t wrtPending; /* handle in use - defer close */
struct semaphore fh_sem; /* prevents reopen race after dead ses*/ struct semaphore fh_sem; /* prevents reopen race after dead ses*/
char * search_resume_name; /* BB removeme BB */ char *search_resume_name; /* BB removeme BB */
struct cifs_search_info srch_inf; struct cifs_search_info srch_inf;
}; };
...@@ -336,7 +354,7 @@ struct cifsFileInfo { ...@@ -336,7 +354,7 @@ struct cifsFileInfo {
struct cifsInodeInfo { struct cifsInodeInfo {
struct list_head lockList; struct list_head lockList;
/* BB add in lists for dirty pages - i.e. write caching info for oplock */ /* BB add in lists for dirty pages i.e. write caching info for oplock */
struct list_head openFileList; struct list_head openFileList;
int write_behind_rc; int write_behind_rc;
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
...@@ -362,7 +380,7 @@ CIFS_SB(struct super_block *sb) ...@@ -362,7 +380,7 @@ CIFS_SB(struct super_block *sb)
{ {
return sb->s_fs_info; return sb->s_fs_info;
} }
#else #else /* 2.4 kernel case */
static inline struct cifsInodeInfo * static inline struct cifsInodeInfo *
CIFS_I(struct inode *inode) CIFS_I(struct inode *inode)
{ {
...@@ -408,9 +426,9 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon, ...@@ -408,9 +426,9 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
} }
#else #else
#define cifs_stats_inc(field) do {} while(0) #define cifs_stats_inc(field) do {} while (0)
#define cifs_stats_bytes_written(tcon, bytes) do {} while(0) #define cifs_stats_bytes_written(tcon, bytes) do {} while (0)
#define cifs_stats_bytes_read(tcon, bytes) do {} while(0) #define cifs_stats_bytes_read(tcon, bytes) do {} while (0)
#endif #endif
...@@ -437,8 +455,8 @@ struct mid_q_entry { ...@@ -437,8 +455,8 @@ struct mid_q_entry {
struct oplock_q_entry { struct oplock_q_entry {
struct list_head qhead; struct list_head qhead;
struct inode * pinode; struct inode *pinode;
struct cifsTconInfo * tcon; struct cifsTconInfo *tcon;
__u16 netfid; __u16 netfid;
}; };
...@@ -453,7 +471,7 @@ struct dir_notify_req { ...@@ -453,7 +471,7 @@ struct dir_notify_req {
__u16 netfid; __u16 netfid;
__u32 filter; /* CompletionFilter (for multishot) */ __u32 filter; /* CompletionFilter (for multishot) */
int multishot; int multishot;
struct file * pfile; struct file *pfile;
}; };
#define MID_FREE 0 #define MID_FREE 0
...@@ -544,7 +562,8 @@ require use of the stronger protocol */ ...@@ -544,7 +562,8 @@ require use of the stronger protocol */
* This list helps improve performance and eliminate the messages indicating * This list helps improve performance and eliminate the messages indicating
* that we had a communications error talking to the server in this list. * that we had a communications error talking to the server in this list.
*/ */
GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */ /* Feature not supported */
/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
/* /*
* The following is a hash table of all the users we know about. * The following is a hash table of all the users we know about.
...@@ -602,7 +621,6 @@ GLOBAL_EXTERN unsigned int lookupCacheEnabled; ...@@ -602,7 +621,6 @@ GLOBAL_EXTERN unsigned int lookupCacheEnabled;
GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */ with more secure ntlmssp2 challenge/resp */
GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
GLOBAL_EXTERN unsigned int secFlags;
GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */
GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
......
...@@ -229,7 +229,7 @@ ...@@ -229,7 +229,7 @@
*/ */
#define CIFS_NO_HANDLE 0xFFFF #define CIFS_NO_HANDLE 0xFFFF
#define NO_CHANGE_64 0xFFFFFFFFFFFFFFFFULL #define NO_CHANGE_64 cpu_to_le64(0xFFFFFFFFFFFFFFFFULL)
#define NO_CHANGE_32 0xFFFFFFFFUL #define NO_CHANGE_32 0xFFFFFFFFUL
/* IPC$ in ASCII */ /* IPC$ in ASCII */
...@@ -369,23 +369,25 @@ struct smb_hdr { ...@@ -369,23 +369,25 @@ struct smb_hdr {
__u8 WordCount; __u8 WordCount;
} __attribute__((packed)); } __attribute__((packed));
/* given a pointer to an smb_hdr retrieve the value of byte count */ /* given a pointer to an smb_hdr retrieve the value of byte count */
#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount)))
#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) #define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount)))
/* given a pointer to an smb_hdr retrieve the pointer to the byte area */ /* given a pointer to an smb_hdr retrieve the pointer to the byte area */
#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount) + 2)
/* /*
* Computer Name Length * Computer Name Length (since Netbios name was length 16 with last byte 0x20)
* No longer as important, now that TCP names are more commonly used to
* resolve hosts.
*/ */
#define CNLEN 15 #define CNLEN 15
/* /*
* Share Name Length @S8A * Share Name Length (SNLEN)
* Note: This length is limited by the SMB used to get @S8A * Note: This length was limited by the SMB used to get
* the Share info. NetShareEnum only returns 13 @S8A * the Share info. NetShareEnum only returned 13
* chars, including the null termination. @S8A * chars, including the null termination.
* This was removed because it no longer is limiting.
*/ */
#define SNLEN 12 /*@S8A */
/* /*
* Comment Length * Comment Length
...@@ -721,6 +723,7 @@ typedef struct smb_com_findclose_req { ...@@ -721,6 +723,7 @@ typedef struct smb_com_findclose_req {
#define REQ_OPLOCK 0x00000002 #define REQ_OPLOCK 0x00000002
#define REQ_BATCHOPLOCK 0x00000004 #define REQ_BATCHOPLOCK 0x00000004
#define REQ_OPENDIRONLY 0x00000008 #define REQ_OPENDIRONLY 0x00000008
#define REQ_EXTENDED_INFO 0x00000010
typedef struct smb_com_open_req { /* also handles create */ typedef struct smb_com_open_req { /* also handles create */
struct smb_hdr hdr; /* wct = 24 */ struct smb_hdr hdr; /* wct = 24 */
...@@ -827,7 +830,8 @@ typedef struct smb_com_writex_req { ...@@ -827,7 +830,8 @@ typedef struct smb_com_writex_req {
__le16 DataLengthLow; __le16 DataLengthLow;
__le16 DataOffset; __le16 DataOffset;
__le16 ByteCount; __le16 ByteCount;
__u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ __u8 Pad; /* BB check for whether padded to DWORD
boundary and optimum performance here */
char Data[0]; char Data[0];
} __attribute__((packed)) WRITEX_REQ; } __attribute__((packed)) WRITEX_REQ;
...@@ -846,7 +850,8 @@ typedef struct smb_com_write_req { ...@@ -846,7 +850,8 @@ typedef struct smb_com_write_req {
__le16 DataOffset; __le16 DataOffset;
__le32 OffsetHigh; __le32 OffsetHigh;
__le16 ByteCount; __le16 ByteCount;
__u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ __u8 Pad; /* BB check for whether padded to DWORD
boundary and optimum performance here */
char Data[0]; char Data[0];
} __attribute__((packed)) WRITE_REQ; } __attribute__((packed)) WRITE_REQ;
...@@ -905,7 +910,8 @@ typedef struct smb_com_read_rsp { ...@@ -905,7 +910,8 @@ typedef struct smb_com_read_rsp {
__le16 DataLengthHigh; __le16 DataLengthHigh;
__u64 Reserved2; __u64 Reserved2;
__u16 ByteCount; __u16 ByteCount;
__u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ __u8 Pad; /* BB check for whether padded to DWORD
boundary and optimum performance here */
char Data[1]; char Data[1];
} __attribute__((packed)) READ_RSP; } __attribute__((packed)) READ_RSP;
...@@ -1397,7 +1403,7 @@ struct smb_t2_rsp { ...@@ -1397,7 +1403,7 @@ struct smb_t2_rsp {
#define SMB_SET_POSIX_LOCK 0x208 #define SMB_SET_POSIX_LOCK 0x208
#define SMB_POSIX_OPEN 0x209 #define SMB_POSIX_OPEN 0x209
#define SMB_POSIX_UNLINK 0x20a #define SMB_POSIX_UNLINK 0x20a
#define SMB_SET_FILE_UNIX_INFO2 #define SMB_SET_FILE_UNIX_INFO2 0x20b
#define SMB_SET_FILE_BASIC_INFO2 0x3ec #define SMB_SET_FILE_BASIC_INFO2 0x3ec
#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */ #define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */
#define SMB_FILE_ALL_INFO2 0x3fa #define SMB_FILE_ALL_INFO2 0x3fa
...@@ -1752,7 +1758,9 @@ typedef struct smb_com_transaction2_get_dfs_refer_req { ...@@ -1752,7 +1758,9 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
__u8 Reserved3; __u8 Reserved3;
__le16 SubCommand; /* one setup word */ __le16 SubCommand; /* one setup word */
__le16 ByteCount; __le16 ByteCount;
__u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */ __u8 Pad[3]; /* Win2K has sent 0x0F01 (max response length
perhaps?) followed by one byte pad - doesn't
seem to matter though */
__le16 MaxReferralLevel; __le16 MaxReferralLevel;
char RequestFileName[1]; char RequestFileName[1];
} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ; } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ;
...@@ -1761,7 +1769,10 @@ typedef struct dfs_referral_level_3 { ...@@ -1761,7 +1769,10 @@ typedef struct dfs_referral_level_3 {
__le16 VersionNumber; __le16 VersionNumber;
__le16 ReferralSize; __le16 ReferralSize;
__le16 ServerType; /* 0x0001 = CIFS server */ __le16 ServerType; /* 0x0001 = CIFS server */
__le16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */ __le16 ReferralFlags; /* or proximity - not clear which since it is
always set to zero - SNIA spec says 0x01
means strip off PathConsumed chars before
submitting RequestFileName to remote node */
__le16 TimeToLive; __le16 TimeToLive;
__le16 Proximity; __le16 Proximity;
__le16 DfsPathOffset; __le16 DfsPathOffset;
...@@ -1787,11 +1798,13 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp { ...@@ -1787,11 +1798,13 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp {
#define DFSREF_STORAGE_SERVER 0x0002 #define DFSREF_STORAGE_SERVER 0x0002
/* IOCTL information */ /* IOCTL information */
/* List of ioctl function codes that look to be of interest to remote clients like this. */ /*
/* Need to do some experimentation to make sure they all work remotely. */ * List of ioctl function codes that look to be of interest to remote clients
/* Some of the following such as the encryption/compression ones would be */ * like this one. Need to do some experimentation to make sure they all work
/* invoked from tools via a specialized hook into the VFS rather than via the */ * remotely. Some of the following, such as the encryption/compression ones
/* standard vfs entry points */ * would be invoked from tools via a specialized hook into the VFS rather
* than via the standard vfs entry points
*/
#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000 #define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004 #define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008 #define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008
...@@ -1880,7 +1893,7 @@ typedef struct { ...@@ -1880,7 +1893,7 @@ typedef struct {
__le16 MajorVersionNumber; __le16 MajorVersionNumber;
__le16 MinorVersionNumber; __le16 MinorVersionNumber;
__le64 Capability; __le64 Capability;
} __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ } __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extension level 0x200*/
/* Version numbers for CIFS UNIX major and minor. */ /* Version numbers for CIFS UNIX major and minor. */
#define CIFS_UNIX_MAJOR_VERSION 1 #define CIFS_UNIX_MAJOR_VERSION 1
...@@ -1895,14 +1908,18 @@ typedef struct { ...@@ -1895,14 +1908,18 @@ typedef struct {
#define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based #define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based
calls including posix open calls including posix open
and posix unlink */ and posix unlink */
#define CIFS_UNIX_LARGE_READ_CAP 0x00000040 /* support reads >128K (up
to 0xFFFF00 */
#define CIFS_UNIX_LARGE_WRITE_CAP 0x00000080
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
/* Can not set pathnames cap yet until we send new posix create SMB since /* Can not set pathnames cap yet until we send new posix create SMB since
otherwise server can treat such handles opened with older ntcreatex otherwise server can treat such handles opened with older ntcreatex
(by a new client which knows how to send posix path ops) (by a new client which knows how to send posix path ops)
as non-posix handles (can affect write behavior with byte range locks. as non-posix handles (can affect write behavior with byte range locks.
We can add back in POSIX_PATH_OPS cap when Posix Create/Mkdir finished */ We can add back in POSIX_PATH_OPS cap when Posix Create/Mkdir finished */
/* #define CIFS_UNIX_CAP_MASK 0x0000003b */ /* #define CIFS_UNIX_CAP_MASK 0x000000fb */
#define CIFS_UNIX_CAP_MASK 0x0000001b #define CIFS_UNIX_CAP_MASK 0x000000db
#else #else
#define CIFS_UNIX_CAP_MASK 0x00000013 #define CIFS_UNIX_CAP_MASK 0x00000013
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
...@@ -2118,22 +2135,46 @@ struct cifs_posix_acl { /* access conrol list (ACL) */ ...@@ -2118,22 +2135,46 @@ struct cifs_posix_acl { /* access conrol list (ACL) */
/* end of POSIX ACL definitions */ /* end of POSIX ACL definitions */
/* POSIX Open Flags */
#define SMB_O_RDONLY 0x1
#define SMB_O_WRONLY 0x2
#define SMB_O_RDWR 0x4
#define SMB_O_CREAT 0x10
#define SMB_O_EXCL 0x20
#define SMB_O_TRUNC 0x40
#define SMB_O_APPEND 0x80
#define SMB_O_SYNC 0x100
#define SMB_O_DIRECTORY 0x200
#define SMB_O_NOFOLLOW 0x400
#define SMB_O_DIRECT 0x800
typedef struct { typedef struct {
__u32 OpenFlags; /* same as NT CreateX */ __le32 OpenFlags; /* same as NT CreateX */
__u32 PosixOpenFlags; __le32 PosixOpenFlags;
__u32 Mode; __le64 Permissions;
__u16 Level; /* reply level requested (see QPathInfo levels) */ __le16 Level; /* reply level requested (see QPathInfo levels) */
__u16 Pad; /* reserved - MBZ */
} __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */ } __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */
typedef struct { typedef struct {
/* reply varies based on requested level */ __le16 OplockFlags;
__u16 Fid;
__le32 CreateAction;
__le16 ReturnedLevel;
__le16 Pad;
/* struct following varies based on requested level */
} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ } __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
#define SMB_POSIX_UNLINK_FILE_TARGET 0
#define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1
struct unlink_psx_rq { /* level 0x20a SetPathInfo */
__le16 type;
} __attribute__((packed));
struct file_internal_info { struct file_internal_info {
__u64 UniqueId; /* inode number */ __u64 UniqueId; /* inode number */
} __attribute__((packed)); /* level 0x3ee */ } __attribute__((packed)); /* level 0x3ee */
struct file_mode_info { struct file_mode_info {
__le32 Mode; __le32 Mode;
} __attribute__((packed)); /* level 0x3f8 */ } __attribute__((packed)); /* level 0x3f8 */
...@@ -2282,7 +2323,7 @@ struct fealist { ...@@ -2282,7 +2323,7 @@ struct fealist {
struct data_blob { struct data_blob {
__u8 *data; __u8 *data;
size_t length; size_t length;
void (*free) (struct data_blob * data_blob); void (*free) (struct data_blob *data_blob);
} __attribute__((packed)); } __attribute__((packed));
...@@ -2348,8 +2389,10 @@ struct data_blob { ...@@ -2348,8 +2389,10 @@ struct data_blob {
T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks
T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2) T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2)
T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK) T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK)
T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) BB check for missing
Actually need QUERY_FILE_UNIX_INFO since has inode num inode fields
Actually a need QUERY_FILE_UNIX_INFO
since has inode num
BB what about a) blksize/blkbits/blocks BB what about a) blksize/blkbits/blocks
b) i_version b) i_version
c) i_rdev c) i_rdev
...@@ -2359,8 +2402,6 @@ struct data_blob { ...@@ -2359,8 +2402,6 @@ struct data_blob {
T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
*/ */
/* xsymlink is a symlink format (used by MacOS) that can be used /* xsymlink is a symlink format (used by MacOS) that can be used
...@@ -2396,7 +2437,8 @@ typedef struct file_xattr_info { ...@@ -2396,7 +2437,8 @@ typedef struct file_xattr_info {
__u32 xattr_value_len; __u32 xattr_value_len;
char xattr_name[0]; char xattr_name[0];
/* followed by xattr_value[xattr_value_len], no pad */ /* followed by xattr_value[xattr_value_len], no pad */
} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ } __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info
level 0x205 */
/* flags for chattr command */ /* flags for chattr command */
...@@ -2422,7 +2464,8 @@ typedef struct file_xattr_info { ...@@ -2422,7 +2464,8 @@ typedef struct file_xattr_info {
typedef struct file_chattr_info { typedef struct file_chattr_info {
__le64 mask; /* list of all possible attribute bits */ __le64 mask; /* list of all possible attribute bits */
__le64 mode; /* list of actual attribute bits on this inode */ __le64 mode; /* list of actual attribute bits on this inode */
} __attribute__((packed)) FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */ } __attribute__((packed)) FILE_CHATTR_INFO; /* ext attributes
(chattr, chflags) level 0x206 */
#endif #endif
......
/* /*
* fs/cifs/cifsproto.h * fs/cifs/cifsproto.h
* *
* Copyright (c) International Business Machines Corp., 2002,2006 * Copyright (c) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/version.h> #include <linux/version.h>
struct statfs; struct statfs;
struct smb_vol;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
#define kvec iovec #define kvec iovec
...@@ -63,11 +64,11 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, ...@@ -63,11 +64,11 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
struct kvec *, int /* nvec to send */, struct kvec *, int /* nvec to send */,
int * /* type of buf returned */ , const int long_op); int * /* type of buf returned */ , const int long_op);
extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *, extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
struct cifsTconInfo *,
struct smb_hdr * /* input */ , struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ , struct smb_hdr * /* out */ ,
int * /* bytes returned */); int * /* bytes returned */);
extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
extern int is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); extern int is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
...@@ -76,19 +77,19 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr); ...@@ -76,19 +77,19 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr);
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
extern int decode_negTokenInit(unsigned char *security_blob, int length, extern int decode_negTokenInit(unsigned char *security_blob, int length,
enum securityEnum *secType); enum securityEnum *secType);
extern int cifs_inet_pton(int, char * source, void *dst); extern int cifs_inet_pton(int, char *source, void *dst);
extern int map_smb_to_linux_error(struct smb_hdr *smb); extern int map_smb_to_linux_error(struct smb_hdr *smb);
extern void header_assemble(struct smb_hdr *, char /* command */ , extern void header_assemble(struct smb_hdr *, char /* command */ ,
const struct cifsTconInfo *, int /* length of const struct cifsTconInfo *, int /* length of
fixed section (word count) in two byte units */); fixed section (word count) in two byte units */);
extern int small_smb_init_no_tc(const int smb_cmd, const int wct, extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
struct cifsSesInfo *ses, struct cifsSesInfo *ses,
void ** request_buf); void **request_buf);
extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
const int stage, const int stage,
const struct nls_table *nls_cp); const struct nls_table *nls_cp);
extern __u16 GetNextMid(struct TCP_Server_Info *server); extern __u16 GetNextMid(struct TCP_Server_Info *server);
extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16,
struct cifsTconInfo *); struct cifsTconInfo *);
extern void DeleteOplockQEntry(struct oplock_q_entry *); extern void DeleteOplockQEntry(struct oplock_q_entry *);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
...@@ -108,7 +109,7 @@ extern int cifs_get_inode_info(struct inode **pinode, ...@@ -108,7 +109,7 @@ extern int cifs_get_inode_info(struct inode **pinode,
struct super_block *sb, int xid); struct super_block *sb, int xid);
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 int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
const char *); const char *);
...@@ -117,7 +118,7 @@ void cifs_proc_init(void); ...@@ -117,7 +118,7 @@ void cifs_proc_init(void);
void cifs_proc_clean(void); void cifs_proc_clean(void);
extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
struct nls_table * nls_info); struct nls_table *nls_info);
extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses);
extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
...@@ -126,11 +127,11 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -126,11 +127,11 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
const char *searchName, const struct nls_table *nls_codepage, const char *searchName, const struct nls_table *nls_codepage,
__u16 *searchHandle, struct cifs_search_info * psrch_inf, __u16 *searchHandle, struct cifs_search_info *psrch_inf,
int map, const char dirsep); int map, const char dirsep);
extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
__u16 searchHandle, struct cifs_search_info * psrch_inf); __u16 searchHandle, struct cifs_search_info *psrch_inf);
extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
const __u16 search_handle); const __u16 search_handle);
...@@ -142,7 +143,7 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, ...@@ -142,7 +143,7 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, const unsigned char *searchName,
FILE_ALL_INFO * findData, FILE_ALL_INFO *findData,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
extern int CIFSSMBUnixQPathInfo(const int xid, extern int CIFSSMBUnixQPathInfo(const int xid,
...@@ -164,8 +165,10 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ...@@ -164,8 +165,10 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const char *old_path,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
unsigned int *pnum_referrals, unsigned int *pnum_referrals,
unsigned char ** preferrals, unsigned char **preferrals,
int remap); int remap);
extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
struct super_block *sb, struct smb_vol *vol);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
struct kstatfs *FSData); struct kstatfs *FSData);
...@@ -208,7 +211,7 @@ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, ...@@ -208,7 +211,7 @@ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
__u64 size, __u16 fileHandle,__u32 opener_pid, __u64 size, __u16 fileHandle, __u32 opener_pid,
int AllocSizeFlag); int AllocSizeFlag);
extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon, extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon,
char *full_path, __u64 mode, __u64 uid, char *full_path, __u64 mode, __u64 uid,
...@@ -223,7 +226,10 @@ extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, ...@@ -223,7 +226,10 @@ extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
const char *name, const struct nls_table *nls_codepage, const char *name, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon,
const char *name, __u16 type,
const struct nls_table *nls_codepage,
int remap_special_chars);
extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
const char *name, const char *name,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
...@@ -232,8 +238,8 @@ extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, ...@@ -232,8 +238,8 @@ extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
const char *fromName, const char *toName, const char *fromName, const char *toName,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
int netfid, char * target_name, int netfid, char *target_name,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSCreateHardLink(const int xid, extern int CIFSCreateHardLink(const int xid,
...@@ -271,13 +277,18 @@ extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -271,13 +277,18 @@ extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
const int access_flags, const int omode, const int access_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *, __u16 * netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap); const struct nls_table *nls_codepage, int remap);
extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
u32 posix_flags, __u64 mode, __u16 * netfid,
FILE_UNIX_BASIC_INFO *pRetData,
__u32 *pOplock, const char *name,
const struct nls_table *nls_codepage, int remap);
extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
const int smb_file_id); const int smb_file_id);
extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
const int netfid, unsigned int count, const int netfid, unsigned int count,
const __u64 lseek, unsigned int *nbytes, char **buf, const __u64 lseek, unsigned int *nbytes, char **buf,
int * return_buf_type); int *return_buf_type);
extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
const int netfid, const unsigned int count, const int netfid, const unsigned int count,
const __u64 lseek, unsigned int *nbytes, const __u64 lseek, unsigned int *nbytes,
...@@ -292,9 +303,9 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, ...@@ -292,9 +303,9 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
const struct nls_table * codepage); const struct nls_table *codepage);
extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen, extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
const struct nls_table * cp, int mapChars); const struct nls_table *cp, int mapChars);
extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
const __u16 netfid, const __u64 len, const __u16 netfid, const __u64 len,
...@@ -313,21 +324,21 @@ extern void sesInfoFree(struct cifsSesInfo *); ...@@ -313,21 +324,21 @@ extern void sesInfoFree(struct cifsSesInfo *);
extern struct cifsTconInfo *tconInfoAlloc(void); extern struct cifsTconInfo *tconInfoAlloc(void);
extern void tconInfoFree(struct cifsTconInfo *); extern void tconInfoFree(struct cifsTconInfo *);
extern int cifs_reconnect(struct TCP_Server_Info *server); extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
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 *, extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
__u32 *); __u32 *);
extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, extern int cifs_verify_signature(struct smb_hdr *,
const struct mac_key *mac_key,
__u32 expected_sequence_number); __u32 expected_sequence_number);
extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
const char *pass);
extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *,
const struct nls_table *); const struct nls_table *);
extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * ); extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *);
extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
const struct nls_table *); const struct nls_table *);
#ifdef CONFIG_CIFS_WEAK_PW_HASH #ifdef CONFIG_CIFS_WEAK_PW_HASH
extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key); extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key);
#endif /* CIFS_WEAK_PW_HASH */ #endif /* CIFS_WEAK_PW_HASH */
extern int CIFSSMBCopy(int xid, extern int CIFSSMBCopy(int xid,
struct cifsTconInfo *source_tcon, struct cifsTconInfo *source_tcon,
...@@ -337,27 +348,27 @@ extern int CIFSSMBCopy(int xid, ...@@ -337,27 +348,27 @@ extern int CIFSSMBCopy(int xid,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
const int notify_subdirs,const __u16 netfid, const int notify_subdirs, const __u16 netfid,
__u32 filter, struct file * file, int multishot, __u32 filter, struct file *file, int multishot,
const struct nls_table *nls_codepage); const struct nls_table *nls_codepage);
extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, char * EAData, const unsigned char *searchName, char *EAData,
size_t bufsize, const struct nls_table *nls_codepage, size_t bufsize, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon, extern ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
const unsigned char * searchName,const unsigned char * ea_name, const unsigned char *searchName, const unsigned char *ea_name,
unsigned char * ea_value, size_t buf_size, unsigned char *ea_value, size_t buf_size,
const struct nls_table *nls_codepage, int remap_special_chars); const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const char * ea_name, const char *fileName, const char *ea_name,
const void * ea_value, const __u16 ea_value_len, const void *ea_value, const __u16 ea_value_len,
const struct nls_table *nls_codepage, int remap_special_chars); const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
__u16 fid, char *acl_inf, const int buflen, __u16 fid, char *acl_inf, const int buflen,
const int acl_type /* ACCESS vs. DEFAULT */); const int acl_type /* ACCESS vs. DEFAULT */);
extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, const unsigned char *searchName,
char *acl_inf, const int buflen,const int acl_type, char *acl_inf, const int buflen, const int acl_type,
const struct nls_table *nls_codepage, int remap_special_chars); const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
const unsigned char *fileName, const unsigned char *fileName,
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/* /*
* fs/cifs/connect.c * fs/cifs/connect.c
* *
* Copyright (C) International Business Machines Corp., 2002,2006 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/freezer.h> #include <linux/freezer.h>
#endif /* 2.6.19 */ #endif /* 2.6.19 */
#endif #endif
#include <linux/kthread.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/processor.h> #include <asm/processor.h>
#include "cifspdu.h" #include "cifspdu.h"
...@@ -56,6 +57,7 @@ ...@@ -56,6 +57,7 @@
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7)
#define sock_create_kern sock_create #define sock_create_kern sock_create
#endif #endif
static DECLARE_COMPLETION(cifsd_complete); static DECLARE_COMPLETION(cifsd_complete);
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
...@@ -88,6 +90,8 @@ struct smb_vol { ...@@ -88,6 +90,8 @@ struct smb_vol {
unsigned retry:1; unsigned retry:1;
unsigned intr:1; unsigned intr:1;
unsigned setuids:1; unsigned setuids:1;
unsigned override_uid:1;
unsigned override_gid:1;
unsigned noperm:1; unsigned noperm:1;
unsigned no_psx_acl:1; /* set if posix acl support should be disabled */ unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
unsigned cifs_acl:1; unsigned cifs_acl:1;
...@@ -96,6 +100,7 @@ struct smb_vol { ...@@ -96,6 +100,7 @@ struct smb_vol {
unsigned direct_io:1; unsigned direct_io:1;
unsigned remap:1; /* set to remap seven reserved chars in filenames */ unsigned remap:1; /* set to remap seven reserved chars in filenames */
unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
unsigned no_linux_ext:1;
unsigned sfu_emul:1; unsigned sfu_emul:1;
unsigned nullauth:1; /* attempt to authenticate with null user */ unsigned nullauth:1; /* attempt to authenticate with null user */
unsigned nocase; /* request case insensitive filenames */ unsigned nocase; /* request case insensitive filenames */
...@@ -104,13 +109,13 @@ struct smb_vol { ...@@ -104,13 +109,13 @@ struct smb_vol {
unsigned int wsize; unsigned int wsize;
unsigned int sockopt; unsigned int sockopt;
unsigned short int port; unsigned short int port;
char * prepath; char *prepath;
}; };
static int ipv4_connect(struct sockaddr_in *psin_server, static int ipv4_connect(struct sockaddr_in *psin_server,
struct socket **csocket, struct socket **csocket,
char * netb_name, char *netb_name,
char * server_netb_name); char *server_netb_name);
static int ipv6_connect(struct sockaddr_in6 *psin_server, static int ipv6_connect(struct sockaddr_in6 *psin_server,
struct socket **csocket); struct socket **csocket);
...@@ -124,17 +129,17 @@ static int ipv6_connect(struct sockaddr_in6 *psin_server, ...@@ -124,17 +129,17 @@ static int ipv6_connect(struct sockaddr_in6 *psin_server,
* wake up waiters on reconnection? - (not needed currently) * wake up waiters on reconnection? - (not needed currently)
*/ */
int static int
cifs_reconnect(struct TCP_Server_Info *server) cifs_reconnect(struct TCP_Server_Info *server)
{ {
int rc = 0; int rc = 0;
struct list_head *tmp; struct list_head *tmp;
struct cifsSesInfo *ses; struct cifsSesInfo *ses;
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
struct mid_q_entry * mid_entry; struct mid_q_entry *mid_entry;
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if(server->tcpStatus == CifsExiting) { if (kthread_should_stop()) {
/* the demux thread will exit normally /* the demux thread will exit normally
next time through the loop */ next time through the loop */
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -161,18 +166,18 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -161,18 +166,18 @@ cifs_reconnect(struct TCP_Server_Info *server)
} }
list_for_each(tmp, &GlobalTreeConnectionList) { list_for_each(tmp, &GlobalTreeConnectionList) {
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
if((tcon) && (tcon->ses) && (tcon->ses->server == server)) { if ((tcon) && (tcon->ses) && (tcon->ses->server == server))
tcon->tidStatus = CifsNeedReconnect; tcon->tidStatus = CifsNeedReconnect;
} }
}
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
/* do not want to be sending data on a socket we are freeing */ /* do not want to be sending data on a socket we are freeing */
down(&server->tcpSem); down(&server->tcpSem);
if(server->ssocket) { if (server->ssocket) {
cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state, cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
server->ssocket->flags)); server->ssocket->flags));
server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN); server->ssocket->ops->shutdown(server->ssocket, SEND_SHUTDOWN);
cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state, cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
server->ssocket->state,
server->ssocket->flags)); server->ssocket->flags));
sock_release(server->ssocket); sock_release(server->ssocket);
server->ssocket = NULL; server->ssocket = NULL;
...@@ -183,8 +188,8 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -183,8 +188,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
mid_entry = list_entry(tmp, struct mid_entry = list_entry(tmp, struct
mid_q_entry, mid_q_entry,
qhead); qhead);
if(mid_entry) { if (mid_entry) {
if(mid_entry->midState == MID_REQUEST_SUBMITTED) { if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
/* Mark other intransit requests as needing /* Mark other intransit requests as needing
retry so we do not immediately mark the retry so we do not immediately mark the
session bad again (ie after we reconnect session bad again (ie after we reconnect
...@@ -196,26 +201,26 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -196,26 +201,26 @@ cifs_reconnect(struct TCP_Server_Info *server)
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
up(&server->tcpSem); up(&server->tcpSem);
while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12)
try_to_freeze(); try_to_freeze();
#endif #endif
if(server->protocolType == IPV6) { if (server->protocolType == IPV6) {
rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket); rc = ipv6_connect(&server->addr.sockAddr6,
&server->ssocket);
} else { } else {
rc = ipv4_connect(&server->addr.sockAddr, rc = ipv4_connect(&server->addr.sockAddr,
&server->ssocket, &server->ssocket,
server->workstation_RFC1001_name, server->workstation_RFC1001_name,
server->server_RFC1001_name); server->server_RFC1001_name);
} }
if(rc) { if (rc) {
cFYI(1,("reconnect error %d",rc)); cFYI(1, ("reconnect error %d", rc));
msleep(3000); msleep(3000);
} else { } else {
atomic_inc(&tcpSesReconnectCount); atomic_inc(&tcpSesReconnectCount);
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if(server->tcpStatus != CifsExiting) if (!kthread_should_stop())
server->tcpStatus = CifsGood; server->tcpStatus = CifsGood;
server->sequence_number = 0; server->sequence_number = 0;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -233,20 +238,20 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -233,20 +238,20 @@ cifs_reconnect(struct TCP_Server_Info *server)
-EINVAL = invalid transact2 -EINVAL = invalid transact2
*/ */
static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize) static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
{ {
struct smb_t2_rsp * pSMBt; struct smb_t2_rsp *pSMBt;
int total_data_size; int total_data_size;
int data_in_this_rsp; int data_in_this_rsp;
int remaining; int remaining;
if(pSMB->Command != SMB_COM_TRANSACTION2) if (pSMB->Command != SMB_COM_TRANSACTION2)
return 0; return 0;
/* check for plausible wct, bcc and t2 data and parm sizes */ /* check for plausible wct, bcc and t2 data and parm sizes */
/* check for parm and data offset going beyond end of smb */ /* check for parm and data offset going beyond end of smb */
if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */ if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
cFYI(1,("invalid transact2 word count")); cFYI(1, ("invalid transact2 word count"));
return -EINVAL; return -EINVAL;
} }
...@@ -257,25 +262,25 @@ static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize) ...@@ -257,25 +262,25 @@ static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
remaining = total_data_size - data_in_this_rsp; remaining = total_data_size - data_in_this_rsp;
if(remaining == 0) if (remaining == 0)
return 0; return 0;
else if(remaining < 0) { else if (remaining < 0) {
cFYI(1,("total data %d smaller than data in frame %d", cFYI(1, ("total data %d smaller than data in frame %d",
total_data_size, data_in_this_rsp)); total_data_size, data_in_this_rsp));
return -EINVAL; return -EINVAL;
} else { } else {
cFYI(1,("missing %d bytes from transact2, check next response", cFYI(1, ("missing %d bytes from transact2, check next response",
remaining)); remaining));
if(total_data_size > maxBufSize) { if (total_data_size > maxBufSize) {
cERROR(1,("TotalDataSize %d is over maximum buffer %d", cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
total_data_size,maxBufSize)); total_data_size, maxBufSize));
return -EINVAL; return -EINVAL;
} }
return remaining; return remaining;
} }
} }
static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
{ {
struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond; struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB; struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
...@@ -283,29 +288,29 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) ...@@ -283,29 +288,29 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
int total_in_buf; int total_in_buf;
int remaining; int remaining;
int total_in_buf2; int total_in_buf2;
char * data_area_of_target; char *data_area_of_target;
char * data_area_of_buf2; char *data_area_of_buf2;
__u16 byte_count; __u16 byte_count;
total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) { if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
cFYI(1,("total data sizes of primary and secondary t2 differ")); cFYI(1, ("total data size of primary and secondary t2 differ"));
} }
total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount); total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
remaining = total_data_size - total_in_buf; remaining = total_data_size - total_in_buf;
if(remaining < 0) if (remaining < 0)
return -EINVAL; return -EINVAL;
if(remaining == 0) /* nothing to do, ignore */ if (remaining == 0) /* nothing to do, ignore */
return 0; return 0;
total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount); total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
if(remaining < total_in_buf2) { if (remaining < total_in_buf2) {
cFYI(1,("transact2 2nd response contains too much data")); cFYI(1, ("transact2 2nd response contains too much data"));
} }
/* find end of first SMB data area */ /* find end of first SMB data area */
...@@ -319,7 +324,7 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) ...@@ -319,7 +324,7 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
data_area_of_target += total_in_buf; data_area_of_target += total_in_buf;
/* copy second buffer into end of first buffer */ /* copy second buffer into end of first buffer */
memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2); memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
total_in_buf += total_in_buf2; total_in_buf += total_in_buf2;
pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf); pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
byte_count = le16_to_cpu(BCC_LE(pTargetSMB)); byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
...@@ -333,8 +338,8 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) ...@@ -333,8 +338,8 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
pTargetSMB->smb_buf_length = byte_count; pTargetSMB->smb_buf_length = byte_count;
if(remaining == total_in_buf2) { if (remaining == total_in_buf2) {
cFYI(1,("found the last secondary response")); cFYI(1, ("found the last secondary response"));
return 0; /* we are done */ return 0; /* we are done */
} else /* more responses to go */ } else /* more responses to go */
return 1; return 1;
...@@ -367,10 +372,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -367,10 +372,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
daemonize(); daemonize();
sprintf(current->comm,"cifsd"); sprintf(current->comm,"cifsd");
#else
daemonize("cifsd");
allow_signal(SIGKILL);
#endif #endif
current->flags |= PF_MEMALLOC; current->flags |= PF_MEMALLOC;
server->tsk = current; /* save process info to wake at shutdown */ server->tsk = current; /* save process info to wake at shutdown */
cFYI(1, ("Demultiplex PID: %d", current->pid)); cFYI(1, ("Demultiplex PID: %d", current->pid));
...@@ -380,19 +383,19 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -380,19 +383,19 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
complete(&cifsd_complete); complete(&cifsd_complete);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10)
if(length > 1) { if (length > 1)
mempool_resize(cifs_req_poolp, mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
length + cifs_min_rcv,
GFP_KERNEL); GFP_KERNEL);
}
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
temp_fs = get_fs(); /* we must turn off socket api parm checking */ temp_fs = get_fs(); /* we must turn off socket api parm checking */
set_fs(get_ds()); set_fs(get_ds());
#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
set_freezable();
#endif #endif
while (server->tcpStatus != CifsExiting) { while (!kthread_should_stop()) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12)
if (try_to_freeze()) if (try_to_freeze())
continue; continue;
...@@ -407,7 +410,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -407,7 +410,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
} else if (isLargeBuf) { } else if (isLargeBuf) {
/* we are reusing a dirty large buf, clear its start */ /* we are reusing a dirty large buf, clear its start */
memset(bigbuf, 0, sizeof (struct smb_hdr)); memset(bigbuf, 0, sizeof(struct smb_hdr));
} }
if (smallbuf == NULL) { if (smallbuf == NULL) {
...@@ -420,7 +423,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -420,7 +423,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
/* beginning of smb buffer is cleared in our buf_get */ /* beginning of smb buffer is cleared in our buf_get */
} else /* if existing small buf clear beginning */ } else /* if existing small buf clear beginning */
memset(smallbuf, 0, sizeof (struct smb_hdr)); memset(smallbuf, 0, sizeof(struct smb_hdr));
isLargeBuf = FALSE; isLargeBuf = FALSE;
isMultiRsp = FALSE; isMultiRsp = FALSE;
...@@ -429,16 +432,20 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -429,16 +432,20 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
iov.iov_len = 4; iov.iov_len = 4;
smb_msg.msg_control = NULL; smb_msg.msg_control = NULL;
smb_msg.msg_controllen = 0; smb_msg.msg_controllen = 0;
pdu_length = 4; /* enought to get RFC1001 header */
incomplete_rcv:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
smb_msg.msg_iov = &iov; smb_msg.msg_iov = &iov;
smb_msg.msg_iovlen = 1; smb_msg.msg_iovlen = 1;
length = length =
sock_recvmsg(csocket, &smb_msg, 4 /* RFC1001 len */, 0); sock_recvmsg(csocket, &smb_msg, pdu_length, 0);
#else #else
length = kernel_recvmsg(csocket, &smb_msg, length =
&iov, 1, 4, 0 /* BB see socket.h flags */); kernel_recvmsg(csocket, &smb_msg,
&iov, 1, pdu_length, 0 /* BB other flags? */);
#endif #endif
if (server->tcpStatus == CifsExiting) {
if (kthread_should_stop()) {
break; break;
} else if (server->tcpStatus == CifsNeedReconnect) { } else if (server->tcpStatus == CifsNeedReconnect) {
cFYI(1, ("Reconnect after server stopped responding")); cFYI(1, ("Reconnect after server stopped responding"));
...@@ -465,23 +472,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -465,23 +472,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
#else #else
if (length == -EINTR) { if (length == -EINTR) {
#endif #endif
cFYI(1,("cifsd thread killed")); cFYI(1, ("cifsd thread killed"));
break; break;
} }
cFYI(1,("Reconnect after unexpected peek error %d", cFYI(1, ("Reconnect after unexpected peek error %d",
length)); length));
cifs_reconnect(server); cifs_reconnect(server);
csocket = server->ssocket; csocket = server->ssocket;
wake_up(&server->response_q); wake_up(&server->response_q);
continue; continue;
} else if (length < 4) { } else if (length < 4) {
cFYI(1, cFYI(1, ("less than four bytes received (%d bytes)",
("Frame under four bytes received (%d bytes long)",
length)); length));
cifs_reconnect(server); pdu_length -= length;
csocket = server->ssocket; msleep(1);
wake_up(&server->response_q); goto incomplete_rcv;
continue;
} }
/* The right amount was read from socket - 4 bytes */ /* The right amount was read from socket - 4 bytes */
...@@ -498,19 +503,19 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -498,19 +503,19 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
pdu_length = ntohl(smb_buffer->smb_buf_length); pdu_length = ntohl(smb_buffer->smb_buf_length);
smb_buffer->smb_buf_length = pdu_length; smb_buffer->smb_buf_length = pdu_length;
cFYI(1,("rfc1002 length 0x%x)", pdu_length+4)); cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) { if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
continue; continue;
} else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
cFYI(1,("Good RFC 1002 session rsp")); cFYI(1, ("Good RFC 1002 session rsp"));
continue; continue;
} else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
/* we get this from Windows 98 instead of /* we get this from Windows 98 instead of
an error on SMB negprot response */ an error on SMB negprot response */
cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
pdu_length)); pdu_length));
if(server->tcpStatus == CifsNew) { if (server->tcpStatus == CifsNew) {
/* if nack on negprot (rather than /* if nack on negprot (rather than
ret of smb negprot error) reconnecting ret of smb negprot error) reconnecting
not going to help, ret error to mount */ not going to help, ret error to mount */
...@@ -532,7 +537,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -532,7 +537,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
continue; continue;
} }
} else if (temp != (char) 0) { } else if (temp != (char) 0) {
cERROR(1,("Unknown RFC 1002 frame")); cERROR(1, ("Unknown RFC 1002 frame"));
cifs_dump_mem(" Received Data: ", (char *)smb_buffer, cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
length); length);
cifs_reconnect(server); cifs_reconnect(server);
...@@ -541,8 +546,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -541,8 +546,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
/* else we have an SMB response */ /* else we have an SMB response */
if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
(pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) {
cERROR(1, ("Invalid size SMB length %d pdu_length %d", cERROR(1, ("Invalid size SMB length %d pdu_length %d",
length, pdu_length+4)); length, pdu_length+4));
cifs_reconnect(server); cifs_reconnect(server);
...@@ -554,7 +559,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -554,7 +559,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
/* else length ok */ /* else length ok */
reconnect = 0; reconnect = 0;
if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
isLargeBuf = TRUE; isLargeBuf = TRUE;
memcpy(bigbuf, smallbuf, 4); memcpy(bigbuf, smallbuf, 4);
smb_buffer = bigbuf; smb_buffer = bigbuf;
...@@ -571,7 +576,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -571,7 +576,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
pdu_length - total_read, 0); pdu_length - total_read, 0);
#endif #endif
if((server->tcpStatus == CifsExiting) || if (kthread_should_stop() ||
(length == -EINTR)) { (length == -EINTR)) {
/* then will exit */ /* then will exit */
reconnect = 2; reconnect = 2;
...@@ -591,7 +596,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -591,7 +596,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
CifsNeedReconnect if server hung*/ CifsNeedReconnect if server hung*/
continue; continue;
} else if (length <= 0) { } else if (length <= 0) {
cERROR(1,("Received no data, expecting %d", cERROR(1, ("Received no data, expecting %d",
pdu_length - total_read)); pdu_length - total_read));
cifs_reconnect(server); cifs_reconnect(server);
csocket = server->ssocket; csocket = server->ssocket;
...@@ -599,9 +604,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -599,9 +604,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
break; break;
} }
} }
if(reconnect == 2) if (reconnect == 2)
break; break;
else if(reconnect == 1) else if (reconnect == 1)
continue; continue;
length += 4; /* account for rfc1002 hdr */ length += 4; /* account for rfc1002 hdr */
...@@ -622,12 +627,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -622,12 +627,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
if ((mid_entry->mid == smb_buffer->Mid) && if ((mid_entry->mid == smb_buffer->Mid) &&
(mid_entry->midState == MID_REQUEST_SUBMITTED) && (mid_entry->midState == MID_REQUEST_SUBMITTED) &&
(mid_entry->command == smb_buffer->Command)) { (mid_entry->command == smb_buffer->Command)) {
if(check2ndT2(smb_buffer,server->maxBuf) > 0) { if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
/* We have a multipart transact2 resp */ /* We have a multipart transact2 resp */
isMultiRsp = TRUE; isMultiRsp = TRUE;
if(mid_entry->resp_buf) { if (mid_entry->resp_buf) {
/* merge response - fix up 1st*/ /* merge response - fix up 1st*/
if(coalesce_t2(smb_buffer, if (coalesce_t2(smb_buffer,
mid_entry->resp_buf)) { mid_entry->resp_buf)) {
mid_entry->multiRsp = 1; mid_entry->multiRsp = 1;
break; break;
...@@ -637,7 +642,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -637,7 +642,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
goto multi_t2_fnd; goto multi_t2_fnd;
} }
} else { } else {
if(!isLargeBuf) { if (!isLargeBuf) {
cERROR(1,("1st trans2 resp needs bigbuf")); cERROR(1,("1st trans2 resp needs bigbuf"));
/* BB maybe we can fix this up, switch /* BB maybe we can fix this up, switch
to already allocated large buffer? */ to already allocated large buffer? */
...@@ -652,7 +657,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -652,7 +657,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
break; break;
} }
mid_entry->resp_buf = smb_buffer; mid_entry->resp_buf = smb_buffer;
if(isLargeBuf) if (isLargeBuf)
mid_entry->largeBuf = 1; mid_entry->largeBuf = 1;
else else
mid_entry->largeBuf = 0; mid_entry->largeBuf = 0;
...@@ -672,18 +677,19 @@ multi_t2_fnd: ...@@ -672,18 +677,19 @@ multi_t2_fnd:
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
if (task_to_wake) { if (task_to_wake) {
/* Was previous buf put in mpx struct for multi-rsp? */ /* Was previous buf put in mpx struct for multi-rsp? */
if(!isMultiRsp) { if (!isMultiRsp) {
/* smb buffer will be freed by user thread */ /* smb buffer will be freed by user thread */
if(isLargeBuf) { if (isLargeBuf)
bigbuf = NULL; bigbuf = NULL;
} else else
smallbuf = NULL; smallbuf = NULL;
} }
wake_up_process(task_to_wake); wake_up_process(task_to_wake);
} else if ((is_valid_oplock_break(smb_buffer, server) == FALSE) } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
&& (isMultiRsp == FALSE)) { && (isMultiRsp == FALSE)) {
cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter)); cERROR(1, ("No task to wake, unknown frame received! "
cifs_dump_mem("Received Data is: ",(char *)smb_buffer, "NumMids %d", midCount.counter));
cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
sizeof(struct smb_hdr)); sizeof(struct smb_hdr));
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
cifs_dump_detail(smb_buffer); cifs_dump_detail(smb_buffer);
...@@ -699,7 +705,7 @@ multi_t2_fnd: ...@@ -699,7 +705,7 @@ multi_t2_fnd:
/* check if we have blocked requests that need to free */ /* check if we have blocked requests that need to free */
/* Note that cifs_max_pending is normally 50, but /* Note that cifs_max_pending is normally 50, but
can be set at module install time to as little as two */ can be set at module install time to as little as two */
if(atomic_read(&server->inFlight) >= cifs_max_pending) if (atomic_read(&server->inFlight) >= cifs_max_pending)
atomic_set(&server->inFlight, cifs_max_pending - 1); atomic_set(&server->inFlight, cifs_max_pending - 1);
/* We do not want to set the max_pending too low or we /* We do not want to set the max_pending too low or we
could end up with the counter going negative */ could end up with the counter going negative */
...@@ -713,11 +719,10 @@ multi_t2_fnd: ...@@ -713,11 +719,10 @@ multi_t2_fnd:
/* give those requests time to exit */ /* give those requests time to exit */
msleep(125); msleep(125);
if(server->ssocket) { if (server->ssocket) {
sock_release(csocket); sock_release(csocket);
server->ssocket = NULL; server->ssocket = NULL;
} }
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
set_fs(temp_fs); set_fs(temp_fs);
#endif #endif
...@@ -748,23 +753,21 @@ multi_t2_fnd: ...@@ -748,23 +753,21 @@ multi_t2_fnd:
list_for_each(tmp, &GlobalSMBSessionList) { list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo, ses = list_entry(tmp, struct cifsSesInfo,
cifsSessionList); cifsSessionList);
if (ses->server == server) { if (ses->server == server)
ses->status = CifsExiting; ses->status = CifsExiting;
} }
}
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
list_for_each(tmp, &server->pending_mid_q) { list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead); mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
if (mid_entry->midState == MID_REQUEST_SUBMITTED) { if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
cFYI(1, cFYI(1, ("Clearing Mid 0x%x - waking up ",
("Clearing Mid 0x%x - waking up ",mid_entry->mid)); mid_entry->mid));
task_to_wake = mid_entry->tsk; task_to_wake = mid_entry->tsk;
if(task_to_wake) { if (task_to_wake)
wake_up_process(task_to_wake); wake_up_process(task_to_wake);
} }
} }
}
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
/* 1/8th of sec is more than enough time for them to exit */ /* 1/8th of sec is more than enough time for them to exit */
...@@ -795,27 +798,25 @@ multi_t2_fnd: ...@@ -795,27 +798,25 @@ multi_t2_fnd:
list_for_each(tmp, &GlobalSMBSessionList) { list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo, ses = list_entry(tmp, struct cifsSesInfo,
cifsSessionList); cifsSessionList);
if (ses->server == server) { if (ses->server == server)
ses->server = NULL; ses->server = NULL;
} }
}
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
kfree(server); kfree(server);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
if(length > 0) { if (length > 0)
mempool_resize(cifs_req_poolp, mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
length + cifs_min_rcv,
GFP_KERNEL); GFP_KERNEL);
}
#endif #endif
complete_and_exit(&cifsd_complete, 0); /* BB PORT - do we need complete_and_exit here? BB */
return 0; return 0;
} }
static int static int
cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) cifs_parse_mount_options(char *options, const char *devname,
struct smb_vol *vol)
{ {
char *value; char *value;
char *data; char *data;
...@@ -825,22 +826,22 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -825,22 +826,22 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
separator[0] = ','; separator[0] = ',';
separator[1] = 0; separator[1] = 0;
memset(vol->source_rfc1001_name,0x20,15); if (Local_System_Name[0] != 0)
memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
else {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
for(i=0;i < strnlen(utsname()->nodename,15);i++) { char *nodename = utsname()->nodename;
/* does not have to be a perfect mapping since the field is
informational, only used for servers that do not support
port 445 and it can be overridden at mount time */
vol->source_rfc1001_name[i] =
toupper(utsname()->nodename[i]);
#else #else
for(i=0;i < strnlen(system_utsname.nodename,15);i++) { char *nodename = system_utsname.nodename;
/* does not have to be a perfect mapping since the field is #endif
int n = strnlen(nodename, 15);
memset(vol->source_rfc1001_name, 0x20, 15);
for (i = 0; i < n; i++) {
/* does not have to be perfect mapping since field is
informational, only used for servers that do not support informational, only used for servers that do not support
port 445 and it can be overridden at mount time */ port 445 and it can be overridden at mount time */
vol->source_rfc1001_name[i] = vol->source_rfc1001_name[i] = toupper(nodename[i]);
toupper(system_utsname.nodename[i]); }
#endif
} }
vol->source_rfc1001_name[15] = 0; vol->source_rfc1001_name[15] = 0;
/* null target name indicates to use *SMBSERVR default called name /* null target name indicates to use *SMBSERVR default called name
...@@ -860,12 +861,12 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -860,12 +861,12 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
if (!options) if (!options)
return 1; return 1;
if(strncmp(options,"sep=",4) == 0) { if (strncmp(options, "sep=", 4) == 0) {
if(options[4] != 0) { if (options[4] != 0) {
separator[0] = options[4]; separator[0] = options[4];
options += 5; options += 5;
} else { } else {
cFYI(1,("Null separator not allowed")); cFYI(1, ("Null separator not allowed"));
} }
} }
...@@ -875,16 +876,17 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -875,16 +876,17 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
if ((value = strchr(data, '=')) != NULL) if ((value = strchr(data, '=')) != NULL)
*value++ = '\0'; *value++ = '\0';
if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/ /* Have to parse this before we parse for "user" */
if (strnicmp(data, "user_xattr", 10) == 0) {
vol->no_xattr = 0; vol->no_xattr = 0;
} else if (strnicmp(data, "nouser_xattr",12) == 0) { } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
vol->no_xattr = 1; vol->no_xattr = 1;
} else if (strnicmp(data, "user", 4) == 0) { } else if (strnicmp(data, "user", 4) == 0) {
if (!value) { if (!value) {
printk(KERN_WARNING printk(KERN_WARNING
"CIFS: invalid or missing username\n"); "CIFS: invalid or missing username\n");
return 1; /* needs_arg; */ return 1; /* needs_arg; */
} else if(!*value) { } else if (!*value) {
/* null user, ie anonymous, authentication */ /* null user, ie anonymous, authentication */
vol->nullauth = 1; vol->nullauth = 1;
} }
...@@ -898,12 +900,12 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -898,12 +900,12 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
if (!value) { if (!value) {
vol->password = NULL; vol->password = NULL;
continue; continue;
} else if(value[0] == 0) { } else if (value[0] == 0) {
/* check if string begins with double comma /* check if string begins with double comma
since that would mean the password really since that would mean the password really
does start with a comma, and would not does start with a comma, and would not
indicate an empty string */ indicate an empty string */
if(value[1] != separator[0]) { if (value[1] != separator[0]) {
vol->password = NULL; vol->password = NULL;
continue; continue;
} }
...@@ -926,8 +928,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -926,8 +928,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
(value[temp_len+1] == separator[0])) { (value[temp_len+1] == separator[0])) {
/* reinsert comma */ /* reinsert comma */
value[temp_len] = separator[0]; value[temp_len] = separator[0];
temp_len+=2; /* move after the second comma */ temp_len += 2; /* move after second comma */
while(value[temp_len] != 0) { while (value[temp_len] != 0) {
if (value[temp_len] == separator[0]) { if (value[temp_len] == separator[0]) {
if (value[temp_len+1] == if (value[temp_len+1] ==
separator[0]) { separator[0]) {
...@@ -941,7 +943,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -941,7 +943,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
} }
temp_len++; temp_len++;
} }
if(value[temp_len] == 0) { if (value[temp_len] == 0) {
options = NULL; options = NULL;
} else { } else {
value[temp_len] = 0; value[temp_len] = 0;
...@@ -952,13 +954,14 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -952,13 +954,14 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
double commas to singles. Note that this ends up double commas to singles. Note that this ends up
allocating a few bytes too many, which is ok */ allocating a few bytes too many, which is ok */
vol->password = kzalloc(temp_len, GFP_KERNEL); vol->password = kzalloc(temp_len, GFP_KERNEL);
if(vol->password == NULL) { if (vol->password == NULL) {
printk("CIFS: no memory for pass\n"); printk(KERN_WARNING "CIFS: no memory "
"for password\n");
return 1; return 1;
} }
for(i=0,j=0;i<temp_len;i++,j++) { for (i = 0, j = 0; i < temp_len; i++, j++) {
vol->password[j] = value[i]; vol->password[j] = value[i];
if(value[i] == separator[0] if (value[i] == separator[0]
&& value[i+1] == separator[0]) { && value[i+1] == separator[0]) {
/* skip second comma */ /* skip second comma */
i++; i++;
...@@ -967,8 +970,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -967,8 +970,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->password[j] = 0; vol->password[j] = 0;
} else { } else {
vol->password = kzalloc(temp_len+1, GFP_KERNEL); vol->password = kzalloc(temp_len+1, GFP_KERNEL);
if(vol->password == NULL) { if (vol->password == NULL) {
printk("CIFS: no memory for pass\n"); printk(KERN_WARNING "CIFS: no memory "
"for password\n");
return 1; return 1;
} }
strcpy(vol->password, value); strcpy(vol->password, value);
...@@ -979,12 +983,13 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -979,12 +983,13 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
} else if (strnlen(value, 35) < 35) { } else if (strnlen(value, 35) < 35) {
vol->UNCip = value; vol->UNCip = value;
} else { } else {
printk(KERN_WARNING "CIFS: ip address too long\n"); printk(KERN_WARNING "CIFS: ip address "
"too long\n");
return 1; return 1;
} }
} else if (strnicmp(data, "sec", 3) == 0) { } else if (strnicmp(data, "sec", 3) == 0) {
if (!value || !*value) { if (!value || !*value) {
cERROR(1,("no security value specified")); cERROR(1, ("no security value specified"));
continue; continue;
} else if (strnicmp(value, "krb5i", 5) == 0) { } else if (strnicmp(value, "krb5i", 5) == 0) {
vol->secFlg |= CIFSSEC_MAY_KRB5 | vol->secFlg |= CIFSSEC_MAY_KRB5 |
...@@ -992,7 +997,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -992,7 +997,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
} else if (strnicmp(value, "krb5p", 5) == 0) { } else if (strnicmp(value, "krb5p", 5) == 0) {
/* vol->secFlg |= CIFSSEC_MUST_SEAL | /* vol->secFlg |= CIFSSEC_MUST_SEAL |
CIFSSEC_MAY_KRB5; */ CIFSSEC_MAY_KRB5; */
cERROR(1,("Krb5 cifs privacy not supported")); cERROR(1, ("Krb5 cifs privacy not supported"));
return 1; return 1;
} else if (strnicmp(value, "krb5", 4) == 0) { } else if (strnicmp(value, "krb5", 4) == 0) {
vol->secFlg |= CIFSSEC_MAY_KRB5; vol->secFlg |= CIFSSEC_MAY_KRB5;
...@@ -1017,28 +1022,29 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -1017,28 +1022,29 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
} else if (strnicmp(value, "none", 4) == 0) { } else if (strnicmp(value, "none", 4) == 0) {
vol->nullauth = 1; vol->nullauth = 1;
} else { } else {
cERROR(1,("bad security option: %s", value)); cERROR(1, ("bad security option: %s", value));
return 1; return 1;
} }
} else if ((strnicmp(data, "unc", 3) == 0) } else if ((strnicmp(data, "unc", 3) == 0)
|| (strnicmp(data, "target", 6) == 0) || (strnicmp(data, "target", 6) == 0)
|| (strnicmp(data, "path", 4) == 0)) { || (strnicmp(data, "path", 4) == 0)) {
if (!value || !*value) { if (!value || !*value) {
printk(KERN_WARNING printk(KERN_WARNING "CIFS: invalid path to "
"CIFS: invalid path to network resource\n"); "network resource\n");
return 1; /* needs_arg; */ return 1; /* needs_arg; */
} }
if ((temp_len = strnlen(value, 300)) < 300) { if ((temp_len = strnlen(value, 300)) < 300) {
vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
if(vol->UNC == NULL) if (vol->UNC == NULL)
return 1; return 1;
strcpy(vol->UNC,value); strcpy(vol->UNC, value);
if (strncmp(vol->UNC, "//", 2) == 0) { if (strncmp(vol->UNC, "//", 2) == 0) {
vol->UNC[0] = '\\'; vol->UNC[0] = '\\';
vol->UNC[1] = '\\'; vol->UNC[1] = '\\';
} else if (strncmp(vol->UNC, "\\\\", 2) != 0) { } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
printk(KERN_WARNING printk(KERN_WARNING
"CIFS: UNC Path does not begin with // or \\\\ \n"); "CIFS: UNC Path does not begin "
"with // or \\\\ \n");
return 1; return 1;
} }
} else { } else {
...@@ -1057,54 +1063,60 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -1057,54 +1063,60 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->domainname = value; vol->domainname = value;
cFYI(1, ("Domain name set")); cFYI(1, ("Domain name set"));
} else { } else {
printk(KERN_WARNING "CIFS: domain name too long\n"); printk(KERN_WARNING "CIFS: domain name too "
"long\n");
return 1; return 1;
} }
} else if (strnicmp(data, "prefixpath", 10) == 0) { } else if (strnicmp(data, "prefixpath", 10) == 0) {
if (!value || !*value) { if (!value || !*value) {
printk(KERN_WARNING printk(KERN_WARNING
"CIFS: invalid path prefix\n"); "CIFS: invalid path prefix\n");
return 1; /* needs_arg; */ return 1; /* needs_argument */
} }
if ((temp_len = strnlen(value, 1024)) < 1024) { if ((temp_len = strnlen(value, 1024)) < 1024) {
if(value[0] != '/') if (value[0] != '/')
temp_len++; /* missing leading slash */ temp_len++; /* missing leading slash */
vol->prepath = kmalloc(temp_len+1,GFP_KERNEL); vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
if(vol->prepath == NULL) if (vol->prepath == NULL)
return 1; return 1;
if(value[0] != '/') { if (value[0] != '/') {
vol->prepath[0] = '/'; vol->prepath[0] = '/';
strcpy(vol->prepath+1,value); strcpy(vol->prepath+1, value);
} else } else
strcpy(vol->prepath,value); strcpy(vol->prepath, value);
cFYI(1,("prefix path %s",vol->prepath)); cFYI(1, ("prefix path %s", vol->prepath));
} else { } else {
printk(KERN_WARNING "CIFS: prefix too long\n"); printk(KERN_WARNING "CIFS: prefix too long\n");
return 1; return 1;
} }
} else if (strnicmp(data, "iocharset", 9) == 0) { } else if (strnicmp(data, "iocharset", 9) == 0) {
if (!value || !*value) { if (!value || !*value) {
printk(KERN_WARNING "CIFS: invalid iocharset specified\n"); printk(KERN_WARNING "CIFS: invalid iocharset "
"specified\n");
return 1; /* needs_arg; */ return 1; /* needs_arg; */
} }
if (strnlen(value, 65) < 65) { if (strnlen(value, 65) < 65) {
if(strnicmp(value,"default",7)) if (strnicmp(value, "default", 7))
vol->iocharset = value; vol->iocharset = value;
/* if iocharset not set load_nls_default used by caller */ /* if iocharset not set then load_nls_default
cFYI(1, ("iocharset set to %s",value)); is used by caller */
cFYI(1, ("iocharset set to %s", value));
} else { } else {
printk(KERN_WARNING "CIFS: iocharset name too long.\n"); printk(KERN_WARNING "CIFS: iocharset name "
"too long.\n");
return 1; return 1;
} }
} else if (strnicmp(data, "uid", 3) == 0) { } else if (strnicmp(data, "uid", 3) == 0) {
if (value && *value) { if (value && *value) {
vol->linux_uid = vol->linux_uid =
simple_strtoul(value, &value, 0); simple_strtoul(value, &value, 0);
vol->override_uid = 1;
} }
} else if (strnicmp(data, "gid", 3) == 0) { } else if (strnicmp(data, "gid", 3) == 0) {
if (value && *value) { if (value && *value) {
vol->linux_gid = vol->linux_gid =
simple_strtoul(value, &value, 0); simple_strtoul(value, &value, 0);
vol->override_gid = 1;
} }
} else if (strnicmp(data, "file_mode", 4) == 0) { } else if (strnicmp(data, "file_mode", 4) == 0) {
if (value && *value) { if (value && *value) {
...@@ -1143,54 +1155,59 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -1143,54 +1155,59 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
} }
} else if (strnicmp(data, "netbiosname", 4) == 0) { } else if (strnicmp(data, "netbiosname", 4) == 0) {
if (!value || !*value || (*value == ' ')) { if (!value || !*value || (*value == ' ')) {
cFYI(1,("invalid (empty) netbiosname specified")); cFYI(1, ("invalid (empty) netbiosname"));
} else { } else {
memset(vol->source_rfc1001_name,0x20,15); memset(vol->source_rfc1001_name, 0x20, 15);
for(i=0;i<15;i++) { for (i = 0; i < 15; i++) {
/* BB are there cases in which a comma can be /* BB are there cases in which a comma can be
valid in this workstation netbios name (and need valid in this workstation netbios name (and need
special handling)? */ special handling)? */
/* We do not uppercase netbiosname for user */ /* We do not uppercase netbiosname for user */
if (value[i]==0) if (value[i] == 0)
break; break;
else else
vol->source_rfc1001_name[i] = value[i]; vol->source_rfc1001_name[i] =
value[i];
} }
/* The string has 16th byte zero still from /* The string has 16th byte zero still from
set at top of the function */ set at top of the function */
if((i==15) && (value[i] != 0)) if ((i == 15) && (value[i] != 0))
printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n"); printk(KERN_WARNING "CIFS: netbiosname"
" longer than 15 truncated.\n");
} }
} else if (strnicmp(data, "servern", 7) == 0) { } else if (strnicmp(data, "servern", 7) == 0) {
/* servernetbiosname specified override *SMBSERVER */ /* servernetbiosname specified override *SMBSERVER */
if (!value || !*value || (*value == ' ')) { if (!value || !*value || (*value == ' ')) {
cFYI(1,("empty server netbiosname specified")); cFYI(1, ("empty server netbiosname specified"));
} else { } else {
/* last byte, type, is 0x20 for servr type */ /* last byte, type, is 0x20 for servr type */
memset(vol->target_rfc1001_name,0x20,16); memset(vol->target_rfc1001_name, 0x20, 16);
for(i=0;i<15;i++) { for (i = 0; i < 15; i++) {
/* BB are there cases in which a comma can be /* BB are there cases in which a comma can be
valid in this workstation netbios name (and need valid in this workstation netbios name
special handling)? */ (and need special handling)? */
/* user or mount helper must uppercase netbiosname */ /* user or mount helper must uppercase
if (value[i]==0) the netbiosname */
if (value[i] == 0)
break; break;
else else
vol->target_rfc1001_name[i] = value[i]; vol->target_rfc1001_name[i] =
value[i];
} }
/* The string has 16th byte zero still from /* The string has 16th byte zero still from
set at top of the function */ set at top of the function */
if((i==15) && (value[i] != 0)) if ((i == 15) && (value[i] != 0))
printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n"); printk(KERN_WARNING "CIFS: server net"
"biosname longer than 15 truncated.\n");
} }
} else if (strnicmp(data, "credentials", 4) == 0) { } else if (strnicmp(data, "credentials", 4) == 0) {
/* ignore */ /* ignore */
} else if (strnicmp(data, "version", 3) == 0) { } else if (strnicmp(data, "version", 3) == 0) {
/* ignore */ /* ignore */
} else if (strnicmp(data, "guest",5) == 0) { } else if (strnicmp(data, "guest", 5) == 0) {
/* ignore */ /* ignore */
} else if (strnicmp(data, "rw", 2) == 0) { } else if (strnicmp(data, "rw", 2) == 0) {
vol->rw = TRUE; vol->rw = TRUE;
...@@ -1230,6 +1247,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -1230,6 +1247,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->posix_paths = 1; vol->posix_paths = 1;
} else if (strnicmp(data, "noposixpaths", 12) == 0) { } else if (strnicmp(data, "noposixpaths", 12) == 0) {
vol->posix_paths = 0; vol->posix_paths = 0;
} else if (strnicmp(data, "nounix", 6) == 0) {
vol->no_linux_ext = 1;
} else if (strnicmp(data, "nolinux", 7) == 0) {
vol->no_linux_ext = 1;
} else if ((strnicmp(data, "nocase", 6) == 0) || } else if ((strnicmp(data, "nocase", 6) == 0) ||
(strnicmp(data, "ignorecase", 10) == 0)) { (strnicmp(data, "ignorecase", 10) == 0)) {
vol->nocase = 1; vol->nocase = 1;
...@@ -1241,7 +1262,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -1241,7 +1262,8 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
/* turn off mandatory locking in mode /* turn off mandatory locking in mode
if remote locking is turned off since the if remote locking is turned off since the
local vfs will do advisory */ local vfs will do advisory */
if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP))) if (vol->file_mode ==
(S_IALLUGO & ~(S_ISUID | S_IXGRP)))
vol->file_mode = S_IALLUGO; vol->file_mode = S_IALLUGO;
} else if (strnicmp(data, "setuids", 7) == 0) { } else if (strnicmp(data, "setuids", 7) == 0) {
vol->setuids = 1; vol->setuids = 1;
...@@ -1255,55 +1277,61 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -1255,55 +1277,61 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->intr = 0; vol->intr = 0;
} else if (strnicmp(data, "intr", 4) == 0) { } else if (strnicmp(data, "intr", 4) == 0) {
vol->intr = 1; vol->intr = 1;
} else if (strnicmp(data, "serverino",7) == 0) { } else if (strnicmp(data, "serverino", 7) == 0) {
vol->server_ino = 1; vol->server_ino = 1;
} else if (strnicmp(data, "noserverino",9) == 0) { } else if (strnicmp(data, "noserverino", 9) == 0) {
vol->server_ino = 0; vol->server_ino = 0;
} else if (strnicmp(data, "cifsacl",7) == 0) { } else if (strnicmp(data, "cifsacl", 7) == 0) {
vol->cifs_acl = 1; vol->cifs_acl = 1;
} else if (strnicmp(data, "nocifsacl", 9) == 0) { } else if (strnicmp(data, "nocifsacl", 9) == 0) {
vol->cifs_acl = 0; vol->cifs_acl = 0;
} else if (strnicmp(data, "acl",3) == 0) { } else if (strnicmp(data, "acl", 3) == 0) {
vol->no_psx_acl = 0; vol->no_psx_acl = 0;
} else if (strnicmp(data, "noacl",5) == 0) { } else if (strnicmp(data, "noacl", 5) == 0) {
vol->no_psx_acl = 1; vol->no_psx_acl = 1;
} else if (strnicmp(data, "sign",4) == 0) { } else if (strnicmp(data, "sign", 4) == 0) {
vol->secFlg |= CIFSSEC_MUST_SIGN; vol->secFlg |= CIFSSEC_MUST_SIGN;
/* } else if (strnicmp(data, "seal",4) == 0) { /* } else if (strnicmp(data, "seal",4) == 0) {
vol->secFlg |= CIFSSEC_MUST_SEAL; */ vol->secFlg |= CIFSSEC_MUST_SEAL; */
} else if (strnicmp(data, "direct",6) == 0) { } else if (strnicmp(data, "direct", 6) == 0) {
vol->direct_io = 1; vol->direct_io = 1;
} else if (strnicmp(data, "forcedirectio",13) == 0) { } else if (strnicmp(data, "forcedirectio", 13) == 0) {
vol->direct_io = 1; vol->direct_io = 1;
} else if (strnicmp(data, "in6_addr",8) == 0) { } else if (strnicmp(data, "in6_addr", 8) == 0) {
if (!value || !*value) { if (!value || !*value) {
vol->in6_addr = NULL; vol->in6_addr = NULL;
} else if (strnlen(value, 49) == 48) { } else if (strnlen(value, 49) == 48) {
vol->in6_addr = value; vol->in6_addr = value;
} else { } else {
printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n"); printk(KERN_WARNING "CIFS: ip v6 address not "
"48 characters long\n");
return 1; return 1;
} }
} else if (strnicmp(data, "noac", 4) == 0) { } else if (strnicmp(data, "noac", 4) == 0) {
printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); printk(KERN_WARNING "CIFS: Mount option noac not "
"supported. Instead set "
"/proc/fs/cifs/LookupCacheEnabled to 0\n");
} else } else
printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
data);
} }
if (vol->UNC == NULL) { if (vol->UNC == NULL) {
if(devname == NULL) { if (devname == NULL) {
printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n"); printk(KERN_WARNING "CIFS: Missing UNC name for mount "
"target\n");
return 1; return 1;
} }
if ((temp_len = strnlen(devname, 300)) < 300) { if ((temp_len = strnlen(devname, 300)) < 300) {
vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
if(vol->UNC == NULL) if (vol->UNC == NULL)
return 1; return 1;
strcpy(vol->UNC,devname); strcpy(vol->UNC, devname);
if (strncmp(vol->UNC, "//", 2) == 0) { if (strncmp(vol->UNC, "//", 2) == 0) {
vol->UNC[0] = '\\'; vol->UNC[0] = '\\';
vol->UNC[1] = '\\'; vol->UNC[1] = '\\';
} else if (strncmp(vol->UNC, "\\\\", 2) != 0) { } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n"); printk(KERN_WARNING "CIFS: UNC Path does not "
"begin with // or \\\\ \n");
return 1; return 1;
} }
} else { } else {
...@@ -1311,14 +1339,14 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) ...@@ -1311,14 +1339,14 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
return 1; return 1;
} }
} }
if(vol->UNCip == NULL) if (vol->UNCip == NULL)
vol->UNCip = &vol->UNC[2]; vol->UNCip = &vol->UNC[2];
return 0; return 0;
} }
static struct cifsSesInfo * static struct cifsSesInfo *
cifs_find_tcp_session(struct in_addr * target_ip_addr, cifs_find_tcp_session(struct in_addr *target_ip_addr,
struct in6_addr *target_ip6_addr, struct in6_addr *target_ip6_addr,
char *userName, struct TCP_Server_Info **psrvTcp) char *userName, struct TCP_Server_Info **psrvTcp)
{ {
...@@ -1330,19 +1358,25 @@ cifs_find_tcp_session(struct in_addr * target_ip_addr, ...@@ -1330,19 +1358,25 @@ cifs_find_tcp_session(struct in_addr * target_ip_addr,
list_for_each(tmp, &GlobalSMBSessionList) { list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
if (ses->server) { if (ses->server) {
if((target_ip_addr && if ((target_ip_addr &&
(ses->server->addr.sockAddr.sin_addr.s_addr (ses->server->addr.sockAddr.sin_addr.s_addr
== target_ip_addr->s_addr)) || (target_ip6_addr == target_ip_addr->s_addr)) || (target_ip6_addr
&& memcmp(&ses->server->addr.sockAddr6.sin6_addr, && memcmp(&ses->server->addr.sockAddr6.sin6_addr,
target_ip6_addr,sizeof(*target_ip6_addr)))){ target_ip6_addr, sizeof(*target_ip6_addr)))) {
/* BB lock server and tcp session and increment use count here?? */ /* BB lock server and tcp session and increment
*psrvTcp = ses->server; /* found a match on the TCP session */ use count here?? */
/* found a match on the TCP session */
*psrvTcp = ses->server;
/* BB check if reconnection needed */ /* BB check if reconnection needed */
if (strncmp if (strncmp
(ses->userName, userName, (ses->userName, userName,
MAX_USERNAME_SIZE) == 0){ MAX_USERNAME_SIZE) == 0){
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
return ses; /* found exact match on both tcp and SMB sessions */ /* Found exact match on both TCP and
SMB sessions */
return ses;
} }
} }
} }
...@@ -1373,7 +1407,8 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) ...@@ -1373,7 +1407,8 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
/* BB lock tcon, server and tcp session and increment use count here? */ /* BB lock tcon, server and tcp session and increment use count here? */
/* found a match on the TCP session */ /* found a match on the TCP session */
/* BB check if reconnection needed */ /* BB check if reconnection needed */
cFYI(1,("IP match, old UNC: %s new: %s", cFYI(1,
("IP match, old UNC: %s new: %s",
tcon->treeName, uncName)); tcon->treeName, uncName));
if (strncmp if (strncmp
(tcon->treeName, uncName, (tcon->treeName, uncName,
...@@ -1408,7 +1443,7 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ...@@ -1408,7 +1443,7 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
unsigned int num_referrals; unsigned int num_referrals;
int rc = 0; int rc = 0;
rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
&num_referrals, &referrals, remap); &num_referrals, &referrals, remap);
/* BB Add in code to: if valid refrl, if not ip address contact /* BB Add in code to: if valid refrl, if not ip address contact
...@@ -1421,10 +1456,9 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ...@@ -1421,10 +1456,9 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
} }
int int
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
const char *old_path, const struct nls_table *nls_codepage, const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
unsigned int *pnum_referrals, unsigned char **preferrals, int remap)
unsigned char ** preferrals, int remap)
{ {
char *temp_unc; char *temp_unc;
int rc = 0; int rc = 0;
...@@ -1433,7 +1467,8 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ...@@ -1433,7 +1467,8 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
if (pSesInfo->ipc_tid == 0) { if (pSesInfo->ipc_tid == 0) {
temp_unc = kmalloc(2 /* for slashes */ + temp_unc = kmalloc(2 /* for slashes */ +
strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2) strnlen(pSesInfo->serverName,
SERVER_NAME_LEN_WITH_NULL * 2)
+ 1 + 4 /* slash IPC$ */ + 2, + 1 + 4 /* slash IPC$ */ + 2,
GFP_KERNEL); GFP_KERNEL);
if (temp_unc == NULL) if (temp_unc == NULL)
...@@ -1444,7 +1479,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ...@@ -1444,7 +1479,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$"); strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage); rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
cFYI(1, cFYI(1,
("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid)); ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
kfree(temp_unc); kfree(temp_unc);
} }
if (rc == 0) if (rc == 0)
...@@ -1455,15 +1490,15 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ...@@ -1455,15 +1490,15 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
} }
/* See RFC1001 section 14 on representation of Netbios names */ /* See RFC1001 section 14 on representation of Netbios names */
static void rfc1002mangle(char * target,char * source, unsigned int length) static void rfc1002mangle(char *target, char *source, unsigned int length)
{ {
unsigned int i,j; unsigned int i, j;
for(i=0,j=0;i<(length);i++) { for (i = 0, j = 0; i < (length); i++) {
/* mask a nibble at a time and encode */ /* mask a nibble at a time and encode */
target[j] = 'A' + (0x0F & (source[i] >> 4)); target[j] = 'A' + (0x0F & (source[i] >> 4));
target[j+1] = 'A' + (0x0F & source[i]); target[j+1] = 'A' + (0x0F & source[i]);
j+=2; j += 2;
} }
} }
...@@ -1471,21 +1506,22 @@ static void rfc1002mangle(char * target,char * source, unsigned int length) ...@@ -1471,21 +1506,22 @@ static void rfc1002mangle(char * target,char * source, unsigned int length)
static int static int
ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
char * netbios_name, char * target_name) char *netbios_name, char *target_name)
{ {
int rc = 0; int rc = 0;
int connected = 0; int connected = 0;
__be16 orig_port = 0; __be16 orig_port = 0;
if(*csocket == NULL) { if (*csocket == NULL) {
rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket); rc = sock_create_kern(PF_INET, SOCK_STREAM,
IPPROTO_TCP, csocket);
if (rc < 0) { if (rc < 0) {
cERROR(1, ("Error %d creating socket",rc)); cERROR(1, ("Error %d creating socket", rc));
*csocket = NULL; *csocket = NULL;
return rc; return rc;
} else { } else {
/* BB other socket options to set KEEPALIVE, NODELAY? */ /* BB other socket options to set KEEPALIVE, NODELAY? */
cFYI(1,("Socket created")); cFYI(1, ("Socket created"));
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
(*csocket)->sk->sk_allocation = GFP_NOFS; (*csocket)->sk->sk_allocation = GFP_NOFS;
#else #else
...@@ -1495,26 +1531,26 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, ...@@ -1495,26 +1531,26 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
} }
psin_server->sin_family = AF_INET; psin_server->sin_family = AF_INET;
if(psin_server->sin_port) { /* user overrode default port */ if (psin_server->sin_port) { /* user overrode default port */
rc = (*csocket)->ops->connect(*csocket, rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server, (struct sockaddr *) psin_server,
sizeof (struct sockaddr_in),0); sizeof (struct sockaddr_in), 0);
if (rc >= 0) if (rc >= 0)
connected = 1; connected = 1;
} }
if(!connected) { if (!connected) {
/* save original port so we can retry user specified port /* save original port so we can retry user specified port
later if fall back ports fail this time */ later if fall back ports fail this time */
orig_port = psin_server->sin_port; orig_port = psin_server->sin_port;
/* do not retry on the same port we just failed on */ /* do not retry on the same port we just failed on */
if(psin_server->sin_port != htons(CIFS_PORT)) { if (psin_server->sin_port != htons(CIFS_PORT)) {
psin_server->sin_port = htons(CIFS_PORT); psin_server->sin_port = htons(CIFS_PORT);
rc = (*csocket)->ops->connect(*csocket, rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server, (struct sockaddr *) psin_server,
sizeof (struct sockaddr_in),0); sizeof (struct sockaddr_in), 0);
if (rc >= 0) if (rc >= 0)
connected = 1; connected = 1;
} }
...@@ -1522,7 +1558,8 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, ...@@ -1522,7 +1558,8 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
if (!connected) { if (!connected) {
psin_server->sin_port = htons(RFC1001_PORT); psin_server->sin_port = htons(RFC1001_PORT);
rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
psin_server, sizeof (struct sockaddr_in),0); psin_server,
sizeof (struct sockaddr_in), 0);
if (rc >= 0) if (rc >= 0)
connected = 1; connected = 1;
} }
...@@ -1530,9 +1567,9 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, ...@@ -1530,9 +1567,9 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
/* give up here - unless we want to retry on different /* give up here - unless we want to retry on different
protocol families some day */ protocol families some day */
if (!connected) { if (!connected) {
if(orig_port) if (orig_port)
psin_server->sin_port = orig_port; psin_server->sin_port = orig_port;
cFYI(1,("Error %d connecting to server via ipv4",rc)); cFYI(1, ("Error %d connecting to server via ipv4", rc));
sock_release(*csocket); sock_release(*csocket);
*csocket = NULL; *csocket = NULL;
return rc; return rc;
...@@ -1541,13 +1578,14 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, ...@@ -1541,13 +1578,14 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
the default. sock_setsockopt not used because it expects the default. sock_setsockopt not used because it expects
user space buffer */ user space buffer */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf, cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
(*csocket)->sk->sk_sndbuf,
(*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
(*csocket)->sk->sk_rcvtimeo = 7 * HZ; (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
/* make the bufsizes depend on wsize/rsize and max requests */ /* make the bufsizes depend on wsize/rsize and max requests */
if((*csocket)->sk->sk_sndbuf < (200 * 1024)) if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
(*csocket)->sk->sk_sndbuf = 200 * 1024; (*csocket)->sk->sk_sndbuf = 200 * 1024;
if((*csocket)->sk->sk_rcvbuf < (140 * 1024)) if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
(*csocket)->sk->sk_rcvbuf = 140 * 1024; (*csocket)->sk->sk_rcvbuf = 140 * 1024;
#else #else
cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sndbuf, cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sndbuf,
...@@ -1559,33 +1597,35 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, ...@@ -1559,33 +1597,35 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
if((*csocket)->sk->rcvbuf < (140 * 1024)) if((*csocket)->sk->rcvbuf < (140 * 1024))
(*csocket)->sk->rcvbuf = 140 * 1024; (*csocket)->sk->rcvbuf = 140 * 1024;
#endif #endif
/* send RFC1001 sessinit */ /* send RFC1001 sessinit */
if(psin_server->sin_port == htons(RFC1001_PORT)) { if (psin_server->sin_port == htons(RFC1001_PORT)) {
/* some servers require RFC1001 sessinit before sending /* some servers require RFC1001 sessinit before sending
negprot - BB check reconnection in case where second negprot - BB check reconnection in case where second
sessinit is sent but no second negprot */ sessinit is sent but no second negprot */
struct rfc1002_session_packet * ses_init_buf; struct rfc1002_session_packet *ses_init_buf;
struct smb_hdr * smb_buf; struct smb_hdr *smb_buf;
ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
if(ses_init_buf) { GFP_KERNEL);
if (ses_init_buf) {
ses_init_buf->trailer.session_req.called_len = 32; ses_init_buf->trailer.session_req.called_len = 32;
if(target_name && (target_name[0] != 0)) { if (target_name && (target_name[0] != 0)) {
rfc1002mangle(ses_init_buf->trailer.session_req.called_name, rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
target_name, 16); target_name, 16);
} else { } else {
rfc1002mangle(ses_init_buf->trailer.session_req.called_name, rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
DEFAULT_CIFS_CALLED_NAME,16); DEFAULT_CIFS_CALLED_NAME, 16);
} }
ses_init_buf->trailer.session_req.calling_len = 32; ses_init_buf->trailer.session_req.calling_len = 32;
/* calling name ends in null (byte 16) from old smb /* calling name ends in null (byte 16) from old smb
convention. */ convention. */
if(netbios_name && (netbios_name[0] !=0)) { if (netbios_name && (netbios_name[0] != 0)) {
rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
netbios_name,16); netbios_name, 16);
} else { } else {
rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
"LINUX_CIFS_CLNT",16); "LINUX_CIFS_CLNT", 16);
} }
ses_init_buf->trailer.session_req.scope1 = 0; ses_init_buf->trailer.session_req.scope1 = 0;
ses_init_buf->trailer.session_req.scope2 = 0; ses_init_buf->trailer.session_req.scope2 = 0;
...@@ -1619,15 +1659,16 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) ...@@ -1619,15 +1659,16 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
int connected = 0; int connected = 0;
__be16 orig_port = 0; __be16 orig_port = 0;
if(*csocket == NULL) { if (*csocket == NULL) {
rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket); rc = sock_create_kern(PF_INET6, SOCK_STREAM,
IPPROTO_TCP, csocket);
if (rc < 0) { if (rc < 0) {
cERROR(1, ("Error %d creating ipv6 socket",rc)); cERROR(1, ("Error %d creating ipv6 socket", rc));
*csocket = NULL; *csocket = NULL;
return rc; return rc;
} else { } else {
/* BB other socket options to set KEEPALIVE, NODELAY? */ /* BB other socket options to set KEEPALIVE, NODELAY? */
cFYI(1,("ipv6 Socket created")); cFYI(1, ("ipv6 Socket created"));
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
(*csocket)->sk->sk_allocation = GFP_NOFS; (*csocket)->sk->sk_allocation = GFP_NOFS;
#else #else
...@@ -1638,26 +1679,26 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) ...@@ -1638,26 +1679,26 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
psin_server->sin6_family = AF_INET6; psin_server->sin6_family = AF_INET6;
if(psin_server->sin6_port) { /* user overrode default port */ if (psin_server->sin6_port) { /* user overrode default port */
rc = (*csocket)->ops->connect(*csocket, rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server, (struct sockaddr *) psin_server,
sizeof (struct sockaddr_in6),0); sizeof (struct sockaddr_in6), 0);
if (rc >= 0) if (rc >= 0)
connected = 1; connected = 1;
} }
if(!connected) { if (!connected) {
/* save original port so we can retry user specified port /* save original port so we can retry user specified port
later if fall back ports fail this time */ later if fall back ports fail this time */
orig_port = psin_server->sin6_port; orig_port = psin_server->sin6_port;
/* do not retry on the same port we just failed on */ /* do not retry on the same port we just failed on */
if(psin_server->sin6_port != htons(CIFS_PORT)) { if (psin_server->sin6_port != htons(CIFS_PORT)) {
psin_server->sin6_port = htons(CIFS_PORT); psin_server->sin6_port = htons(CIFS_PORT);
rc = (*csocket)->ops->connect(*csocket, rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server, (struct sockaddr *) psin_server,
sizeof (struct sockaddr_in6),0); sizeof (struct sockaddr_in6), 0);
if (rc >= 0) if (rc >= 0)
connected = 1; connected = 1;
} }
...@@ -1665,7 +1706,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) ...@@ -1665,7 +1706,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
if (!connected) { if (!connected) {
psin_server->sin6_port = htons(RFC1001_PORT); psin_server->sin6_port = htons(RFC1001_PORT);
rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
psin_server, sizeof (struct sockaddr_in6),0); psin_server, sizeof (struct sockaddr_in6), 0);
if (rc >= 0) if (rc >= 0)
connected = 1; connected = 1;
} }
...@@ -1673,9 +1714,9 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) ...@@ -1673,9 +1714,9 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
/* give up here - unless we want to retry on different /* give up here - unless we want to retry on different
protocol families some day */ protocol families some day */
if (!connected) { if (!connected) {
if(orig_port) if (orig_port)
psin_server->sin6_port = orig_port; psin_server->sin6_port = orig_port;
cFYI(1,("Error %d connecting to server via ipv6",rc)); cFYI(1, ("Error %d connecting to server via ipv6", rc));
sock_release(*csocket); sock_release(*csocket);
*csocket = NULL; *csocket = NULL;
return rc; return rc;
...@@ -1692,6 +1733,117 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) ...@@ -1692,6 +1733,117 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
return rc; return rc;
} }
void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
struct super_block *sb, struct smb_vol *vol_info)
{
/* if we are reconnecting then should we check to see if
* any requested capabilities changed locally e.g. via
* remount but we can not do much about it here
* if they have (even if we could detect it by the following)
* Perhaps we could add a backpointer to array of sb from tcon
* or if we change to make all sb to same share the same
* sb as NFS - then we only have one backpointer to sb.
* What if we wanted to mount the server share twice once with
* and once without posixacls or posix paths? */
__u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
if (vol_info && vol_info->no_linux_ext) {
tcon->fsUnixInfo.Capability = 0;
tcon->unix_ext = 0; /* Unix Extensions disabled */
cFYI(1, ("Linux protocol extensions disabled"));
return;
} else if (vol_info)
tcon->unix_ext = 1; /* Unix Extensions supported */
if (tcon->unix_ext == 0) {
cFYI(1, ("Unix extensions disabled so not set on reconnect"));
return;
}
if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
__u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
/* check for reconnect case in which we do not
want to change the mount behavior if we can avoid it */
if (vol_info == NULL) {
/* turn off POSIX ACL and PATHNAMES if not set
originally at mount time */
if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
}
cap &= CIFS_UNIX_CAP_MASK;
if (vol_info && vol_info->no_psx_acl)
cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
cFYI(1, ("negotiated posix acl support"));
if (sb)
sb->s_flags |= MS_POSIXACL;
#else
cFYI(1,("ACLs not supported"));
#endif
}
if (vol_info && vol_info->posix_paths == 0)
cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
cFYI(1, ("negotiate posix pathnames"));
if (sb)
CIFS_SB(sb)->mnt_cifs_flags |=
CIFS_MOUNT_POSIX_PATHS;
}
/* We might be setting the path sep back to a different
form if we are reconnecting and the server switched its
posix path capability for this share */
if (sb && (CIFS_SB(sb)->prepathlen > 0))
CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
CIFS_SB(sb)->rsize = 127 * 1024;
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("larger reads not supported by srv"));
#endif
}
}
cFYI(1, ("Negotiate caps 0x%x", (int)cap));
#ifdef CONFIG_CIFS_DEBUG2
if (cap & CIFS_UNIX_FCNTL_CAP)
cFYI(1, ("FCNTL cap"));
if (cap & CIFS_UNIX_EXTATTR_CAP)
cFYI(1, ("EXTATTR cap"));
if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
cFYI(1, ("POSIX path cap"));
if (cap & CIFS_UNIX_XATTR_CAP)
cFYI(1, ("XATTR cap"));
if (cap & CIFS_UNIX_POSIX_ACL_CAP)
cFYI(1, ("POSIX ACL cap"));
if (cap & CIFS_UNIX_LARGE_READ_CAP)
cFYI(1, ("very large read cap"));
if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
cFYI(1, ("very large write cap"));
#endif /* CIFS_DEBUG2 */
if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
if (vol_info == NULL)
cFYI(1, ("resetting capabilities failed"));
else
cERROR(1, ("Negotiating Unix capabilities "
"with the server failed. Consider "
"mounting with the Unix Extensions\n"
"disabled, if problems are found, "
"by specifying the nounix mount "
"option."));
}
}
}
int int
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
char *mount_data, const char *devname) char *mount_data, const char *devname)
...@@ -1712,7 +1864,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1712,7 +1864,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
memset(&volume_info,0,sizeof(struct smb_vol)); memset(&volume_info, 0, sizeof(struct smb_vol));
if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.password); kfree(volume_info.password);
...@@ -1721,12 +1873,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1721,12 +1873,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
return -EINVAL; return -EINVAL;
} }
if (volume_info.username) { if (volume_info.nullauth) {
cFYI(1, ("null user"));
volume_info.username = NULL;
} else if (volume_info.username) {
/* BB fixme parse for domain name here */ /* BB fixme parse for domain name here */
cFYI(1, ("Username: %s ", volume_info.username)); cFYI(1, ("Username: %s", volume_info.username));
} else if (volume_info.nullauth) {
cFYI(1,("null user"));
} else { } else {
cifserror("No username specified"); cifserror("No username specified");
/* In userspace mount helper we can get user name from alternate /* In userspace mount helper we can get user name from alternate
...@@ -1739,18 +1891,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1739,18 +1891,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
} }
if (volume_info.UNCip && volume_info.UNC) { if (volume_info.UNCip && volume_info.UNC) {
rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr); rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
&sin_server.sin_addr.s_addr);
if(rc <= 0) { if (rc <= 0) {
/* not ipv4 address, try ipv6 */ /* not ipv4 address, try ipv6 */
rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
if(rc > 0) &sin_server6.sin6_addr.in6_u);
if (rc > 0)
address_type = AF_INET6; address_type = AF_INET6;
} else { } else {
address_type = AF_INET; address_type = AF_INET;
} }
if(rc <= 0) { if (rc <= 0) {
/* we failed translating address */ /* we failed translating address */
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.password); kfree(volume_info.password);
...@@ -1762,9 +1916,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1762,9 +1916,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
/* success */ /* success */
rc = 0; rc = 0;
} else if (volume_info.UNCip){ } else if (volume_info.UNCip) {
/* BB using ip addr as server name connect to the DFS root below */ /* BB using ip addr as server name to connect to the
cERROR(1,("Connecting to DFS root not implemented yet")); DFS root below */
cERROR(1, ("Connecting to DFS root not implemented yet"));
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.password); kfree(volume_info.password);
kfree(volume_info.prepath); kfree(volume_info.prepath);
...@@ -1772,7 +1927,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1772,7 +1927,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
return -EINVAL; return -EINVAL;
} else /* which servers DFS root would we conect to */ { } else /* which servers DFS root would we conect to */ {
cERROR(1, cERROR(1,
("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified")); ("CIFS mount error: No UNC path (e.g. -o "
"unc=//192.168.1.100/public) specified"));
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.password); kfree(volume_info.password);
kfree(volume_info.prepath); kfree(volume_info.prepath);
...@@ -1781,13 +1937,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1781,13 +1937,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
} }
/* this is needed for ASCII cp to Unicode converts */ /* this is needed for ASCII cp to Unicode converts */
if(volume_info.iocharset == NULL) { if (volume_info.iocharset == NULL) {
cifs_sb->local_nls = load_nls_default(); cifs_sb->local_nls = load_nls_default();
/* load_nls_default can not return null */ /* load_nls_default can not return null */
} else { } else {
cifs_sb->local_nls = load_nls(volume_info.iocharset); cifs_sb->local_nls = load_nls(volume_info.iocharset);
if(cifs_sb->local_nls == NULL) { if (cifs_sb->local_nls == NULL) {
cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); cERROR(1, ("CIFS mount error: iocharset %s not found",
volume_info.iocharset));
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.password); kfree(volume_info.password);
kfree(volume_info.prepath); kfree(volume_info.prepath);
...@@ -1796,15 +1953,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1796,15 +1953,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
} }
} }
if(address_type == AF_INET) if (address_type == AF_INET)
existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr, existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
NULL /* no ipv6 addr */, NULL /* no ipv6 addr */,
volume_info.username, &srvTcp); volume_info.username, &srvTcp);
else if(address_type == AF_INET6) else if (address_type == AF_INET6) {
cFYI(1, ("looking for ipv6 address"));
existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */, existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
&sin_server6.sin6_addr, &sin_server6.sin6_addr,
volume_info.username, &srvTcp); volume_info.username, &srvTcp);
else { } else {
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.password); kfree(volume_info.password);
kfree(volume_info.prepath); kfree(volume_info.prepath);
...@@ -1812,21 +1970,26 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1812,21 +1970,26 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
return -EINVAL; return -EINVAL;
} }
if (srvTcp) { if (srvTcp) {
cFYI(1, ("Existing tcp session with server found")); cFYI(1, ("Existing tcp session with server found"));
} else { /* create socket */ } else { /* create socket */
if(volume_info.port) if (volume_info.port)
sin_server.sin_port = htons(volume_info.port); sin_server.sin_port = htons(volume_info.port);
else else
sin_server.sin_port = 0; sin_server.sin_port = 0;
rc = ipv4_connect(&sin_server,&csocket, if (address_type == AF_INET6) {
cFYI(1, ("attempting ipv6 connect"));
/* BB should we allow ipv6 on port 139? */
/* other OS never observed in Wild doing 139 with v6 */
rc = ipv6_connect(&sin_server6, &csocket);
} else
rc = ipv4_connect(&sin_server, &csocket,
volume_info.source_rfc1001_name, volume_info.source_rfc1001_name,
volume_info.target_rfc1001_name); volume_info.target_rfc1001_name);
if (rc < 0) { if (rc < 0) {
cERROR(1, cERROR(1, ("Error connecting to IPv4 socket. "
("Error connecting to IPv4 socket. Aborting operation")); "Aborting operation"));
if(csocket != NULL) if (csocket != NULL)
sock_release(csocket); sock_release(csocket);
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.password); kfree(volume_info.password);
...@@ -1846,8 +2009,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1846,8 +2009,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
return rc; return rc;
} else { } else {
memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in)); memcpy(&srvTcp->addr.sockAddr, &sin_server,
atomic_set(&srvTcp->inFlight,0); sizeof (struct sockaddr_in));
atomic_set(&srvTcp->inFlight, 0);
/* BB Add code for ipv6 case too */ /* BB Add code for ipv6 case too */
srvTcp->ssocket = csocket; srvTcp->ssocket = csocket;
srvTcp->protocolType = IPV4; srvTcp->protocolType = IPV4;
...@@ -1859,10 +2023,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1859,10 +2023,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
so no need to spinlock this init of tcpStatus */ so no need to spinlock this init of tcpStatus */
srvTcp->tcpStatus = CifsNew; srvTcp->tcpStatus = CifsNew;
init_MUTEX(&srvTcp->tcpSem); init_MUTEX(&srvTcp->tcpSem);
rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp, srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
CLONE_FS | CLONE_FILES | CLONE_VM); if ( IS_ERR(srvTcp->tsk) ) {
if(rc < 0) { rc = PTR_ERR(srvTcp->tsk);
rc = -ENOMEM; cERROR(1, ("error %d create cifsd thread", rc));
srvTcp->tsk = NULL;
sock_release(csocket); sock_release(csocket);
kfree(volume_info.UNC); kfree(volume_info.UNC);
kfree(volume_info.password); kfree(volume_info.password);
...@@ -1872,8 +2037,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1872,8 +2037,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
} }
wait_for_completion(&cifsd_complete); wait_for_completion(&cifsd_complete);
rc = 0; rc = 0;
memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); memcpy(srvTcp->workstation_RFC1001_name,
memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16); volume_info.source_rfc1001_name, 16);
memcpy(srvTcp->server_RFC1001_name,
volume_info.target_rfc1001_name, 16);
srvTcp->sequence_number = 0; srvTcp->sequence_number = 0;
} }
} }
...@@ -1894,18 +2061,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1894,18 +2061,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
NIPQUAD(sin_server.sin_addr.s_addr)); NIPQUAD(sin_server.sin_addr.s_addr));
} }
if (!rc){ if (!rc) {
/* volume_info.password freed at unmount */ /* volume_info.password freed at unmount */
if (volume_info.password) if (volume_info.password)
pSesInfo->password = volume_info.password; pSesInfo->password = volume_info.password;
if (volume_info.username) if (volume_info.username)
strncpy(pSesInfo->userName, strncpy(pSesInfo->userName,
volume_info.username,MAX_USERNAME_SIZE); volume_info.username,
MAX_USERNAME_SIZE);
if (volume_info.domainname) { if (volume_info.domainname) {
int len = strlen(volume_info.domainname); int len = strlen(volume_info.domainname);
pSesInfo->domainName = pSesInfo->domainName =
kmalloc(len + 1, GFP_KERNEL); kmalloc(len + 1, GFP_KERNEL);
if(pSesInfo->domainName) if (pSesInfo->domainName)
strcpy(pSesInfo->domainName, strcpy(pSesInfo->domainName,
volume_info.domainname); volume_info.domainname);
} }
...@@ -1913,9 +2081,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1913,9 +2081,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
pSesInfo->overrideSecFlg = volume_info.secFlg; pSesInfo->overrideSecFlg = volume_info.secFlg;
down(&pSesInfo->sesSem); down(&pSesInfo->sesSem);
/* BB FIXME need to pass vol->secFlgs BB */ /* BB FIXME need to pass vol->secFlgs BB */
rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); rc = cifs_setup_session(xid, pSesInfo,
cifs_sb->local_nls);
up(&pSesInfo->sesSem); up(&pSesInfo->sesSem);
if(!rc) if (!rc)
atomic_inc(&srvTcp->socketUseCount); atomic_inc(&srvTcp->socketUseCount);
} else } else
kfree(volume_info.password); kfree(volume_info.password);
...@@ -1923,20 +2092,21 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1923,20 +2092,21 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* search for existing tcon to this server share */ /* search for existing tcon to this server share */
if (!rc) { if (!rc) {
if(volume_info.rsize > CIFSMaxBufSize) { if (volume_info.rsize > CIFSMaxBufSize) {
cERROR(1,("rsize %d too large, using MaxBufSize", cERROR(1, ("rsize %d too large, using MaxBufSize",
volume_info.rsize)); volume_info.rsize));
cifs_sb->rsize = CIFSMaxBufSize; cifs_sb->rsize = CIFSMaxBufSize;
} else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) } else if ((volume_info.rsize) &&
(volume_info.rsize <= CIFSMaxBufSize))
cifs_sb->rsize = volume_info.rsize; cifs_sb->rsize = volume_info.rsize;
else /* default */ else /* default */
cifs_sb->rsize = CIFSMaxBufSize; cifs_sb->rsize = CIFSMaxBufSize;
if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
cERROR(1,("wsize %d too large using 4096 instead", cERROR(1, ("wsize %d too large, using 4096 instead",
volume_info.wsize)); volume_info.wsize));
cifs_sb->wsize = 4096; cifs_sb->wsize = 4096;
} else if(volume_info.wsize) } else if (volume_info.wsize)
cifs_sb->wsize = volume_info.wsize; cifs_sb->wsize = volume_info.wsize;
else else
cifs_sb->wsize = cifs_sb->wsize =
...@@ -1949,14 +2119,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1949,14 +2119,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
conjunction with 52K kvec constraint on arch with 4K conjunction with 52K kvec constraint on arch with 4K
page size */ page size */
if(cifs_sb->rsize < 2048) { if (cifs_sb->rsize < 2048) {
cifs_sb->rsize = 2048; cifs_sb->rsize = 2048;
/* Windows ME may prefer this */ /* Windows ME may prefer this */
cFYI(1,("readsize set to minimum 2048")); cFYI(1, ("readsize set to minimum: 2048"));
} }
/* calculate prepath */ /* calculate prepath */
cifs_sb->prepath = volume_info.prepath; cifs_sb->prepath = volume_info.prepath;
if(cifs_sb->prepath) { if (cifs_sb->prepath) {
cifs_sb->prepathlen = strlen(cifs_sb->prepath); cifs_sb->prepathlen = strlen(cifs_sb->prepath);
cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb); cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
volume_info.prepath = NULL; volume_info.prepath = NULL;
...@@ -1966,28 +2136,31 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1966,28 +2136,31 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cifs_sb->mnt_gid = volume_info.linux_gid; cifs_sb->mnt_gid = volume_info.linux_gid;
cifs_sb->mnt_file_mode = volume_info.file_mode; cifs_sb->mnt_file_mode = volume_info.file_mode;
cifs_sb->mnt_dir_mode = volume_info.dir_mode; cifs_sb->mnt_dir_mode = volume_info.dir_mode;
cFYI(1,("file mode: 0x%x dir mode: 0x%x", cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
if(volume_info.noperm) if (volume_info.noperm)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
if(volume_info.setuids) if (volume_info.setuids)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
if(volume_info.server_ino) if (volume_info.server_ino)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
if(volume_info.remap) if (volume_info.remap)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
if(volume_info.no_xattr) if (volume_info.no_xattr)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
if(volume_info.sfu_emul) if (volume_info.sfu_emul)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
if(volume_info.nobrl) if (volume_info.nobrl)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
if(volume_info.cifs_acl) if (volume_info.cifs_acl)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
if (volume_info.override_uid)
if(volume_info.direct_io) { cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
cFYI(1,("mounting share using direct i/o")); if (volume_info.override_gid)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
if (volume_info.direct_io) {
cFYI(1, ("mounting share using direct i/o"));
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
} }
...@@ -2007,9 +2180,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2007,9 +2180,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (tcon == NULL) if (tcon == NULL)
rc = -ENOMEM; rc = -ENOMEM;
else { else {
/* check for null share name ie connect to dfs root */ /* check for null share name ie connecting to
* dfs root */
/* BB check if this works for exactly length three strings */ /* BB check if this works for exactly length
* three strings */
if ((strchr(volume_info.UNC + 3, '\\') == NULL) if ((strchr(volume_info.UNC + 3, '\\') == NULL)
&& (strchr(volume_info.UNC + 3, '/') == && (strchr(volume_info.UNC + 3, '/') ==
NULL)) { NULL)) {
...@@ -2021,6 +2196,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2021,6 +2196,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
FreeXid(xid); FreeXid(xid);
return -ENODEV; return -ENODEV;
} else { } else {
/* BB Do we need to wrap sesSem around
* this TCon call and Unix SetFS as
* we do on SessSetup and reconnect? */
rc = CIFSTCon(xid, pSesInfo, rc = CIFSTCon(xid, pSesInfo,
volume_info.UNC, volume_info.UNC,
tcon, cifs_sb->local_nls); tcon, cifs_sb->local_nls);
...@@ -2034,13 +2212,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2034,13 +2212,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
} }
} }
} }
if(pSesInfo) { if (pSesInfo) {
if (pSesInfo->capabilities & CAP_LARGE_FILES) { if (pSesInfo->capabilities & CAP_LARGE_FILES) {
sb->s_maxbytes = (u64) 1 << 63; sb->s_maxbytes = (u64) 1 << 63;
} else } else
sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */ sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
} }
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10)
/* BB FIXME fix time_gran to be larger for LANMAN sessions */
sb->s_time_gran = 100; sb->s_time_gran = 100;
#endif #endif
...@@ -2048,13 +2228,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2048,13 +2228,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (rc) { if (rc) {
/* if session setup failed, use count is zero but /* if session setup failed, use count is zero but
we still need to free cifsd thread */ we still need to free cifsd thread */
if(atomic_read(&srvTcp->socketUseCount) == 0) { if (atomic_read(&srvTcp->socketUseCount) == 0) {
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
srvTcp->tcpStatus = CifsExiting; srvTcp->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
if(srvTcp->tsk) { if (srvTcp->tsk) {
send_sig(SIGKILL,srvTcp->tsk,1); struct task_struct *tsk;
wait_for_completion(&cifsd_complete); /* If we could verify that kthread_stop would
always wake up processes blocked in
tcp in recv_mesg then we could remove the
send_sig call */
force_sig(SIGKILL, srvTcp->tsk);
tsk = srvTcp->tsk;
if (tsk)
kthread_stop(tsk);
} }
} }
/* If find_unc succeeded then rc == 0 so we can not end */ /* If find_unc succeeded then rc == 0 so we can not end */
...@@ -2067,10 +2254,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2067,10 +2254,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
int temp_rc; int temp_rc;
temp_rc = CIFSSMBLogoff(xid, pSesInfo); temp_rc = CIFSSMBLogoff(xid, pSesInfo);
/* if the socketUseCount is now zero */ /* if the socketUseCount is now zero */
if((temp_rc == -ESHUTDOWN) && if ((temp_rc == -ESHUTDOWN) &&
(pSesInfo->server) &&
(pSesInfo->server->tsk)) { (pSesInfo->server->tsk)) {
send_sig(SIGKILL,pSesInfo->server->tsk,1); struct task_struct *tsk;
wait_for_completion(&cifsd_complete); force_sig(SIGKILL,
pSesInfo->server->tsk);
tsk = pSesInfo->server->tsk;
if (tsk)
kthread_stop(tsk);
} }
} else } else
cFYI(1, ("No session or bad tcon")); cFYI(1, ("No session or bad tcon"));
...@@ -2087,47 +2279,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -2087,47 +2279,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
CIFSSMBQFSDeviceInfo(xid, tcon); CIFSSMBQFSDeviceInfo(xid, tcon);
CIFSSMBQFSAttributeInfo(xid, tcon); CIFSSMBQFSAttributeInfo(xid, tcon);
if (tcon->ses->capabilities & CAP_UNIX) { /* tell server which Unix caps we support */
if(!CIFSSMBQFSUnixInfo(xid, tcon)) { if (tcon->ses->capabilities & CAP_UNIX)
__u64 cap = /* reset of caps checks mount to see if unix extensions
le64_to_cpu(tcon->fsUnixInfo.Capability); disabled for just this mount */
cap &= CIFS_UNIX_CAP_MASK; reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
if(volume_info.no_psx_acl) else
cap &= ~CIFS_UNIX_POSIX_ACL_CAP; tcon->unix_ext = 0; /* server does not support them */
else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
cFYI(1,("negotiated posix acl support"));
sb->s_flags |= MS_POSIXACL;
#else
cFYI(1,("ACLs not supported"));
#endif
}
if(volume_info.posix_paths == 0)
cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
cFYI(1,("negotiate posix pathnames"));
cifs_sb->mnt_cifs_flags |=
CIFS_MOUNT_POSIX_PATHS;
}
cFYI(1,("Negotiate caps 0x%x",(int)cap)); if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
cifs_sb->rsize = 1024 * 127;
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
if(cap & CIFS_UNIX_FCNTL_CAP) cFYI(1, ("no very large read support, rsize now 127K"));
cFYI(1,("FCNTL cap")); #endif
if(cap & CIFS_UNIX_EXTATTR_CAP)
cFYI(1,("EXTATTR cap"));
if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
cFYI(1,("POSIX path cap"));
if(cap & CIFS_UNIX_XATTR_CAP)
cFYI(1,("XATTR cap"));
if(cap & CIFS_UNIX_POSIX_ACL_CAP)
cFYI(1,("POSIX ACL cap"));
#endif /* CIFS_DEBUG2 */
if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
cFYI(1,("setting capabilities failed"));
}
}
} }
if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
cifs_sb->wsize = min(cifs_sb->wsize, cifs_sb->wsize = min(cifs_sb->wsize,
...@@ -2169,7 +2333,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2169,7 +2333,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 count; __u16 count;
cFYI(1, ("In sesssetup")); cFYI(1, ("In sesssetup"));
if(ses == NULL) if (ses == NULL)
return -EINVAL; return -EINVAL;
user = ses->userName; user = ses->userName;
domain = ses->domainName; domain = ses->domainName;
...@@ -2189,7 +2353,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2189,7 +2353,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) if (ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
...@@ -2224,7 +2389,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2224,7 +2389,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
*bcc_ptr = 0; *bcc_ptr = 0;
bcc_ptr++; bcc_ptr++;
} }
if(user == NULL) if (user == NULL)
bytes_returned = 0; /* skip null user */ bytes_returned = 0; /* skip null user */
else else
bytes_returned = bytes_returned =
...@@ -2249,9 +2414,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2249,9 +2414,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr += 2 * bytes_returned; bcc_ptr += 2 * bytes_returned;
bytes_returned = bytes_returned =
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
cifs_strtoUCS((__le16 *)bcc_ptr, utsname()->release, cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
32, nls_codepage); 32, nls_codepage);
#else #else
cifs_strtoUCS((__le16 *)bcc_ptr, system_utsname.release, cifs_strtoUCS((__le16 *)bcc_ptr, system_utsname.release,
32, nls_codepage); 32, nls_codepage);
...@@ -2264,7 +2428,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2264,7 +2428,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr += 2 * bytes_returned; bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2; bcc_ptr += 2;
} else { } else {
if(user != NULL) { if (user != NULL) {
strncpy(bcc_ptr, user, 200); strncpy(bcc_ptr, user, 200);
bcc_ptr += strnlen(user, 200); bcc_ptr += strnlen(user, 200);
} }
...@@ -2304,8 +2468,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2304,8 +2468,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 action = le16_to_cpu(pSMBr->resp.Action); __u16 action = le16_to_cpu(pSMBr->resp.Action);
__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
if (action & GUEST_LOGIN) if (action & GUEST_LOGIN)
cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */ cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
(little endian) */
cFYI(1, ("UID = %d ", ses->Suid)); cFYI(1, ("UID = %d ", ses->Suid));
/* response can have either 3 or 4 word count - Samba sends 3 */ /* response can have either 3 or 4 word count - Samba sends 3 */
bcc_ptr = pByteArea(smb_buffer_response); bcc_ptr = pByteArea(smb_buffer_response);
...@@ -2318,8 +2483,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2318,8 +2483,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
if ((long) (bcc_ptr) % 2) { if ((long) (bcc_ptr) % 2) {
remaining_words = remaining_words =
(BCC(smb_buffer_response) - 1) /2; (BCC(smb_buffer_response) - 1) / 2;
bcc_ptr++; /* Unicode strings must be word aligned */ /* Unicode strings must be word
aligned */
bcc_ptr++;
} else { } else {
remaining_words = remaining_words =
BCC(smb_buffer_response) / 2; BCC(smb_buffer_response) / 2;
...@@ -2330,13 +2497,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2330,13 +2497,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
/* We look for obvious messed up bcc or strings in response so we do not go off /* We look for obvious messed up bcc or strings in response so we do not go off
the end since (at least) WIN2K and Windows XP have a major bug in not null the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */ terminating last Unicode string in response */
if(ses->serverOS) if (ses->serverOS)
kfree(ses->serverOS); kfree(ses->serverOS);
ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); ses->serverOS = kzalloc(2 * (len + 1),
if(ses->serverOS == NULL) GFP_KERNEL);
if (ses->serverOS == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverOS, cifs_strfromUCS_le(ses->serverOS,
(__le16 *)bcc_ptr, len,nls_codepage); (__le16 *)bcc_ptr,
len, nls_codepage);
bcc_ptr += 2 * (len + 1); bcc_ptr += 2 * (len + 1);
remaining_words -= len + 1; remaining_words -= len + 1;
ses->serverOS[2 * len] = 0; ses->serverOS[2 * len] = 0;
...@@ -2345,42 +2514,49 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2345,42 +2514,49 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
len = UniStrnlen((wchar_t *)bcc_ptr, len = UniStrnlen((wchar_t *)bcc_ptr,
remaining_words-1); remaining_words-1);
kfree(ses->serverNOS); kfree(ses->serverNOS);
ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL); ses->serverNOS = kzalloc(2 * (len + 1),
if(ses->serverNOS == NULL) GFP_KERNEL);
if (ses->serverNOS == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverNOS, cifs_strfromUCS_le(ses->serverNOS,
(__le16 *)bcc_ptr,len,nls_codepage); (__le16 *)bcc_ptr,
len, nls_codepage);
bcc_ptr += 2 * (len + 1); bcc_ptr += 2 * (len + 1);
ses->serverNOS[2 * len] = 0; ses->serverNOS[2 * len] = 0;
ses->serverNOS[1 + (2 * len)] = 0; ses->serverNOS[1 + (2 * len)] = 0;
if(strncmp(ses->serverNOS, if (strncmp(ses->serverNOS,
"NT LAN Manager 4",16) == 0) { "NT LAN Manager 4", 16) == 0) {
cFYI(1,("NT4 server")); cFYI(1, ("NT4 server"));
ses->flags |= CIFS_SES_NT4; ses->flags |= CIFS_SES_NT4;
} }
remaining_words -= len + 1; remaining_words -= len + 1;
if (remaining_words > 0) { if (remaining_words > 0) {
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */ /* last string is not always null terminated
if(ses->serverDomain) (for e.g. for Windows XP & 2000) */
if (ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = ses->serverDomain =
kzalloc(2*(len+1),GFP_KERNEL); kzalloc(2*(len+1),
if(ses->serverDomain == NULL) GFP_KERNEL);
if (ses->serverDomain == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverDomain, cifs_strfromUCS_le(ses->serverDomain,
(__le16 *)bcc_ptr,len,nls_codepage); (__le16 *)bcc_ptr,
len, nls_codepage);
bcc_ptr += 2 * (len + 1); bcc_ptr += 2 * (len + 1);
ses->serverDomain[2*len] = 0; ses->serverDomain[2*len] = 0;
ses->serverDomain[1+(2*len)] = 0; ses->serverDomain[1+(2*len)] = 0;
} /* else no more room so create dummy domain string */ } else { /* else no more room so create
else { dummy domain string */
if(ses->serverDomain) if (ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = ses->serverDomain =
kzalloc(2, GFP_KERNEL); kzalloc(2, GFP_KERNEL);
} }
} else { /* no room so create dummy domain and NOS string */ } else { /* no room so create dummy domain
and NOS string */
/* if these kcallocs fail not much we /* if these kcallocs fail not much we
can do, but better to not fail the can do, but better to not fail the
sesssetup itself */ sesssetup itself */
...@@ -2397,19 +2573,22 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2397,19 +2573,22 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pByteArea(smb_buffer_response) pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) { <= BCC(smb_buffer_response)) {
kfree(ses->serverOS); kfree(ses->serverOS);
ses->serverOS = kzalloc(len + 1,GFP_KERNEL); ses->serverOS = kzalloc(len + 1,
if(ses->serverOS == NULL) GFP_KERNEL);
if (ses->serverOS == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
strncpy(ses->serverOS,bcc_ptr, len); strncpy(ses->serverOS, bcc_ptr, len);
bcc_ptr += len; bcc_ptr += len;
bcc_ptr[0] = 0; /* null terminate the string */ /* null terminate the string */
bcc_ptr[0] = 0;
bcc_ptr++; bcc_ptr++;
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
kfree(ses->serverNOS); kfree(ses->serverNOS);
ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); ses->serverNOS = kzalloc(len + 1,
if(ses->serverNOS == NULL) GFP_KERNEL);
if (ses->serverNOS == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
strncpy(ses->serverNOS, bcc_ptr, len); strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len; bcc_ptr += len;
...@@ -2417,23 +2596,27 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2417,23 +2596,27 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr++; bcc_ptr++;
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
if(ses->serverDomain) if (ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = kzalloc(len + 1,GFP_KERNEL); ses->serverDomain = kzalloc(len + 1,
if(ses->serverDomain == NULL) GFP_KERNEL);
if (ses->serverDomain == NULL)
goto sesssetup_nomem; goto sesssetup_nomem;
strncpy(ses->serverDomain, bcc_ptr, len); strncpy(ses->serverDomain, bcc_ptr,
len);
bcc_ptr += len; bcc_ptr += len;
bcc_ptr[0] = 0; bcc_ptr[0] = 0;
bcc_ptr++; bcc_ptr++;
} else } else
cFYI(1, cFYI(1,
("Variable field of length %d extends beyond end of smb ", ("Variable field of length %d "
"extends beyond end of smb ",
len)); len));
} }
} else { } else {
cERROR(1, cERROR(1,
(" Security Blob Length extends beyond end of SMB")); (" Security Blob Length extends beyond "
"end of SMB"));
} }
} else { } else {
cERROR(1, cERROR(1,
...@@ -2452,7 +2635,7 @@ sesssetup_nomem: /* do not return an error on nomem for the info strings, ...@@ -2452,7 +2635,7 @@ sesssetup_nomem: /* do not return an error on nomem for the info strings,
static int static int
CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
struct cifsSesInfo *ses, int * pNTLMv2_flag, struct cifsSesInfo *ses, int *pNTLMv2_flag,
const struct nls_table *nls_codepage) const struct nls_table *nls_codepage)
{ {
struct smb_hdr *smb_buffer; struct smb_hdr *smb_buffer;
...@@ -2472,7 +2655,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2472,7 +2655,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
__u16 count; __u16 count;
cFYI(1, ("In NTLMSSP sesssetup (negotiate)")); cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
if(ses == NULL) if (ses == NULL)
return -EINVAL; return -EINVAL;
domain = ses->domainName; domain = ses->domainName;
*pNTLMv2_flag = FALSE; *pNTLMv2_flag = FALSE;
...@@ -2496,7 +2679,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2496,7 +2679,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
...@@ -2524,9 +2707,9 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2524,9 +2707,9 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_NEGOTIATE_56 | NTLMSSP_NEGOTIATE_56 |
/* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
if(sign_CIFS_PDUs) if (sign_CIFS_PDUs)
negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
/* if(ntlmv2_support) /* if (ntlmv2_support)
negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/ negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
/* setup pointers to domain name and workstation name */ /* setup pointers to domain name and workstation name */
bcc_ptr += SecurityBlobLength; bcc_ptr += SecurityBlobLength;
...@@ -2552,9 +2735,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2552,9 +2735,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
bcc_ptr += 2 * bytes_returned; bcc_ptr += 2 * bytes_returned;
bytes_returned = bytes_returned =
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
cifs_strtoUCS((__le16 *)bcc_ptr, utsname()->release, 32, cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
nls_codepage); nls_codepage);
#else #else
cifs_strtoUCS((__le16 *)bcc_ptr, system_utsname.release, 32, cifs_strtoUCS((__le16 *)bcc_ptr, system_utsname.release, 32,
nls_codepage); nls_codepage);
...@@ -2637,11 +2819,11 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2637,11 +2819,11 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
memcpy(ses->server->cryptKey, memcpy(ses->server->cryptKey,
SecurityBlob2->Challenge, SecurityBlob2->Challenge,
CIFS_CRYPTO_KEY_SIZE); CIFS_CRYPTO_KEY_SIZE);
if(SecurityBlob2->NegotiateFlags & if (SecurityBlob2->NegotiateFlags &
cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2)) cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
*pNTLMv2_flag = TRUE; *pNTLMv2_flag = TRUE;
if((SecurityBlob2->NegotiateFlags & if ((SecurityBlob2->NegotiateFlags &
cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
|| (sign_CIFS_PDUs > 1)) || (sign_CIFS_PDUs > 1))
ses->server->secMode |= ses->server->secMode |=
...@@ -2656,7 +2838,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2656,7 +2838,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
remaining_words = remaining_words =
(BCC(smb_buffer_response) (BCC(smb_buffer_response)
- 1) / 2; - 1) / 2;
bcc_ptr++; /* Unicode strings must be word aligned */ /* Must word align unicode strings */
bcc_ptr++;
} else { } else {
remaining_words = remaining_words =
BCC BCC
...@@ -2668,7 +2851,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2668,7 +2851,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
/* We look for obvious messed up bcc or strings in response so we do not go off /* We look for obvious messed up bcc or strings in response so we do not go off
the end since (at least) WIN2K and Windows XP have a major bug in not null the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */ terminating last Unicode string in response */
if(ses->serverOS) if (ses->serverOS)
kfree(ses->serverOS); kfree(ses->serverOS);
ses->serverOS = ses->serverOS =
kzalloc(2 * (len + 1), GFP_KERNEL); kzalloc(2 * (len + 1), GFP_KERNEL);
...@@ -2702,7 +2885,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2702,7 +2885,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
remaining_words -= len + 1; remaining_words -= len + 1;
if (remaining_words > 0) { if (remaining_words > 0) {
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string is not always null terminated (for e.g. for Windows XP & 2000) */ /* last string not always null terminated
(for e.g. for Windows XP & 2000) */
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = ses->serverDomain =
kzalloc(2 * kzalloc(2 *
...@@ -2740,7 +2924,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2740,7 +2924,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
if (((long) bcc_ptr + len) - (long) if (((long) bcc_ptr + len) - (long)
pByteArea(smb_buffer_response) pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) { <= BCC(smb_buffer_response)) {
if(ses->serverOS) if (ses->serverOS)
kfree(ses->serverOS); kfree(ses->serverOS);
ses->serverOS = ses->serverOS =
kzalloc(len + 1, kzalloc(len + 1,
...@@ -2767,18 +2951,20 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ...@@ -2767,18 +2951,20 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
ses->serverDomain = ses->serverDomain =
kzalloc(len + 1, kzalloc(len + 1,
GFP_KERNEL); GFP_KERNEL);
strncpy(ses->serverDomain, bcc_ptr, len); strncpy(ses->serverDomain,
bcc_ptr, len);
bcc_ptr += len; bcc_ptr += len;
bcc_ptr[0] = 0; bcc_ptr[0] = 0;
bcc_ptr++; bcc_ptr++;
} else } else
cFYI(1, cFYI(1,
("Variable field of length %d extends beyond end of smb", ("field of length %d "
"extends beyond end of smb",
len)); len));
} }
} else { } else {
cERROR(1, cERROR(1, ("Security Blob Length extends beyond"
(" Security Blob Length extends beyond end of SMB")); " end of SMB"));
} }
} else { } else {
cERROR(1, ("No session structure passed in.")); cERROR(1, ("No session structure passed in."));
...@@ -2817,7 +3003,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2817,7 +3003,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 count; __u16 count;
cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
if(ses == NULL) if (ses == NULL)
return -EINVAL; return -EINVAL;
user = ses->userName; user = ses->userName;
domain = ses->domainName; domain = ses->domainName;
...@@ -2842,7 +3028,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2842,7 +3028,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pSMB->req.hdr.Uid = ses->Suid; pSMB->req.hdr.Uid = ses->Suid;
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
...@@ -2870,9 +3056,9 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2870,9 +3056,9 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
0x80000000 | NTLMSSP_NEGOTIATE_128; 0x80000000 | NTLMSSP_NEGOTIATE_128;
if(sign_CIFS_PDUs) if (sign_CIFS_PDUs)
negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
if(ntlmv2_flag) if (ntlmv2_flag)
negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
/* setup pointers to domain name and workstation name */ /* setup pointers to domain name and workstation name */
...@@ -2904,45 +3090,45 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2904,45 +3090,45 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.Length = 0;
SecurityBlob->DomainName.MaximumLength = 0; SecurityBlob->DomainName.MaximumLength = 0;
} else { } else {
__u16 len = __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
nls_codepage); nls_codepage);
len *= 2; ln *= 2;
SecurityBlob->DomainName.MaximumLength = SecurityBlob->DomainName.MaximumLength =
cpu_to_le16(len); cpu_to_le16(ln);
SecurityBlob->DomainName.Buffer = SecurityBlob->DomainName.Buffer =
cpu_to_le32(SecurityBlobLength); cpu_to_le32(SecurityBlobLength);
bcc_ptr += len; bcc_ptr += ln;
SecurityBlobLength += len; SecurityBlobLength += ln;
SecurityBlob->DomainName.Length = SecurityBlob->DomainName.Length = cpu_to_le16(ln);
cpu_to_le16(len);
} }
if (user == NULL) { if (user == NULL) {
SecurityBlob->UserName.Buffer = 0; SecurityBlob->UserName.Buffer = 0;
SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.Length = 0;
SecurityBlob->UserName.MaximumLength = 0; SecurityBlob->UserName.MaximumLength = 0;
} else { } else {
__u16 len = __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
cifs_strtoUCS((__le16 *) bcc_ptr, user, 64,
nls_codepage); nls_codepage);
len *= 2; ln *= 2;
SecurityBlob->UserName.MaximumLength = SecurityBlob->UserName.MaximumLength =
cpu_to_le16(len); cpu_to_le16(ln);
SecurityBlob->UserName.Buffer = SecurityBlob->UserName.Buffer =
cpu_to_le32(SecurityBlobLength); cpu_to_le32(SecurityBlobLength);
bcc_ptr += len; bcc_ptr += ln;
SecurityBlobLength += len; SecurityBlobLength += ln;
SecurityBlob->UserName.Length = SecurityBlob->UserName.Length = cpu_to_le16(ln);
cpu_to_le16(len);
} }
/* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage); /* SecurityBlob->WorkstationName.Length =
cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
SecurityBlob->WorkstationName.Length *= 2; SecurityBlob->WorkstationName.Length *= 2;
SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length); SecurityBlob->WorkstationName.MaximumLength =
SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength); cpu_to_le16(SecurityBlob->WorkstationName.Length);
SecurityBlob->WorkstationName.Buffer =
cpu_to_le32(SecurityBlobLength);
bcc_ptr += SecurityBlob->WorkstationName.Length; bcc_ptr += SecurityBlob->WorkstationName.Length;
SecurityBlobLength += SecurityBlob->WorkstationName.Length; SecurityBlobLength += SecurityBlob->WorkstationName.Length;
SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */ SecurityBlob->WorkstationName.Length =
cpu_to_le16(SecurityBlob->WorkstationName.Length); */
if ((long) bcc_ptr % 2) { if ((long) bcc_ptr % 2) {
*bcc_ptr = 0; *bcc_ptr = 0;
...@@ -2953,7 +3139,6 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2953,7 +3139,6 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
32, nls_codepage); 32, nls_codepage);
bcc_ptr += 2 * bytes_returned; bcc_ptr += 2 * bytes_returned;
bytes_returned = bytes_returned =
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
nls_codepage); nls_codepage);
...@@ -2979,33 +3164,32 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -2979,33 +3164,32 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.Length = 0;
SecurityBlob->DomainName.MaximumLength = 0; SecurityBlob->DomainName.MaximumLength = 0;
} else { } else {
__u16 len; __u16 ln;
negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
strncpy(bcc_ptr, domain, 63); strncpy(bcc_ptr, domain, 63);
len = strnlen(domain, 64); ln = strnlen(domain, 64);
SecurityBlob->DomainName.MaximumLength = SecurityBlob->DomainName.MaximumLength =
cpu_to_le16(len); cpu_to_le16(ln);
SecurityBlob->DomainName.Buffer = SecurityBlob->DomainName.Buffer =
cpu_to_le32(SecurityBlobLength); cpu_to_le32(SecurityBlobLength);
bcc_ptr += len; bcc_ptr += ln;
SecurityBlobLength += len; SecurityBlobLength += ln;
SecurityBlob->DomainName.Length = cpu_to_le16(len); SecurityBlob->DomainName.Length = cpu_to_le16(ln);
} }
if (user == NULL) { if (user == NULL) {
SecurityBlob->UserName.Buffer = 0; SecurityBlob->UserName.Buffer = 0;
SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.Length = 0;
SecurityBlob->UserName.MaximumLength = 0; SecurityBlob->UserName.MaximumLength = 0;
} else { } else {
__u16 len; __u16 ln;
strncpy(bcc_ptr, user, 63); strncpy(bcc_ptr, user, 63);
len = strnlen(user, 64); ln = strnlen(user, 64);
SecurityBlob->UserName.MaximumLength = SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln);
cpu_to_le16(len);
SecurityBlob->UserName.Buffer = SecurityBlob->UserName.Buffer =
cpu_to_le32(SecurityBlobLength); cpu_to_le32(SecurityBlobLength);
bcc_ptr += len; bcc_ptr += ln;
SecurityBlobLength += len; SecurityBlobLength += ln;
SecurityBlob->UserName.Length = cpu_to_le16(len); SecurityBlob->UserName.Length = cpu_to_le16(ln);
} }
/* BB fill in our workstation name if known BB */ /* BB fill in our workstation name if known BB */
...@@ -3039,15 +3223,18 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3039,15 +3223,18 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 blob_len = __u16 blob_len =
le16_to_cpu(pSMBr->resp.SecurityBlobLength); le16_to_cpu(pSMBr->resp.SecurityBlobLength);
if (action & GUEST_LOGIN) if (action & GUEST_LOGIN)
cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ cFYI(1, (" Guest login")); /* BB Should we set anything
/* if(SecurityBlob2->MessageType != NtLm??){ in SesInfo struct ? */
cFYI("Unexpected message type on auth response is %d ")); /* if (SecurityBlob2->MessageType != NtLm??) {
cFYI("Unexpected message type on auth response is %d"));
} */ } */
if (ses) { if (ses) {
cFYI(1, cFYI(1,
("Does UID on challenge %d match auth response UID %d ", ("Check challenge UID %d vs auth response UID %d",
ses->Suid, smb_buffer_response->Uid)); ses->Suid, smb_buffer_response->Uid));
ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */ /* UID left in wire format */
ses->Suid = smb_buffer_response->Uid;
bcc_ptr = pByteArea(smb_buffer_response); bcc_ptr = pByteArea(smb_buffer_response);
/* response can have either 3 or 4 word count - Samba sends 3 */ /* response can have either 3 or 4 word count - Samba sends 3 */
if ((pSMBr->resp.hdr.WordCount == 3) if ((pSMBr->resp.hdr.WordCount == 3)
...@@ -3074,12 +3261,12 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3074,12 +3261,12 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
} else { } else {
remaining_words = BCC(smb_buffer_response) / 2; remaining_words = BCC(smb_buffer_response) / 2;
} }
len = len = UniStrnlen((wchar_t *) bcc_ptr,
UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1); remaining_words - 1);
/* We look for obvious messed up bcc or strings in response so we do not go off /* We look for obvious messed up bcc or strings in response so we do not go off
the end since (at least) WIN2K and Windows XP have a major bug in not null the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */ terminating last Unicode string in response */
if(ses->serverOS) if (ses->serverOS)
kfree(ses->serverOS); kfree(ses->serverOS);
ses->serverOS = ses->serverOS =
kzalloc(2 * (len + 1), GFP_KERNEL); kzalloc(2 * (len + 1), GFP_KERNEL);
...@@ -3113,7 +3300,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3113,7 +3300,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if (remaining_words > 0) { if (remaining_words > 0) {
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string not always null terminated (e.g. for Windows XP & 2000) */ /* last string not always null terminated (e.g. for Windows XP & 2000) */
if(ses->serverDomain) if (ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = ses->serverDomain =
kzalloc(2 * kzalloc(2 *
...@@ -3141,12 +3328,12 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3141,12 +3328,12 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
= 0; = 0;
} /* else no more room so create dummy domain string */ } /* else no more room so create dummy domain string */
else { else {
if(ses->serverDomain) if (ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = kzalloc(2,GFP_KERNEL); ses->serverDomain = kzalloc(2,GFP_KERNEL);
} }
} else { /* no room so create dummy domain and NOS string */ } else { /* no room so create dummy domain and NOS string */
if(ses->serverDomain) if (ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = kzalloc(2, GFP_KERNEL); ses->serverDomain = kzalloc(2, GFP_KERNEL);
kfree(ses->serverNOS); kfree(ses->serverNOS);
...@@ -3157,9 +3344,9 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3157,9 +3344,9 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if (((long) bcc_ptr + len) - if (((long) bcc_ptr + len) -
(long) pByteArea(smb_buffer_response) (long) pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) { <= BCC(smb_buffer_response)) {
if(ses->serverOS) if (ses->serverOS)
kfree(ses->serverOS); kfree(ses->serverOS);
ses->serverOS = kzalloc(len + 1,GFP_KERNEL); ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
strncpy(ses->serverOS,bcc_ptr, len); strncpy(ses->serverOS,bcc_ptr, len);
bcc_ptr += len; bcc_ptr += len;
...@@ -3168,28 +3355,35 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3168,28 +3355,35 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
kfree(ses->serverNOS); kfree(ses->serverNOS);
ses->serverNOS = kzalloc(len+1,GFP_KERNEL); ses->serverNOS = kzalloc(len+1,
strncpy(ses->serverNOS, bcc_ptr, len); GFP_KERNEL);
strncpy(ses->serverNOS,
bcc_ptr, len);
bcc_ptr += len; bcc_ptr += len;
bcc_ptr[0] = 0; bcc_ptr[0] = 0;
bcc_ptr++; bcc_ptr++;
len = strnlen(bcc_ptr, 1024); len = strnlen(bcc_ptr, 1024);
if(ses->serverDomain) if (ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = kzalloc(len+1,GFP_KERNEL); ses->serverDomain =
strncpy(ses->serverDomain, bcc_ptr, len); kzalloc(len+1,
GFP_KERNEL);
strncpy(ses->serverDomain,
bcc_ptr, len);
bcc_ptr += len; bcc_ptr += len;
bcc_ptr[0] = 0; bcc_ptr[0] = 0;
bcc_ptr++; bcc_ptr++;
} else } else
cFYI(1, cFYI(1,
("Variable field of length %d extends beyond end of smb ", ("field of length %d "
"extends beyond end of smb ",
len)); len));
} }
} else { } else {
cERROR(1, cERROR(1,
(" Security Blob Length extends beyond end of SMB")); (" Security Blob extends beyond end "
"of SMB"));
} }
} else { } else {
cERROR(1, ("No session structure passed in.")); cERROR(1, ("No session structure passed in."));
...@@ -3241,7 +3435,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3241,7 +3435,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
pSMB->AndXCommand = 0xFF; pSMB->AndXCommand = 0xFF;
pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
bcc_ptr = &pSMB->Password[0]; bcc_ptr = &pSMB->Password[0];
if((ses->server->secMode) & SECMODE_USER) { if ((ses->server->secMode) & SECMODE_USER) {
pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
*bcc_ptr = 0; /* password is null byte */ *bcc_ptr = 0; /* password is null byte */
bcc_ptr++; /* skip password */ bcc_ptr++; /* skip password */
...@@ -3255,7 +3449,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3255,7 +3449,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
by Samba (not sure whether other servers allow by Samba (not sure whether other servers allow
NTLMv2 password here) */ NTLMv2 password here) */
#ifdef CONFIG_CIFS_WEAK_PW_HASH #ifdef CONFIG_CIFS_WEAK_PW_HASH
if((extended_security & CIFSSEC_MAY_LANMAN) && if ((extended_security & CIFSSEC_MAY_LANMAN) &&
(ses->server->secType == LANMAN)) (ses->server->secType == LANMAN))
calc_lanman_hash(ses, bcc_ptr); calc_lanman_hash(ses, bcc_ptr);
else else
...@@ -3265,14 +3459,14 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3265,14 +3459,14 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr); bcc_ptr);
bcc_ptr += CIFS_SESS_KEY_SIZE; bcc_ptr += CIFS_SESS_KEY_SIZE;
if(ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
/* must align unicode strings */ /* must align unicode strings */
*bcc_ptr = 0; /* null byte password */ *bcc_ptr = 0; /* null byte password */
bcc_ptr++; bcc_ptr++;
} }
} }
if(ses->server->secMode & if (ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
...@@ -3321,7 +3515,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3321,7 +3515,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
kfree(tcon->nativeFileSystem); kfree(tcon->nativeFileSystem);
tcon->nativeFileSystem = tcon->nativeFileSystem =
kzalloc(length + 2, GFP_KERNEL); kzalloc(length + 2, GFP_KERNEL);
cifs_strfromUCS_le(tcon->nativeFileSystem, if (tcon->nativeFileSystem)
cifs_strfromUCS_le(
tcon->nativeFileSystem,
(__le16 *) bcc_ptr, (__le16 *) bcc_ptr,
length, nls_codepage); length, nls_codepage);
bcc_ptr += 2 * length; bcc_ptr += 2 * length;
...@@ -3329,7 +3525,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3329,7 +3525,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr[1] = 0; bcc_ptr[1] = 0;
bcc_ptr += 2; bcc_ptr += 2;
} }
/* else do not bother copying these informational fields */ /* else do not bother copying these information fields*/
} else { } else {
length = strnlen(bcc_ptr, 1024); length = strnlen(bcc_ptr, 1024);
if ((bcc_ptr + length) - if ((bcc_ptr + length) -
...@@ -3338,12 +3534,13 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ...@@ -3338,12 +3534,13 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
kfree(tcon->nativeFileSystem); kfree(tcon->nativeFileSystem);
tcon->nativeFileSystem = tcon->nativeFileSystem =
kzalloc(length + 1, GFP_KERNEL); kzalloc(length + 1, GFP_KERNEL);
if (tcon->nativeFileSystem)
strncpy(tcon->nativeFileSystem, bcc_ptr, strncpy(tcon->nativeFileSystem, bcc_ptr,
length); length);
} }
/* else do not bother copying these informational fields */ /* else do not bother copying these information fields*/
} }
if((smb_buffer_response->WordCount == 3) || if ((smb_buffer_response->WordCount == 3) ||
(smb_buffer_response->WordCount == 7)) (smb_buffer_response->WordCount == 7))
/* field is in same location */ /* field is in same location */
tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
...@@ -3367,7 +3564,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) ...@@ -3367,7 +3564,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
int xid; int xid;
struct cifsSesInfo *ses = NULL; struct cifsSesInfo *ses = NULL;
struct task_struct *cifsd_task; struct task_struct *cifsd_task;
char * tmp; char *tmp;
xid = GetXid(); xid = GetXid();
...@@ -3388,10 +3585,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) ...@@ -3388,10 +3585,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
FreeXid(xid); FreeXid(xid);
return 0; return 0;
} else if (rc == -ESHUTDOWN) { } else if (rc == -ESHUTDOWN) {
cFYI(1,("Waking up socket by sending it signal")); cFYI(1, ("Waking up socket by sending signal"));
if(cifsd_task) { if (cifsd_task) {
send_sig(SIGKILL,cifsd_task,1); force_sig(SIGKILL, cifsd_task);
wait_for_completion(&cifsd_complete); kthread_stop(cifsd_task);
} }
rc = 0; rc = 0;
} /* else - we have an smb session } /* else - we have an smb session
...@@ -3420,7 +3617,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) ...@@ -3420,7 +3617,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
} }
int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
struct nls_table * nls_info) struct nls_table *nls_info)
{ {
int rc = 0; int rc = 0;
char ntlm_session_key[CIFS_SESS_KEY_SIZE]; char ntlm_session_key[CIFS_SESS_KEY_SIZE];
...@@ -3428,16 +3625,16 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ...@@ -3428,16 +3625,16 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
int first_time = 0; int first_time = 0;
/* what if server changes its buffer size after dropping the session? */ /* what if server changes its buffer size after dropping the session? */
if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
rc = CIFSSMBNegotiate(xid, pSesInfo); rc = CIFSSMBNegotiate(xid, pSesInfo);
if(rc == -EAGAIN) /* retry only once on 1st time connection */ { if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
rc = CIFSSMBNegotiate(xid, pSesInfo); rc = CIFSSMBNegotiate(xid, pSesInfo);
if(rc == -EAGAIN) if (rc == -EAGAIN)
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
} }
if(rc == 0) { if (rc == 0) {
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if(pSesInfo->server->tcpStatus != CifsExiting) if (pSesInfo->server->tcpStatus != CifsExiting)
pSesInfo->server->tcpStatus = CifsGood; pSesInfo->server->tcpStatus = CifsGood;
else else
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
...@@ -3449,14 +3646,15 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ...@@ -3449,14 +3646,15 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
if (!rc) { if (!rc) {
pSesInfo->flags = 0; pSesInfo->flags = 0;
pSesInfo->capabilities = pSesInfo->server->capabilities; pSesInfo->capabilities = pSesInfo->server->capabilities;
if(linuxExtEnabled == 0) if (linuxExtEnabled == 0)
pSesInfo->capabilities &= (~CAP_UNIX); pSesInfo->capabilities &= (~CAP_UNIX);
/* pSesInfo->sequence_number = 0;*/ /* pSesInfo->sequence_number = 0;*/
cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", cFYI(1,
("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
pSesInfo->server->secMode, pSesInfo->server->secMode,
pSesInfo->server->capabilities, pSesInfo->server->capabilities,
pSesInfo->server->timeAdj)); pSesInfo->server->timeAdj));
if(experimEnabled < 2) if (experimEnabled < 2)
rc = CIFS_SessSetup(xid, pSesInfo, rc = CIFS_SessSetup(xid, pSesInfo,
first_time, nls_info); first_time, nls_info);
else if (extended_security else if (extended_security
...@@ -3473,21 +3671,22 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ...@@ -3473,21 +3671,22 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
&ntlmv2_flag, &ntlmv2_flag,
nls_info); nls_info);
if (!rc) { if (!rc) {
if(ntlmv2_flag) { if (ntlmv2_flag) {
char * v2_response; char *v2_response;
cFYI(1,("more secure NTLM ver2 hash")); cFYI(1, ("more secure NTLM ver2 hash"));
if(CalcNTLMv2_partial_mac_key(pSesInfo, if (CalcNTLMv2_partial_mac_key(pSesInfo,
nls_info)) { nls_info)) {
rc = -ENOMEM; rc = -ENOMEM;
goto ss_err_exit; goto ss_err_exit;
} else } else
v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
if(v2_response) { if (v2_response) {
CalcNTLMv2_response(pSesInfo,v2_response); CalcNTLMv2_response(pSesInfo,
/* if(first_time) v2_response);
/* if (first_time)
cifs_calculate_ntlmv2_mac_key( cifs_calculate_ntlmv2_mac_key(
pSesInfo->server->mac_signing_key, pSesInfo->server->mac_signing_key,
response, ntlm_session_key, */ response, ntlm_session_key,*/
kfree(v2_response); kfree(v2_response);
/* BB Put dummy sig in SessSetup PDU? */ /* BB Put dummy sig in SessSetup PDU? */
} else { } else {
...@@ -3500,9 +3699,9 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ...@@ -3500,9 +3699,9 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
pSesInfo->server->cryptKey, pSesInfo->server->cryptKey,
ntlm_session_key); ntlm_session_key);
if(first_time) if (first_time)
cifs_calculate_mac_key( cifs_calculate_mac_key(
pSesInfo->server->mac_signing_key, &pSesInfo->server->mac_signing_key,
ntlm_session_key, ntlm_session_key,
pSesInfo->password); pSesInfo->password);
} }
...@@ -3520,18 +3719,18 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ...@@ -3520,18 +3719,18 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
pSesInfo->server->cryptKey, pSesInfo->server->cryptKey,
ntlm_session_key); ntlm_session_key);
if(first_time) if (first_time)
cifs_calculate_mac_key( cifs_calculate_mac_key(
pSesInfo->server->mac_signing_key, &pSesInfo->server->mac_signing_key,
ntlm_session_key, pSesInfo->password); ntlm_session_key, pSesInfo->password);
rc = CIFSSessSetup(xid, pSesInfo, rc = CIFSSessSetup(xid, pSesInfo,
ntlm_session_key, nls_info); ntlm_session_key, nls_info);
} }
if (rc) { if (rc) {
cERROR(1,("Send error in SessSetup = %d",rc)); cERROR(1, ("Send error in SessSetup = %d", rc));
} else { } else {
cFYI(1,("CIFS Session Established successfully")); cFYI(1, ("CIFS Session Established successfully"));
pSesInfo->status = CifsGood; pSesInfo->status = CifsGood;
} }
} }
......
...@@ -40,7 +40,8 @@ ...@@ -40,7 +40,8 @@
static void static void
renew_parental_timestamps(struct dentry *direntry) renew_parental_timestamps(struct dentry *direntry)
{ {
/* BB check if there is a way to get the kernel to do this or if we really need this */ /* BB check if there is a way to get the kernel to do this or if we
really need this */
do { do {
direntry->d_time = jiffies; direntry->d_time = jiffies;
direntry = direntry->d_parent; direntry = direntry->d_parent;
...@@ -57,7 +58,7 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -57,7 +58,7 @@ build_path_from_dentry(struct dentry *direntry)
char *full_path; char *full_path;
char dirsep; char dirsep;
if(direntry == NULL) if (direntry == NULL)
return NULL; /* not much we can do if dentry is freed and return NULL; /* not much we can do if dentry is freed and
we need to reopen the file after it was closed implicitly we need to reopen the file after it was closed implicitly
when the server crashed */ when the server crashed */
...@@ -69,14 +70,14 @@ cifs_bp_rename_retry: ...@@ -69,14 +70,14 @@ cifs_bp_rename_retry:
for (temp = direntry; !IS_ROOT(temp);) { for (temp = direntry; !IS_ROOT(temp);) {
namelen += (1 + temp->d_name.len); namelen += (1 + temp->d_name.len);
temp = temp->d_parent; temp = temp->d_parent;
if(temp == NULL) { if (temp == NULL) {
cERROR(1,("corrupt dentry")); cERROR(1, ("corrupt dentry"));
return NULL; return NULL;
} }
} }
full_path = kmalloc(namelen+1, GFP_KERNEL); full_path = kmalloc(namelen+1, GFP_KERNEL);
if(full_path == NULL) if (full_path == NULL)
return full_path; return full_path;
full_path[namelen] = 0; /* trailing null */ full_path[namelen] = 0; /* trailing null */
for (temp = direntry; !IS_ROOT(temp);) { for (temp = direntry; !IS_ROOT(temp);) {
...@@ -90,8 +91,8 @@ cifs_bp_rename_retry: ...@@ -90,8 +91,8 @@ cifs_bp_rename_retry:
cFYI(0, ("name: %s", full_path + namelen)); cFYI(0, ("name: %s", full_path + namelen));
} }
temp = temp->d_parent; temp = temp->d_parent;
if(temp == NULL) { if (temp == NULL) {
cERROR(1,("corrupt dentry")); cERROR(1, ("corrupt dentry"));
kfree(full_path); kfree(full_path);
return NULL; return NULL;
} }
...@@ -112,7 +113,7 @@ cifs_bp_rename_retry: ...@@ -112,7 +113,7 @@ cifs_bp_rename_retry:
since the '\' is a valid posix character so we can not switch since the '\' is a valid posix character so we can not switch
those safely to '/' if any are found in the middle of the prepath */ those safely to '/' if any are found in the middle of the prepath */
/* BB test paths to Windows with '/' in the midst of prepath */ /* BB test paths to Windows with '/' in the midst of prepath */
strncpy(full_path,CIFS_SB(direntry->d_sb)->prepath,pplen); strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen);
return full_path; return full_path;
} }
...@@ -144,11 +145,11 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) ...@@ -144,11 +145,11 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode)
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
char *full_path = NULL; char *full_path = NULL;
FILE_ALL_INFO * buf = NULL; FILE_ALL_INFO *buf = NULL;
struct inode *newinode = NULL; struct inode *newinode = NULL;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
struct cifsFileInfo * pCifsFile = NULL; struct cifsFileInfo *pCifsFile = NULL;
struct cifsInodeInfo * pCifsInode; struct cifsInodeInfo *pCifsInode;
int write_only = FALSE; int write_only = FALSE;
#endif #endif
int disposition = FILE_OVERWRITE_IF; int disposition = FILE_OVERWRITE_IF;
...@@ -159,7 +160,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) ...@@ -159,7 +160,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode)
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if(full_path == NULL) { if (full_path == NULL) {
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
...@@ -181,26 +182,27 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) ...@@ -181,26 +182,27 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode)
write_only = TRUE; write_only = TRUE;
} }
if((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
disposition = FILE_CREATE; disposition = FILE_CREATE;
else if((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
disposition = FILE_OVERWRITE_IF; disposition = FILE_OVERWRITE_IF;
else if((oflags & O_CREAT) == O_CREAT) else if ((oflags & O_CREAT) == O_CREAT)
disposition = FILE_OPEN_IF; disposition = FILE_OPEN_IF;
else { else {
cFYI(1,("Create flag not set in create function")); cFYI(1, ("Create flag not set in create function"));
} }
} }
/* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */ /* BB add processing to set equivalent of mode - e.g. via CreateX with
ACLs */
if (oplockEnabled) if (oplockEnabled)
oplock = REQ_OPLOCK; oplock = REQ_OPLOCK;
#else #else
desiredAccess = GENERIC_WRITE; desiredAccess = GENERIC_WRITE;
#endif #endif
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if(buf == NULL) { if (buf == NULL) {
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
...@@ -213,7 +215,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) ...@@ -213,7 +215,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode)
else else
rc = -EIO; /* no NT SMB support fall into legacy open below */ rc = -EIO; /* no NT SMB support fall into legacy open below */
if(rc == -EIO) { if (rc == -EIO) {
/* old server, retry the open legacy style */ /* old server, retry the open legacy style */
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, desiredAccess, CREATE_NOT_DIR,
...@@ -225,9 +227,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) ...@@ -225,9 +227,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode)
} else { } else {
/* If Open reported that we actually created a file /* If Open reported that we actually created a file
then we now have to set the mode if possible */ then we now have to set the mode if possible */
if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
(oplock & CIFS_CREATE_ACTION)) mode &= ~current->fs->umask;
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
(__u64)current->fsuid, (__u64)current->fsuid,
(__u64)current->fsgid, (__u64)current->fsgid,
...@@ -244,22 +246,24 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) ...@@ -244,22 +246,24 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode)
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
else { } else {
/* BB implement mode setting via Windows security descriptors */ /* BB implement mode setting via Windows security
/* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ descriptors e.g. */
/* could set r/o dos attribute if mode & 0222 == 0 */ /* CIFSSMBWinSetPerms(xid,pTcon,path,mode,-1,-1,nls);*/
/* Could set r/o dos attribute if mode & 0222 == 0 */
} }
/* BB server might mask mode so we have to query for Unix case*/ /* server might mask mode so we have to query for it */
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path, rc = cifs_get_inode_info_unix(&newinode, full_path,
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);
if(newinode) { if (newinode) {
newinode->i_mode = mode; newinode->i_mode = mode;
if((oplock & CIFS_CREATE_ACTION) && if ((oplock & CIFS_CREATE_ACTION) &&
(cifs_sb->mnt_cifs_flags & (cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_SET_UID)) { CIFS_MOUNT_SET_UID)) {
newinode->i_uid = current->fsuid; newinode->i_uid = current->fsuid;
...@@ -280,14 +284,15 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) ...@@ -280,14 +284,15 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode)
d_instantiate(direntry, newinode); d_instantiate(direntry, newinode);
} }
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
if((nd->flags & LOOKUP_OPEN) == FALSE) { if ((nd == NULL /* nfsd case - nfs srv does not set nd */) ||
((nd->flags & LOOKUP_OPEN) == FALSE)) {
/* mknod case - do not leave file open */ /* mknod case - do not leave file open */
CIFSSMBClose(xid, pTcon, fileHandle); CIFSSMBClose(xid, pTcon, fileHandle);
} else if(newinode) { } else if (newinode) {
pCifsFile = pCifsFile =
kzalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); kzalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
if(pCifsFile == NULL) if (pCifsFile == NULL)
goto cifs_create_out; goto cifs_create_out;
pCifsFile->netfid = fileHandle; pCifsFile->netfid = fileHandle;
pCifsFile->pid = current->tgid; pCifsFile->pid = current->tgid;
...@@ -295,16 +300,20 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) ...@@ -295,16 +300,20 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode)
pCifsFile->invalidHandle = FALSE; pCifsFile->invalidHandle = FALSE;
pCifsFile->closePend = FALSE; pCifsFile->closePend = FALSE;
init_MUTEX(&pCifsFile->fh_sem); init_MUTEX(&pCifsFile->fh_sem);
init_MUTEX(&pCifsFile->lock_sem); #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)
mutex_init(&pCifsFile->lock_mutex);
#else
init_MUTEX(&pCifsFile->lock_mutex);
#endif
INIT_LIST_HEAD(&pCifsFile->llist); INIT_LIST_HEAD(&pCifsFile->llist);
atomic_set(&pCifsFile->wrtPending,0); atomic_set(&pCifsFile->wrtPending, 0);
/* set the following in open now /* set the following in open now
pCifsFile->pfile = file; */ pCifsFile->pfile = file; */
write_lock(&GlobalSMBSeslock); write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist,&pTcon->openFileList); list_add(&pCifsFile->tlist, &pTcon->openFileList);
pCifsInode = CIFS_I(newinode); pCifsInode = CIFS_I(newinode);
if(pCifsInode) { if (pCifsInode) {
/* if readable file instance put first in list*/ /* if readable file instance put first in list*/
if (write_only == TRUE) { if (write_only == TRUE) {
list_add_tail(&pCifsFile->flist, list_add_tail(&pCifsFile->flist,
...@@ -313,12 +322,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode) ...@@ -313,12 +322,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode)
list_add(&pCifsFile->flist, list_add(&pCifsFile->flist,
&pCifsInode->openFileList); &pCifsInode->openFileList);
} }
if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = TRUE; pCifsInode->clientCanCacheAll = TRUE;
pCifsInode->clientCanCacheRead = TRUE; pCifsInode->clientCanCacheRead = TRUE;
cFYI(1,("Exclusive Oplock for inode %p", cFYI(1, ("Exclusive Oplock inode %p",
newinode)); newinode));
} else if((oplock & 0xF) == OPLOCK_READ) } else if ((oplock & 0xF) == OPLOCK_READ)
pCifsInode->clientCanCacheRead = TRUE; pCifsInode->clientCanCacheRead = TRUE;
} }
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
...@@ -347,7 +356,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic ...@@ -347,7 +356,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
char *full_path = NULL; char *full_path = NULL;
struct inode * newinode = NULL; struct inode *newinode = NULL;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
if (!old_valid_dev(device_number)) if (!old_valid_dev(device_number))
...@@ -360,12 +369,14 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic ...@@ -360,12 +369,14 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if(full_path == NULL) if (full_path == NULL)
rc = -ENOMEM; rc = -ENOMEM;
else if (pTcon->ses->capabilities & CAP_UNIX) { else if (pTcon->unix_ext) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
mode,(__u64)current->fsuid,(__u64)current->fsgid, mode, (__u64)current->fsuid,
(__u64)current->fsgid,
device_number, cifs_sb->local_nls, device_number, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
...@@ -377,26 +388,26 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic ...@@ -377,26 +388,26 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
if(!rc) { if (!rc) {
rc = cifs_get_inode_info_unix(&newinode, full_path, rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb,xid); inode->i_sb, xid);
if (pTcon->nocase) if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops; direntry->d_op = &cifs_ci_dentry_ops;
else else
direntry->d_op = &cifs_dentry_ops; direntry->d_op = &cifs_dentry_ops;
if(rc == 0) if (rc == 0)
d_instantiate(direntry, newinode); d_instantiate(direntry, newinode);
} }
} else { } else {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
int oplock = 0; int oplock = 0;
u16 fileHandle; u16 fileHandle;
FILE_ALL_INFO * buf; FILE_ALL_INFO * buf;
cFYI(1,("sfu compat create special file")); cFYI(1, ("sfu compat create special file"));
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if(buf == NULL) { if (buf == NULL) {
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
...@@ -416,16 +427,15 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic ...@@ -416,16 +427,15 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic
/* BB FIXME - add handling for backlevel servers /* BB FIXME - add handling for backlevel servers
which need legacy open and check for all which need legacy open and check for all
calls to SMBOpen for fallback to calls to SMBOpen for fallback to SMBLeagcyOpen */
SMBLeagcyOpen */ if (!rc) {
if(!rc) {
/* BB Do not bother to decode buf since no /* BB Do not bother to decode buf since no
local inode yet to put timestamps in, local inode yet to put timestamps in,
but we can reuse it safely */ but we can reuse it safely */
int bytes_written; unsigned int bytes_written;
struct win_dev *pdev; struct win_dev *pdev;
pdev = (struct win_dev *)buf; pdev = (struct win_dev *)buf;
if(S_ISCHR(mode)) { if (S_ISCHR(mode)) {
memcpy(pdev->type, "IntxCHR", 8); memcpy(pdev->type, "IntxCHR", 8);
pdev->major = pdev->major =
cpu_to_le64(MAJOR(device_number)); cpu_to_le64(MAJOR(device_number));
...@@ -436,7 +446,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic ...@@ -436,7 +446,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic
sizeof(struct win_dev), sizeof(struct win_dev),
0, &bytes_written, (char *)pdev, 0, &bytes_written, (char *)pdev,
NULL, 0); NULL, 0);
} else if(S_ISBLK(mode)) { } else if (S_ISBLK(mode)) {
memcpy(pdev->type, "IntxBLK", 8); memcpy(pdev->type, "IntxBLK", 8);
pdev->major = pdev->major =
cpu_to_le64(MAJOR(device_number)); cpu_to_le64(MAJOR(device_number));
...@@ -463,7 +473,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic ...@@ -463,7 +473,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int devic
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
struct dentry * struct dentry *
cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct nameidata *nd) cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
struct nameidata *nd)
#else #else
struct dentry * struct dentry *
cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry) cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry)
...@@ -482,8 +493,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry) ...@@ -482,8 +493,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry)
(" parent inode = 0x%p name is: %s and dentry = 0x%p", (" parent inode = 0x%p name is: %s and dentry = 0x%p",
parent_dir_inode, direntry->d_name.name, direntry)); parent_dir_inode, direntry->d_name.name, direntry));
/* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */
/* check whether path exists */ /* check whether path exists */
cifs_sb = CIFS_SB(parent_dir_inode->i_sb); cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
...@@ -507,7 +516,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry) ...@@ -507,7 +516,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry)
deadlock in the cases (beginning of sys_rename itself) deadlock in the cases (beginning of sys_rename itself)
in which we already have the sb rename sem */ in which we already have the sb rename sem */
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if(full_path == NULL) { if (full_path == NULL) {
FreeXid(xid); FreeXid(xid);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
...@@ -520,12 +529,12 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry) ...@@ -520,12 +529,12 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry)
cFYI(1, cFYI(1,
(" Full path: %s inode = 0x%p", full_path, direntry->d_inode)); (" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newInode, full_path, rc = cifs_get_inode_info_unix(&newInode, full_path,
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);
if ((rc == 0) && (newInode != NULL)) { if ((rc == 0) && (newInode != NULL)) {
if (pTcon->nocase) if (pTcon->nocase)
...@@ -549,8 +558,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry) ...@@ -549,8 +558,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry)
/* if it was once a directory (but how can we tell?) we could do /* if it was once a directory (but how can we tell?) we could do
shrink_dcache_parent(direntry); */ shrink_dcache_parent(direntry); */
} else { } else {
cERROR(1,("Error 0x%x on cifs_get_inode_info in lookup of %s", cERROR(1, ("Error 0x%x on cifs_get_inode_info in lookup of %s",
rc,full_path)); rc, full_path));
/* BB special case check for Access Denied - watch security /* BB special case check for Access Denied - watch security
exposure of returning dir info implicitly via different rc exposure of returning dir info implicitly via different rc
if file exists or not but no access BB */ if file exists or not but no access BB */
...@@ -578,7 +587,7 @@ cifs_d_revalidate(struct dentry *direntry, int flags) ...@@ -578,7 +587,7 @@ cifs_d_revalidate(struct dentry *direntry, int flags)
} else { } else {
cFYI(1, ("neg dentry 0x%p name = %s", cFYI(1, ("neg dentry 0x%p name = %s",
direntry, direntry->d_name.name)); direntry, direntry->d_name.name));
if(time_after(jiffies, direntry->d_time + HZ) || if (time_after(jiffies, direntry->d_time + HZ) ||
!lookupCacheEnabled) { !lookupCacheEnabled) {
d_drop(direntry); d_drop(direntry);
isValid = 0; isValid = 0;
...@@ -599,8 +608,7 @@ cifs_d_revalidate(struct dentry *direntry, int flags) ...@@ -599,8 +608,7 @@ cifs_d_revalidate(struct dentry *direntry, int flags)
struct dentry_operations cifs_dentry_ops = { struct dentry_operations cifs_dentry_ops = {
.d_revalidate = cifs_d_revalidate, .d_revalidate = cifs_d_revalidate,
/* d_delete: cifs_d_delete, *//* not needed except for debugging */ /* d_delete: cifs_d_delete, */ /* not needed except for debugging */
/* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */
}; };
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
......
...@@ -26,27 +26,45 @@ ...@@ -26,27 +26,45 @@
/* /*
* See Documentation/filesystems/Exporting * See Documentation/filesystems/Exporting
* and examples in fs/exportfs * and examples in fs/exportfs
*
* Since cifs is a network file system, an "fsid" must be included for
* any nfs exports file entries which refer to cifs paths. In addition
* the cifs mount must be mounted with the "serverino" option (ie use stable
* server inode numbers instead of locally generated temporary ones).
* Although cifs inodes do not use generation numbers (have generation number
* of zero) - the inode number alone should be good enough for simple cases
* in which users want to export cifs shares with NFS. The decode and encode
* could be improved by using a new routine which expects 64 bit inode numbers
* instead of the default 32 bit routines in fs/exportfs
*
*/ */
#include <linux/fs.h> #include <linux/fs.h>
#include "cifsglob.h"
#include "cifs_debug.h"
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
#include <linux/exportfs.h>
#endif
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
static struct dentry *cifs_get_parent(struct dentry *dentry) static struct dentry *cifs_get_parent(struct dentry *dentry)
{ {
/* BB need to add code here eventually to enable export via NFSD */ /* BB need to add code here eventually to enable export via NFSD */
cFYI(1, ("get parent for %p", dentry));
return ERR_PTR(-EACCES); return ERR_PTR(-EACCES);
} }
struct export_operations cifs_export_ops = { struct export_operations cifs_export_ops = {
.get_parent = cifs_get_parent, .get_parent = cifs_get_parent,
/* Following five export operations are unneeded so far and can default */ /* Following five export operations are unneeded so far and can default:
/* .get_dentry = .get_dentry =
.get_name = .get_name =
.find_exported_dentry = .find_exported_dentry =
.decode_fh = .decode_fh =
.encode_fs = */ .encode_fs = */
}; };
#endif /* EXPERIMENTAL */ #endif /* EXPERIMENTAL */
...@@ -35,39 +35,38 @@ static __u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags) ...@@ -35,39 +35,38 @@ static __u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags)
/* No way on Linux VFS to ask to monitor xattr /* No way on Linux VFS to ask to monitor xattr
changes (and no stream support either */ changes (and no stream support either */
if(fcntl_notify_flags & DN_ACCESS) { if (fcntl_notify_flags & DN_ACCESS) {
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS; cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
} }
if(fcntl_notify_flags & DN_MODIFY) { if (fcntl_notify_flags & DN_MODIFY) {
/* What does this mean on directories? */ /* What does this mean on directories? */
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE | cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_SIZE; FILE_NOTIFY_CHANGE_SIZE;
} }
if(fcntl_notify_flags & DN_CREATE) { if (fcntl_notify_flags & DN_CREATE) {
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_CREATION | cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_LAST_WRITE; FILE_NOTIFY_CHANGE_LAST_WRITE;
} }
if(fcntl_notify_flags & DN_DELETE) { if (fcntl_notify_flags & DN_DELETE) {
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE; cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE;
} }
if(fcntl_notify_flags & DN_RENAME) { if (fcntl_notify_flags & DN_RENAME) {
/* BB review this - checking various server behaviors */ /* BB review this - checking various server behaviors */
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_DIR_NAME | cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_FILE_NAME; FILE_NOTIFY_CHANGE_FILE_NAME;
} }
if(fcntl_notify_flags & DN_ATTRIB) { if (fcntl_notify_flags & DN_ATTRIB) {
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_SECURITY | cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_SECURITY |
FILE_NOTIFY_CHANGE_ATTRIBUTES; FILE_NOTIFY_CHANGE_ATTRIBUTES;
} }
/* if(fcntl_notify_flags & DN_MULTISHOT) { /* if (fcntl_notify_flags & DN_MULTISHOT) {
cifs_ntfy_flags |= ; cifs_ntfy_flags |= ;
} */ /* BB fixme - not sure how to handle this with CIFS yet */ } */ /* BB fixme - not sure how to handle this with CIFS yet */
return cifs_ntfy_flags; return cifs_ntfy_flags;
} }
int cifs_dir_notify(struct file * file, unsigned long arg) int cifs_dir_notify(struct file *file, unsigned long arg)
{ {
int xid; int xid;
int rc = -EINVAL; int rc = -EINVAL;
...@@ -78,30 +77,36 @@ int cifs_dir_notify(struct file * file, unsigned long arg) ...@@ -78,30 +77,36 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
__u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES;
__u16 netfid; __u16 netfid;
if (experimEnabled == 0)
if(experimEnabled == 0)
return 0; return 0;
xid = GetXid(); xid = GetXid();
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(file->f_dentry); full_path = build_path_from_dentry(file->f_dentry);
#else
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(file->f_path.dentry);
#endif
if(full_path == NULL) { if (full_path == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
} else { } else {
cFYI(1,("dir notify on file %s Arg 0x%lx",full_path,arg)); cFYI(1, ("dir notify on file %s Arg 0x%lx", full_path, arg));
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
GENERIC_READ | SYNCHRONIZE, 0 /* create options */, GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
&netfid, &oplock,NULL, cifs_sb->local_nls, &netfid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
/* BB fixme - add this handle to a notify handle list */ /* BB fixme - add this handle to a notify handle list */
if(rc) { if (rc) {
cFYI(1,("Could not open directory for notify")); cFYI(1, ("Could not open directory for notify"));
} else { } else {
filter = convert_to_cifs_notify_flags(arg); filter = convert_to_cifs_notify_flags(arg);
if(filter != 0) { if (filter != 0) {
rc = CIFSSMBNotify(xid, pTcon, rc = CIFSSMBNotify(xid, pTcon,
0 /* no subdirs */, netfid, 0 /* no subdirs */, netfid,
filter, file, arg & DN_MULTISHOT, filter, file, arg & DN_MULTISHOT,
...@@ -113,7 +118,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg) ...@@ -113,7 +118,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
it would close automatically but may be a way it would close automatically but may be a way
to do it easily when inode freed or when to do it easily when inode freed or when
notify info is cleared/changed */ notify info is cleared/changed */
cFYI(1,("notify rc %d",rc)); cFYI(1, ("notify rc %d", rc));
} }
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* vfs operations that deal with files * vfs operations that deal with files
* *
* Copyright (C) International Business Machines Corp., 2002,2003 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* Jeremy Allison (jra@samba.org) * Jeremy Allison (jra@samba.org)
* *
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/smp_lock.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "cifsfs.h" #include "cifsfs.h"
...@@ -57,7 +56,11 @@ static inline struct cifsFileInfo *cifs_init_private( ...@@ -57,7 +56,11 @@ static inline struct cifsFileInfo *cifs_init_private(
private_data->netfid = netfid; private_data->netfid = netfid;
private_data->pid = current->tgid; private_data->pid = current->tgid;
init_MUTEX(&private_data->fh_sem); init_MUTEX(&private_data->fh_sem);
init_MUTEX(&private_data->lock_sem); #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)
mutex_init(&private_data->lock_mutex);
#else
init_MUTEX(&private_data->lock_mutex);
#endif
INIT_LIST_HEAD(&private_data->llist); INIT_LIST_HEAD(&private_data->llist);
private_data->pfile = file; /* needed for writepage */ private_data->pfile = file; /* needed for writepage */
private_data->pInode = inode; private_data->pInode = inode;
...@@ -67,7 +70,7 @@ static inline struct cifsFileInfo *cifs_init_private( ...@@ -67,7 +70,7 @@ static inline struct cifsFileInfo *cifs_init_private(
does not tell us which handle the write is for so there can does not tell us which handle the write is for so there can
be a close (overlapping with write) of the filehandle that be a close (overlapping with write) of the filehandle that
cifs_writepages chose to use */ cifs_writepages chose to use */
atomic_set(&private_data->wrtPending,0); atomic_set(&private_data->wrtPending, 0);
return private_data; return private_data;
} }
...@@ -140,15 +143,26 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, ...@@ -140,15 +143,26 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
/* if not oplocked, invalidate inode pages if mtime or file /* if not oplocked, invalidate inode pages if mtime or file
size changed */ size changed */
temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime)); temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) && if (timespec_equal(&file->f_dentry->d_inode->i_mtime, &temp) &&
(file->f_dentry->d_inode->i_size == (file->f_dentry->d_inode->i_size ==
(loff_t)le64_to_cpu(buf->EndOfFile))) { (loff_t)le64_to_cpu(buf->EndOfFile))) {
cFYI(1, ("inode unchanged on server")); cFYI(1, ("inode unchanged on server"));
} else { } else {
if (file->f_dentry->d_inode->i_mapping) { if (file->f_dentry->d_inode->i_mapping) {
#else
if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) &&
(file->f_path.dentry->d_inode->i_size ==
(loff_t)le64_to_cpu(buf->EndOfFile))) {
cFYI(1, ("inode unchanged on server"));
} else {
if (file->f_path.dentry->d_inode->i_mapping) {
#endif
/* BB no need to lock inode until after invalidate /* BB no need to lock inode until after invalidate
since namei code should already have it locked? */ since namei code should already have it locked? */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19)
filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping);
#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
filemap_write_and_wait(file->f_dentry->d_inode->i_mapping); filemap_write_and_wait(file->f_dentry->d_inode->i_mapping);
#else #else
filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
...@@ -157,22 +171,39 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, ...@@ -157,22 +171,39 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
} }
cFYI(1, ("invalidating remote inode since open detected it " cFYI(1, ("invalidating remote inode since open detected it "
"changed")); "changed"));
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
invalidate_remote_inode(file->f_dentry->d_inode); invalidate_remote_inode(file->f_dentry->d_inode);
#else
invalidate_remote_inode(file->f_path.dentry->d_inode);
#endif
} }
client_can_cache: client_can_cache:
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
#else
rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
#endif
full_path, inode->i_sb, xid); full_path, inode->i_sb, xid);
else
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
rc = cifs_get_inode_info(&file->f_dentry->d_inode, rc = cifs_get_inode_info(&file->f_dentry->d_inode,
#else
rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
#endif
full_path, buf, inode->i_sb, xid); full_path, buf, inode->i_sb, xid);
if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) { if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = TRUE; pCifsInode->clientCanCacheAll = TRUE;
pCifsInode->clientCanCacheRead = TRUE; pCifsInode->clientCanCacheRead = TRUE;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
cFYI(1, ("Exclusive Oplock granted on inode %p", cFYI(1, ("Exclusive Oplock granted on inode %p",
file->f_dentry->d_inode)); file->f_dentry->d_inode));
#else
cFYI(1, ("Exclusive Oplock granted on inode %p",
file->f_path.dentry->d_inode));
#endif
} else if ((*oplock & 0xF) == OPLOCK_READ) } else if ((*oplock & 0xF) == OPLOCK_READ)
pCifsInode->clientCanCacheRead = TRUE; pCifsInode->clientCanCacheRead = TRUE;
...@@ -201,7 +232,11 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -201,7 +232,11 @@ int cifs_open(struct inode *inode, struct file *file)
if (file->f_flags & O_CREAT) { if (file->f_flags & O_CREAT) {
/* search inode for this file and fill in file->private_data */ /* search inode for this file and fill in file->private_data */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
pCifsInode = CIFS_I(file->f_dentry->d_inode); pCifsInode = CIFS_I(file->f_dentry->d_inode);
#else
pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
#endif
read_lock(&GlobalSMBSeslock); read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &pCifsInode->openFileList) { list_for_each(tmp, &pCifsInode->openFileList) {
pCifsFile = list_entry(tmp, struct cifsFileInfo, pCifsFile = list_entry(tmp, struct cifsFileInfo,
...@@ -229,13 +264,17 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -229,13 +264,17 @@ int cifs_open(struct inode *inode, struct file *file)
} }
} }
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
full_path = build_path_from_dentry(file->f_dentry); full_path = build_path_from_dentry(file->f_dentry);
#else
full_path = build_path_from_dentry(file->f_path.dentry);
#endif
if (full_path == NULL) { if (full_path == NULL) {
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
inode, file->f_flags, full_path)); inode, file->f_flags, full_path));
desiredAccess = cifs_convert_flags(file->f_flags); desiredAccess = cifs_convert_flags(file->f_flags);
...@@ -314,7 +353,11 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -314,7 +353,11 @@ int cifs_open(struct inode *inode, struct file *file)
write_lock(&GlobalSMBSeslock); write_lock(&GlobalSMBSeslock);
list_add(&pCifsFile->tlist, &pTcon->openFileList); list_add(&pCifsFile->tlist, &pTcon->openFileList);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
pCifsInode = CIFS_I(file->f_dentry->d_inode); pCifsInode = CIFS_I(file->f_dentry->d_inode);
#else
pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
#endif
if (pCifsInode) { if (pCifsInode) {
rc = cifs_open_inode_helper(inode, file, pCifsInode, rc = cifs_open_inode_helper(inode, file, pCifsInode,
pCifsFile, pTcon, pCifsFile, pTcon,
...@@ -326,7 +369,7 @@ int cifs_open(struct inode *inode, struct file *file) ...@@ -326,7 +369,7 @@ int cifs_open(struct inode *inode, struct file *file)
if (oplock & CIFS_CREATE_ACTION) { if (oplock & CIFS_CREATE_ACTION) {
/* time to set mode which we can not set earlier due to /* time to set mode which we can not set earlier due to
problems creating new read-only files */ problems creating new read-only files */
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { if (pTcon->unix_ext) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, CIFSSMBUnixSetPerms(xid, pTcon, full_path,
inode->i_mode, inode->i_mode,
(__u64)-1, (__u64)-1, 0 /* dev */, (__u64)-1, (__u64)-1, 0 /* dev */,
...@@ -360,8 +403,7 @@ static int cifs_relock_file(struct cifsFileInfo *cifsFile) ...@@ -360,8 +403,7 @@ static int cifs_relock_file(struct cifsFileInfo *cifsFile)
return rc; return rc;
} }
static int cifs_reopen_file(struct inode *inode, struct file *file, static int cifs_reopen_file(struct file *file, int can_flush)
int can_flush)
{ {
int rc = -EACCES; int rc = -EACCES;
int xid, oplock; int xid, oplock;
...@@ -369,13 +411,12 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, ...@@ -369,13 +411,12 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct cifsFileInfo *pCifsFile; struct cifsFileInfo *pCifsFile;
struct cifsInodeInfo *pCifsInode; struct cifsInodeInfo *pCifsInode;
struct inode *inode;
char *full_path = NULL; char *full_path = NULL;
int desiredAccess; int desiredAccess;
int disposition = FILE_OPEN; int disposition = FILE_OPEN;
__u16 netfid; __u16 netfid;
if (inode == NULL)
return -EBADF;
if (file->private_data) { if (file->private_data) {
pCifsFile = (struct cifsFileInfo *)file->private_data; pCifsFile = (struct cifsFileInfo *)file->private_data;
} else } else
...@@ -389,27 +430,65 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, ...@@ -389,27 +430,65 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
return 0; return 0;
} }
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
if (file->f_dentry == NULL) { if (file->f_dentry == NULL) {
up(&pCifsFile->fh_sem); cERROR(1, ("no valid name if dentry freed"));
cFYI(1, ("failed file reopen, no valid name if dentry freed")); dump_stack();
FreeXid(xid); rc = -EBADF;
return -EBADF; goto reopen_error_exit;
} }
inode = file->f_dentry->d_inode;
if (inode == NULL) {
cERROR(1, ("inode not valid"));
dump_stack();
rc = -EBADF;
goto reopen_error_exit;
}
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
/* can not grab rename sem here because various ops, including /* can not grab rename sem here because various ops, including
those that already have the rename sem can end up causing writepage those that already have the rename sem can end up causing writepage
to get called and if the server was down that means we end up here, to get called and if the server was down that means we end up here,
and we can never tell if the caller already has the rename_sem */ and we can never tell if the caller already has the rename_sem */
full_path = build_path_from_dentry(file->f_dentry); full_path = build_path_from_dentry(file->f_dentry);
#else
if (file->f_path.dentry == NULL) {
cERROR(1, ("no valid name if dentry freed"));
dump_stack();
rc = -EBADF;
goto reopen_error_exit;
}
inode = file->f_path.dentry->d_inode;
if (inode == NULL) {
cERROR(1, ("inode not valid"));
dump_stack();
rc = -EBADF;
goto reopen_error_exit;
}
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
/* can not grab rename sem here because various ops, including
those that already have the rename sem can end up causing writepage
to get called and if the server was down that means we end up here,
and we can never tell if the caller already has the rename_sem */
full_path = build_path_from_dentry(file->f_path.dentry);
#endif
if (full_path == NULL) { if (full_path == NULL) {
rc = -ENOMEM;
reopen_error_exit:
up(&pCifsFile->fh_sem); up(&pCifsFile->fh_sem);
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return rc;
} }
cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
inode, file->f_flags,full_path)); inode, file->f_flags, full_path));
desiredAccess = cifs_convert_flags(file->f_flags); desiredAccess = cifs_convert_flags(file->f_flags);
if (oplockEnabled) if (oplockEnabled)
...@@ -423,13 +502,6 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, ...@@ -423,13 +502,6 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
and server version of file size can be stale. If we knew for sure and server version of file size can be stale. If we knew for sure
that inode was not dirty locally we could do this */ that inode was not dirty locally we could do this */
/* buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if (buf == 0) {
up(&pCifsFile->fh_sem);
kfree(full_path);
FreeXid(xid);
return -ENOMEM;
} */
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
CREATE_NOT_DIR, &netfid, &oplock, NULL, CREATE_NOT_DIR, &netfid, &oplock, NULL,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
...@@ -451,12 +523,11 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, ...@@ -451,12 +523,11 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
filemap_fdatawrite(inode->i_mapping); filemap_fdatawrite(inode->i_mapping);
filemap_fdatawait(inode->i_mapping); filemap_fdatawait(inode->i_mapping);
#endif #endif
/* temporarily disable caching while we /* temporarily disable caching while we
go to server to get inode info */ go to server to get inode info */
pCifsInode->clientCanCacheAll = FALSE; pCifsInode->clientCanCacheAll = FALSE;
pCifsInode->clientCanCacheRead = FALSE; pCifsInode->clientCanCacheRead = FALSE;
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&inode, rc = cifs_get_inode_info_unix(&inode,
full_path, inode->i_sb, xid); full_path, inode->i_sb, xid);
else else
...@@ -472,8 +543,13 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, ...@@ -472,8 +543,13 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = TRUE; pCifsInode->clientCanCacheAll = TRUE;
pCifsInode->clientCanCacheRead = TRUE; pCifsInode->clientCanCacheRead = TRUE;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
cFYI(1, ("Exclusive Oplock granted on inode %p", cFYI(1, ("Exclusive Oplock granted on inode %p",
file->f_dentry->d_inode)); file->f_dentry->d_inode));
#else
cFYI(1, ("Exclusive Oplock granted on inode %p",
file->f_path.dentry->d_inode));
#endif
} else if ((oplock & 0xF) == OPLOCK_READ) { } else if ((oplock & 0xF) == OPLOCK_READ) {
pCifsInode->clientCanCacheRead = TRUE; pCifsInode->clientCanCacheRead = TRUE;
pCifsInode->clientCanCacheAll = FALSE; pCifsInode->clientCanCacheAll = FALSE;
...@@ -493,7 +569,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, ...@@ -493,7 +569,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
int cifs_close(struct inode *inode, struct file *file) int cifs_close(struct inode *inode, struct file *file)
{ {
int rc = 0; int rc = 0;
int xid; int xid, timeout;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct cifsFileInfo *pSMBFile = struct cifsFileInfo *pSMBFile =
...@@ -511,9 +587,9 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -511,9 +587,9 @@ int cifs_close(struct inode *inode, struct file *file)
/* no sense reconnecting to close a file that is /* no sense reconnecting to close a file that is
already closed */ already closed */
if (pTcon->tidStatus != CifsNeedReconnect) { if (pTcon->tidStatus != CifsNeedReconnect) {
int timeout = 2; timeout = 2;
while((atomic_read(&pSMBFile->wrtPending) != 0) while ((atomic_read(&pSMBFile->wrtPending) != 0)
&& (timeout < 1000) ) { && (timeout <= 2048)) {
/* Give write a better chance to get to /* Give write a better chance to get to
server ahead of the close. We do not server ahead of the close. We do not
want to add a wait_q here as it would want to add a wait_q here as it would
...@@ -522,13 +598,14 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -522,13 +598,14 @@ int cifs_close(struct inode *inode, struct file *file)
but this should give enough time to but this should give enough time to
clear the socket */ clear the socket */
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
cFYI(1,("close delay, write pending")); cFYI(1, ("close delay, write pending"));
#endif /* DEBUG2 */ #endif /* DEBUG2 */
msleep(timeout); msleep(timeout);
timeout *= 4; timeout *= 4;
} }
if(atomic_read(&pSMBFile->wrtPending)) if (atomic_read(&pSMBFile->wrtPending))
cERROR(1,("close with pending writes")); cERROR(1,
("close with pending writes"));
rc = CIFSSMBClose(xid, pTcon, rc = CIFSSMBClose(xid, pTcon,
pSMBFile->netfid); pSMBFile->netfid);
} }
...@@ -536,23 +613,41 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -536,23 +613,41 @@ int cifs_close(struct inode *inode, struct file *file)
/* Delete any outstanding lock records. /* Delete any outstanding lock records.
We'll lose them when the file is closed anyway. */ We'll lose them when the file is closed anyway. */
down(&pSMBFile->lock_sem); mutex_lock(&pSMBFile->lock_mutex);
list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) { list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
list_del(&li->llist); list_del(&li->llist);
kfree(li); kfree(li);
} }
up(&pSMBFile->lock_sem); mutex_unlock(&pSMBFile->lock_mutex);
write_lock(&GlobalSMBSeslock); write_lock(&GlobalSMBSeslock);
list_del(&pSMBFile->flist); list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist); list_del(&pSMBFile->tlist);
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
timeout = 10;
/* We waited above to give the SMBWrite a chance to issue
on the wire (so we do not get SMBWrite returning EBADF
if writepages is racing with close. Note that writepages
does not specify a file handle, so it is possible for a file
to be opened twice, and the application close the "wrong"
file handle - in these cases we delay long enough to allow
the SMBWrite to get on the wire before the SMB Close.
We allow total wait here over 45 seconds, more than
oplock break time, and more than enough to allow any write
to complete on the server, or to time out on the client */
while ((atomic_read(&pSMBFile->wrtPending) != 0)
&& (timeout <= 50000)) {
cERROR(1, ("writes pending, delay free of handle"));
msleep(timeout);
timeout *= 8;
}
kfree(pSMBFile->search_resume_name); kfree(pSMBFile->search_resume_name);
kfree(file->private_data); kfree(file->private_data);
file->private_data = NULL; file->private_data = NULL;
} else } else
rc = -EBADF; rc = -EBADF;
read_lock(&GlobalSMBSeslock);
if (list_empty(&(CIFS_I(inode)->openFileList))) { if (list_empty(&(CIFS_I(inode)->openFileList))) {
cFYI(1, ("closing last open instance for inode %p", inode)); cFYI(1, ("closing last open instance for inode %p", inode));
/* if the file is not open we do not know if we can cache info /* if the file is not open we do not know if we can cache info
...@@ -560,7 +655,8 @@ int cifs_close(struct inode *inode, struct file *file) ...@@ -560,7 +655,8 @@ int cifs_close(struct inode *inode, struct file *file)
CIFS_I(inode)->clientCanCacheRead = FALSE; CIFS_I(inode)->clientCanCacheRead = FALSE;
CIFS_I(inode)->clientCanCacheAll = FALSE; CIFS_I(inode)->clientCanCacheAll = FALSE;
} }
if ((rc ==0) && CIFS_I(inode)->write_behind_rc) read_unlock(&GlobalSMBSeslock);
if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
rc = CIFS_I(inode)->write_behind_rc; rc = CIFS_I(inode)->write_behind_rc;
FreeXid(xid); FreeXid(xid);
return rc; return rc;
...@@ -580,7 +676,12 @@ int cifs_closedir(struct inode *inode, struct file *file) ...@@ -580,7 +676,12 @@ int cifs_closedir(struct inode *inode, struct file *file)
if (pCFileStruct) { if (pCFileStruct) {
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_dentry->d_sb); struct cifs_sb_info *cifs_sb =
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
CIFS_SB(file->f_dentry->d_sb);
#else
CIFS_SB(file->f_path.dentry->d_sb);
#endif
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
...@@ -598,7 +699,7 @@ int cifs_closedir(struct inode *inode, struct file *file) ...@@ -598,7 +699,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
if (ptmp) { if (ptmp) {
cFYI(1, ("closedir free smb buf in srch struct")); cFYI(1, ("closedir free smb buf in srch struct"));
pCFileStruct->srch_inf.ntwrk_buf_start = NULL; pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
if(pCFileStruct->srch_inf.smallBuf) if (pCFileStruct->srch_inf.smallBuf)
cifs_small_buf_release(ptmp); cifs_small_buf_release(ptmp);
else else
cifs_buf_release(ptmp); cifs_buf_release(ptmp);
...@@ -620,15 +721,16 @@ int cifs_closedir(struct inode *inode, struct file *file) ...@@ -620,15 +721,16 @@ int cifs_closedir(struct inode *inode, struct file *file)
static int store_file_lock(struct cifsFileInfo *fid, __u64 len, static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
__u64 offset, __u8 lockType) __u64 offset, __u8 lockType)
{ {
struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); struct cifsLockInfo *li =
kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
if (li == NULL) if (li == NULL)
return -ENOMEM; return -ENOMEM;
li->offset = offset; li->offset = offset;
li->length = len; li->length = len;
li->type = lockType; li->type = lockType;
down(&fid->lock_sem); mutex_lock(&fid->lock_mutex);
list_add(&li->llist, &fid->llist); list_add(&li->llist, &fid->llist);
up(&fid->lock_sem); mutex_unlock(&fid->lock_mutex);
return 0; return 0;
} }
...@@ -693,7 +795,11 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -693,7 +795,11 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
} else } else
cFYI(1, ("Unknown type of lock")); cFYI(1, ("Unknown type of lock"));
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
#else
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
#endif
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if (file->private_data == NULL) { if (file->private_data == NULL) {
...@@ -709,9 +815,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -709,9 +815,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
account for negative length which we can not accept over the account for negative length which we can not accept over the
wire */ wire */
if (IS_GETLK(cmd)) { if (IS_GETLK(cmd)) {
if(posix_locking) { if (posix_locking) {
int posix_lock_type; int posix_lock_type;
if(lockType & LOCKING_ANDX_SHARED_LOCK) if (lockType & LOCKING_ANDX_SHARED_LOCK)
posix_lock_type = CIFS_RDLCK; posix_lock_type = CIFS_RDLCK;
else else
posix_lock_type = CIFS_WRLCK; posix_lock_type = CIFS_WRLCK;
...@@ -755,22 +861,24 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -755,22 +861,24 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
if (posix_locking) { if (posix_locking) {
int posix_lock_type; int posix_lock_type;
if(lockType & LOCKING_ANDX_SHARED_LOCK) if (lockType & LOCKING_ANDX_SHARED_LOCK)
posix_lock_type = CIFS_RDLCK; posix_lock_type = CIFS_RDLCK;
else else
posix_lock_type = CIFS_WRLCK; posix_lock_type = CIFS_WRLCK;
if(numUnlock == 1) if (numUnlock == 1)
posix_lock_type = CIFS_UNLCK; posix_lock_type = CIFS_UNLCK;
rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */, rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
length, pfLock, length, pfLock,
posix_lock_type, wait_flag); posix_lock_type, wait_flag);
} else { } else {
struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data; struct cifsFileInfo *fid =
(struct cifsFileInfo *)file->private_data;
if (numLock) { if (numLock) {
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, rc = CIFSSMBLock(xid, pTcon, netfid, length,
pfLock->fl_start,
0, numLock, lockType, wait_flag); 0, numLock, lockType, wait_flag);
if (rc == 0) { if (rc == 0) {
...@@ -785,11 +893,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -785,11 +893,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
struct cifsLockInfo *li, *tmp; struct cifsLockInfo *li, *tmp;
rc = 0; rc = 0;
down(&fid->lock_sem); mutex_lock(&fid->lock_mutex);
list_for_each_entry_safe(li, tmp, &fid->llist, llist) { list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
if (pfLock->fl_start <= li->offset && if (pfLock->fl_start <= li->offset &&
length >= li->length) { (pfLock->fl_start + length) >=
stored_rc = CIFSSMBLock(xid, pTcon, netfid, (li->offset + li->length)) {
stored_rc = CIFSSMBLock(xid, pTcon,
netfid,
li->length, li->offset, li->length, li->offset,
1, 0, li->type, FALSE); 1, 0, li->type, FALSE);
if (stored_rc) if (stored_rc)
...@@ -799,7 +909,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -799,7 +909,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
kfree(li); kfree(li);
} }
} }
up(&fid->lock_sem); mutex_unlock(&fid->lock_mutex);
} }
} }
...@@ -822,31 +932,29 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -822,31 +932,29 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
int xid, long_op; int xid, long_op;
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
if (file->f_dentry == NULL) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
return -EBADF;
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
if (cifs_sb == NULL) #else
return -EBADF; cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
#endif
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
/* cFYI(1, /* cFYI(1,
(" write %d bytes to offset %lld of %s", write_size, (" write %d bytes to offset %lld of %s", write_size,
*poffset, file->f_dentry->d_name.name)); */ *poffset, file->f_path.dentry->d_name.name)); */
if (file->private_data == NULL) if (file->private_data == NULL)
return -EBADF; return -EBADF;
else
open_file = (struct cifsFileInfo *) file->private_data; open_file = (struct cifsFileInfo *) file->private_data;
xid = GetXid(); xid = GetXid();
if (file->f_dentry->d_inode == NULL) {
FreeXid(xid);
return -EBADF;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
if (*poffset > file->f_dentry->d_inode->i_size) if (*poffset > file->f_dentry->d_inode->i_size)
#else
if (*poffset > file->f_path.dentry->d_inode->i_size)
#endif
long_op = 2; /* writes past end of file can take a long time */ long_op = 2; /* writes past end of file can take a long time */
else else
long_op = 1; long_op = 1;
...@@ -871,17 +979,11 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -871,17 +979,11 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
return -EBADF; return -EBADF;
} }
if (open_file->invalidHandle) { if (open_file->invalidHandle) {
if ((file->f_dentry == NULL) ||
(file->f_dentry->d_inode == NULL)) {
FreeXid(xid);
return total_written;
}
/* we could deadlock if we called /* we could deadlock if we called
filemap_fdatawait from here so tell filemap_fdatawait from here so tell
reopen_file not to flush data to server reopen_file not to flush data to server
now */ now */
rc = cifs_reopen_file(file->f_dentry->d_inode, rc = cifs_reopen_file(file, FALSE);
file, FALSE);
if (rc != 0) if (rc != 0)
break; break;
} }
...@@ -909,18 +1011,35 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -909,18 +1011,35 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
cifs_stats_bytes_written(pTcon, total_written); cifs_stats_bytes_written(pTcon, total_written);
/* since the write may have blocked check these pointers again */ /* since the write may have blocked check these pointers again */
if (file->f_dentry) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
if (file->f_dentry->d_inode) { if ((file->f_dentry) && (file->f_dentry->d_inode)) {
struct inode *inode = file->f_dentry->d_inode; struct inode *inode = file->f_dentry->d_inode;
inode->i_ctime = inode->i_mtime = /* Do not update local mtime - server will set its actual value on write
current_fs_time(inode->i_sb); * inode->i_ctime = inode->i_mtime =
* current_fs_time(inode->i_sb);*/
if (total_written > 0) { if (total_written > 0) {
spin_lock(&inode->i_lock);
if (*poffset > file->f_dentry->d_inode->i_size) if (*poffset > file->f_dentry->d_inode->i_size)
i_size_write(file->f_dentry->d_inode, i_size_write(file->f_dentry->d_inode,
*poffset); *poffset);
spin_unlock(&inode->i_lock);
} }
mark_inode_dirty_sync(file->f_dentry->d_inode); mark_inode_dirty_sync(file->f_dentry->d_inode);
#else
if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
struct inode *inode = file->f_path.dentry->d_inode;
/* Do not update local mtime - server will set its actual value on write
* inode->i_ctime = inode->i_mtime =
* current_fs_time(inode->i_sb);*/
if (total_written > 0) {
spin_lock(&inode->i_lock);
if (*poffset > file->f_path.dentry->d_inode->i_size)
i_size_write(file->f_path.dentry->d_inode,
*poffset);
spin_unlock(&inode->i_lock);
} }
mark_inode_dirty_sync(file->f_path.dentry->d_inode);
#endif
} }
FreeXid(xid); FreeXid(xid);
return total_written; return total_written;
...@@ -937,30 +1056,37 @@ static ssize_t cifs_write(struct file *file, const char *write_data, ...@@ -937,30 +1056,37 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
int xid, long_op; int xid, long_op;
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
if (file->f_dentry == NULL) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
return -EBADF;
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
if (cifs_sb == NULL)
return -EBADF;
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
cFYI(1,("write %zd bytes to offset %lld of %s", write_size, cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
*poffset, file->f_dentry->d_name.name)); *poffset, file->f_dentry->d_name.name));
if (file->private_data == NULL) if (file->private_data == NULL)
return -EBADF; return -EBADF;
else
open_file = (struct cifsFileInfo *)file->private_data; open_file = (struct cifsFileInfo *)file->private_data;
xid = GetXid(); xid = GetXid();
if (file->f_dentry->d_inode == NULL) {
FreeXid(xid);
return -EBADF;
}
if (*poffset > file->f_dentry->d_inode->i_size) if (*poffset > file->f_dentry->d_inode->i_size)
#else
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
*poffset, file->f_path.dentry->d_name.name));
if (file->private_data == NULL)
return -EBADF;
open_file = (struct cifsFileInfo *)file->private_data;
xid = GetXid();
if (*poffset > file->f_path.dentry->d_inode->i_size)
#endif
long_op = 2; /* writes past end of file can take a long time */ long_op = 2; /* writes past end of file can take a long time */
else else
long_op = 1; long_op = 1;
...@@ -986,21 +1112,15 @@ static ssize_t cifs_write(struct file *file, const char *write_data, ...@@ -986,21 +1112,15 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
return -EBADF; return -EBADF;
} }
if (open_file->invalidHandle) { if (open_file->invalidHandle) {
if ((file->f_dentry == NULL) ||
(file->f_dentry->d_inode == NULL)) {
FreeXid(xid);
return total_written;
}
/* we could deadlock if we called /* we could deadlock if we called
filemap_fdatawait from here so tell filemap_fdatawait from here so tell
reopen_file not to flush data to reopen_file not to flush data to
server now */ server now */
rc = cifs_reopen_file(file->f_dentry->d_inode, rc = cifs_reopen_file(file, FALSE);
file, FALSE);
if (rc != 0) if (rc != 0)
break; break;
} }
if(experimEnabled || (pTcon->ses->server && if (experimEnabled || (pTcon->ses->server &&
((pTcon->ses->server->secMode & ((pTcon->ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
== 0))) { == 0))) {
...@@ -1042,18 +1162,33 @@ static ssize_t cifs_write(struct file *file, const char *write_data, ...@@ -1042,18 +1162,33 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
cifs_stats_bytes_written(pTcon, total_written); cifs_stats_bytes_written(pTcon, total_written);
/* since the write may have blocked check these pointers again */ /* since the write may have blocked check these pointers again */
if (file->f_dentry) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
if (file->f_dentry->d_inode) { if ((file->f_dentry) && (file->f_dentry->d_inode)) {
/*BB We could make this contingent on superblock ATIME flag too */ /*BB We could make this contingent on superblock ATIME flag too */
/* file->f_dentry->d_inode->i_ctime = /* file->f_dentry->d_inode->i_ctime =
file->f_dentry->d_inode->i_mtime = CURRENT_TIME;*/ file->f_dentry->d_inode->i_mtime = CURRENT_TIME;*/
if (total_written > 0) { if (total_written > 0) {
spin_lock(&file->f_dentry->d_inode->i_lock);
if (*poffset > file->f_dentry->d_inode->i_size) if (*poffset > file->f_dentry->d_inode->i_size)
i_size_write(file->f_dentry->d_inode, i_size_write(file->f_dentry->d_inode,
*poffset); *poffset);
spin_unlock(&file->f_dentry->d_inode->i_lock);
} }
mark_inode_dirty_sync(file->f_dentry->d_inode); mark_inode_dirty_sync(file->f_dentry->d_inode);
#else
if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
/*BB We could make this contingent on superblock ATIME flag too */
/* file->f_path.dentry->d_inode->i_ctime =
file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/
if (total_written > 0) {
spin_lock(&file->f_path.dentry->d_inode->i_lock);
if (*poffset > file->f_path.dentry->d_inode->i_size)
i_size_write(file->f_path.dentry->d_inode,
*poffset);
spin_unlock(&file->f_path.dentry->d_inode->i_lock);
} }
mark_inode_dirty_sync(file->f_path.dentry->d_inode);
#endif
} }
FreeXid(xid); FreeXid(xid);
return total_written; return total_written;
...@@ -1068,8 +1203,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) ...@@ -1068,8 +1203,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
the VFS or MM) should not happen but we had reports of on oops (due to the VFS or MM) should not happen but we had reports of on oops (due to
it being zero) during stress testcases so we need to check for it */ it being zero) during stress testcases so we need to check for it */
if(cifs_inode == NULL) { if (cifs_inode == NULL) {
cERROR(1,("Null inode passed to cifs_writeable_file")); cERROR(1, ("Null inode passed to cifs_writeable_file"));
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 19) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 19)
dump_stack(); dump_stack();
#endif #endif
...@@ -1085,26 +1220,25 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) ...@@ -1085,26 +1220,25 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
(open_file->pfile->f_flags & O_WRONLY))) { (open_file->pfile->f_flags & O_WRONLY))) {
atomic_inc(&open_file->wrtPending); atomic_inc(&open_file->wrtPending);
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
if((open_file->invalidHandle) && if (open_file->invalidHandle) {
(!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) { rc = cifs_reopen_file(open_file->pfile, FALSE);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
rc = cifs_reopen_file(open_file->pfile->f_dentry->d_inode,
#else
rc = cifs_reopen_file(&cifs_inode->vfs_inode,
#endif
open_file->pfile, FALSE);
/* if it fails, try another handle - might be */ /* if it fails, try another handle - might be */
/* dangerous to hold up writepages with retry */ /* dangerous to hold up writepages with retry */
if(rc) { if (rc) {
cFYI(1,("failed on reopen file in wp")); cFYI(1, ("wp failed on reopen file"));
read_lock(&GlobalSMBSeslock); read_lock(&GlobalSMBSeslock);
/* can not use this handle, no write /* can not use this handle, no write
pending on this one after all */ pending on this one after all */
atomic_dec atomic_dec(&open_file->wrtPending);
(&open_file->wrtPending);
continue; continue;
} }
} }
if (open_file->closePend) {
read_lock(&GlobalSMBSeslock);
atomic_dec(&open_file->wrtPending);
continue;
}
return open_file; return open_file;
} }
} }
...@@ -1172,7 +1306,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) ...@@ -1172,7 +1306,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
return rc; return rc;
} }
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 14) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 14)
static int cifs_writepages(struct address_space *mapping, static int cifs_writepages(struct address_space *mapping,
struct writeback_control *wbc) struct writeback_control *wbc)
...@@ -1182,14 +1315,14 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -1182,14 +1315,14 @@ static int cifs_writepages(struct address_space *mapping,
unsigned int bytes_written; unsigned int bytes_written;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
int done = 0; int done = 0;
pgoff_t end = -1; pgoff_t end;
pgoff_t index; pgoff_t index;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17)
int range_whole = 0; int range_whole = 0;
#else #else
int is_range = 0; int is_range = 0;
#endif /* 2.6.17 */ #endif /* 2.6.17 */
struct kvec * iov; struct kvec *iov;
int len; int len;
int n_iov = 0; int n_iov = 0;
pgoff_t next; pgoff_t next;
...@@ -1211,14 +1344,14 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -1211,14 +1344,14 @@ static int cifs_writepages(struct address_space *mapping,
if (cifs_sb->wsize < PAGE_CACHE_SIZE) if (cifs_sb->wsize < PAGE_CACHE_SIZE)
return generic_writepages(mapping, wbc); return generic_writepages(mapping, wbc);
if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
if(cifs_sb->tcon->ses->server->secMode & if (cifs_sb->tcon->ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
if(!experimEnabled) if (!experimEnabled)
return generic_writepages(mapping, wbc); return generic_writepages(mapping, wbc);
iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL); iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
if(iov == NULL) if (iov == NULL)
return generic_writepages(mapping, wbc); return generic_writepages(mapping, wbc);
...@@ -1247,6 +1380,7 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -1247,6 +1380,7 @@ static int cifs_writepages(struct address_space *mapping,
scanned = 1; scanned = 1;
} }
#else #else
end = -1;
if (wbc->sync_mode == WB_SYNC_NONE) if (wbc->sync_mode == WB_SYNC_NONE)
index = mapping->writeback_index; /* Start from prev offset */ index = mapping->writeback_index; /* Start from prev offset */
else { else {
...@@ -1370,7 +1504,7 @@ retry: ...@@ -1370,7 +1504,7 @@ retry:
1); 1);
atomic_dec(&open_file->wrtPending); atomic_dec(&open_file->wrtPending);
if (rc || bytes_written < bytes_to_write) { if (rc || bytes_written < bytes_to_write) {
cERROR(1,("Write2 ret %d, written = %d", cERROR(1, ("Write2 ret %d, wrote %d",
rc, bytes_written)); rc, bytes_written));
/* BB what if continued retry is /* BB what if continued retry is
requested via mount flags? */ requested via mount flags? */
...@@ -1387,7 +1521,7 @@ retry: ...@@ -1387,7 +1521,7 @@ retry:
/* BB investigate retry logic on temporary /* BB investigate retry logic on temporary
server crash cases and how recovery works server crash cases and how recovery works
when page marked as error */ when page marked as error */
if(rc) if (rc)
SetPageError(page); SetPageError(page);
kunmap(page); kunmap(page);
unlock_page(page); unlock_page(page);
...@@ -1425,7 +1559,7 @@ retry: ...@@ -1425,7 +1559,7 @@ retry:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static int cifs_writepage(struct page* page) static int cifs_writepage(struct page* page)
#else #else
static int cifs_writepage(struct page* page, struct writeback_control *wbc) static int cifs_writepage(struct page *page, struct writeback_control *wbc)
#endif #endif
{ {
int rc = -EFAULT; int rc = -EFAULT;
...@@ -1473,32 +1607,6 @@ static int cifs_commit_write(struct file *file, struct page *page, ...@@ -1473,32 +1607,6 @@ static int cifs_commit_write(struct file *file, struct page *page,
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (position > inode->i_size) { if (position > inode->i_size) {
i_size_write(inode, position); i_size_write(inode, position);
/* if (file->private_data == NULL) {
rc = -EBADF;
} else {
open_file = (struct cifsFileInfo *)file->private_data;
cifs_sb = CIFS_SB(inode->i_sb);
rc = -EAGAIN;
while (rc == -EAGAIN) {
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
rc = cifs_reopen_file(
file->f_dentry->d_inode, file);
if (rc != 0)
break;
}
if (!open_file->closePend) {
rc = CIFSSMBSetFileSize(xid,
cifs_sb->tcon, position,
open_file->netfid,
open_file->pid, FALSE);
} else {
rc = -EBADF;
break;
}
}
cFYI(1, (" SetEOF (commit write) rc = %d", rc));
} */
} }
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
...@@ -1534,7 +1642,11 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) ...@@ -1534,7 +1642,11 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
{ {
int xid; int xid;
int rc = 0; int rc = 0;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
struct inode *inode = file->f_dentry->d_inode; struct inode *inode = file->f_dentry->d_inode;
#else
struct inode *inode = file->f_path.dentry->d_inode;
#endif
xid = GetXid(); xid = GetXid();
...@@ -1548,7 +1660,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) ...@@ -1548,7 +1660,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
return rc; return rc;
} }
/* static int cifs_sync_page(struct page *page) /* static void cifs_sync_page(struct page *page)
{ {
struct address_space *mapping; struct address_space *mapping;
struct inode *inode; struct inode *inode;
...@@ -1562,16 +1674,18 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) ...@@ -1562,16 +1674,18 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
return 0; return 0;
inode = mapping->host; inode = mapping->host;
if (!inode) if (!inode)
return 0; */ return; */
/* fill in rpages then /* fill in rpages then
result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */ result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index)); /* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
#if 0
if (rc < 0) if (rc < 0)
return rc; return rc;
return 0; return 0;
#endif
} */ } */
/* /*
...@@ -1584,7 +1698,11 @@ int cifs_flush(struct file *file, fl_owner_t id) ...@@ -1584,7 +1698,11 @@ int cifs_flush(struct file *file, fl_owner_t id)
int cifs_flush(struct file *file) int cifs_flush(struct file *file)
#endif /* 2.6.17 */ #endif /* 2.6.17 */
{ {
struct inode * inode = file->f_dentry->d_inode; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
struct inode *inode = file->f_dentry->d_inode;
#else
struct inode *inode = file->f_path.dentry->d_inode;
#endif
int rc = 0; int rc = 0;
/* Rather than do the steps manually: /* Rather than do the steps manually:
...@@ -1600,7 +1718,7 @@ int cifs_flush(struct file *file) ...@@ -1600,7 +1718,7 @@ int cifs_flush(struct file *file)
if (!rc) /* reset wb rc if we were able to write out dirty pages */ if (!rc) /* reset wb rc if we were able to write out dirty pages */
CIFS_I(inode)->write_behind_rc = 0; CIFS_I(inode)->write_behind_rc = 0;
cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc)); cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
return rc; return rc;
} }
...@@ -1621,7 +1739,11 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, ...@@ -1621,7 +1739,11 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
struct smb_com_read_rsp *pSMBr; struct smb_com_read_rsp *pSMBr;
xid = GetXid(); xid = GetXid();
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
#else
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
#endif
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if (file->private_data == NULL) { if (file->private_data == NULL) {
...@@ -1644,8 +1766,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, ...@@ -1644,8 +1766,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
int buf_type = CIFS_NO_BUFFER; int buf_type = CIFS_NO_BUFFER;
if ((open_file->invalidHandle) && if ((open_file->invalidHandle) &&
(!open_file->closePend)) { (!open_file->closePend)) {
rc = cifs_reopen_file(file->f_dentry->d_inode, rc = cifs_reopen_file(file, TRUE);
file, TRUE);
if (rc != 0) if (rc != 0)
break; break;
} }
...@@ -1664,9 +1785,9 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, ...@@ -1664,9 +1785,9 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
rc = -EFAULT; rc = -EFAULT;
} }
if(buf_type == CIFS_SMALL_BUFFER) if (buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(smb_read_data); cifs_small_buf_release(smb_read_data);
else if(buf_type == CIFS_LARGE_BUFFER) else if (buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(smb_read_data); cifs_buf_release(smb_read_data);
smb_read_data = NULL; smb_read_data = NULL;
} }
...@@ -1703,7 +1824,11 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, ...@@ -1703,7 +1824,11 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
int buf_type = CIFS_NO_BUFFER; int buf_type = CIFS_NO_BUFFER;
xid = GetXid(); xid = GetXid();
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
#else
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
#endif
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if (file->private_data == NULL) { if (file->private_data == NULL) {
...@@ -1722,7 +1847,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, ...@@ -1722,7 +1847,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
cifs_sb->rsize); cifs_sb->rsize);
/* For windows me and 9x we do not want to request more /* For windows me and 9x we do not want to request more
than it negotiated since it will refuse the read then */ than it negotiated since it will refuse the read then */
if((pTcon->ses) && if ((pTcon->ses) &&
!(pTcon->ses->capabilities & CAP_LARGE_FILES)) { !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
current_read_size = min_t(const int, current_read_size, current_read_size = min_t(const int, current_read_size,
pTcon->ses->server->maxBuf - 128); pTcon->ses->server->maxBuf - 128);
...@@ -1731,8 +1856,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, ...@@ -1731,8 +1856,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
while (rc == -EAGAIN) { while (rc == -EAGAIN) {
if ((open_file->invalidHandle) && if ((open_file->invalidHandle) &&
(!open_file->closePend)) { (!open_file->closePend)) {
rc = cifs_reopen_file(file->f_dentry->d_inode, rc = cifs_reopen_file(file, TRUE);
file, TRUE);
if (rc != 0) if (rc != 0)
break; break;
} }
...@@ -1760,7 +1884,11 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, ...@@ -1760,7 +1884,11 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
{ {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
struct dentry *dentry = file->f_dentry; struct dentry *dentry = file->f_dentry;
#else
struct dentry *dentry = file->f_path.dentry;
#endif
int rc, xid; int rc, xid;
xid = GetXid(); xid = GetXid();
...@@ -1799,7 +1927,7 @@ static void cifs_copy_cache_pages(struct address_space *mapping, ...@@ -1799,7 +1927,7 @@ static void cifs_copy_cache_pages(struct address_space *mapping,
continue; continue;
} }
target = kmap_atomic(page,KM_USER0); target = kmap_atomic(page, KM_USER0);
if (PAGE_CACHE_SIZE > bytes_read) { if (PAGE_CACHE_SIZE > bytes_read) {
memcpy(target, data, bytes_read); memcpy(target, data, bytes_read);
...@@ -1833,7 +1961,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1833,7 +1961,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
int bytes_read = 0; int bytes_read = 0;
unsigned int read_size,i; unsigned int read_size, i;
char *smb_read_data = NULL; char *smb_read_data = NULL;
struct smb_com_read_rsp *pSMBr; struct smb_com_read_rsp *pSMBr;
struct pagevec lru_pvec; struct pagevec lru_pvec;
...@@ -1846,11 +1974,17 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1846,11 +1974,17 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
return -EBADF; return -EBADF;
} }
open_file = (struct cifsFileInfo *)file->private_data; open_file = (struct cifsFileInfo *)file->private_data;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
#else
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
#endif
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
pagevec_init(&lru_pvec, 0); pagevec_init(&lru_pvec, 0);
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("rpages: num pages %d", num_pages));
#endif
for (i = 0; i < num_pages; ) { for (i = 0; i < num_pages; ) {
unsigned contig_pages; unsigned contig_pages;
struct page *tmp_page; struct page *tmp_page;
...@@ -1866,7 +2000,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1866,7 +2000,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
contig_pages = 0; contig_pages = 0;
expected_index = expected_index =
list_entry(page_list->prev, struct page, lru)->index; list_entry(page_list->prev, struct page, lru)->index;
list_for_each_entry_reverse(tmp_page,page_list,lru) { list_for_each_entry_reverse(tmp_page, page_list, lru) {
if (tmp_page->index == expected_index) { if (tmp_page->index == expected_index) {
contig_pages++; contig_pages++;
expected_index++; expected_index++;
...@@ -1883,13 +2017,15 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1883,13 +2017,15 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
/* Read size needs to be in multiples of one page */ /* Read size needs to be in multiples of one page */
read_size = min_t(const unsigned int, read_size, read_size = min_t(const unsigned int, read_size,
cifs_sb->rsize & PAGE_CACHE_MASK); cifs_sb->rsize & PAGE_CACHE_MASK);
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("rpages: read size 0x%x contiguous pages %d",
read_size, contig_pages));
#endif
rc = -EAGAIN; rc = -EAGAIN;
while (rc == -EAGAIN) { while (rc == -EAGAIN) {
if ((open_file->invalidHandle) && if ((open_file->invalidHandle) &&
(!open_file->closePend)) { (!open_file->closePend)) {
rc = cifs_reopen_file(file->f_dentry->d_inode, rc = cifs_reopen_file(file, TRUE);
file, TRUE);
if (rc != 0) if (rc != 0)
break; break;
} }
...@@ -1900,11 +2036,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1900,11 +2036,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
&bytes_read, &smb_read_data, &bytes_read, &smb_read_data,
&buf_type); &buf_type);
/* BB more RC checks ? */ /* BB more RC checks ? */
if (rc== -EAGAIN) { if (rc == -EAGAIN) {
if (smb_read_data) { if (smb_read_data) {
if(buf_type == CIFS_SMALL_BUFFER) if (buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(smb_read_data); cifs_small_buf_release(smb_read_data);
else if(buf_type == CIFS_LARGE_BUFFER) else if (buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(smb_read_data); cifs_buf_release(smb_read_data);
smb_read_data = NULL; smb_read_data = NULL;
} }
...@@ -1912,13 +2048,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1912,13 +2048,6 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
} }
if ((rc < 0) || (smb_read_data == NULL)) { if ((rc < 0) || (smb_read_data == NULL)) {
cFYI(1, ("Read error in readpages: %d", rc)); cFYI(1, ("Read error in readpages: %d", rc));
/* clean up remaing pages off list */
while (!list_empty(page_list) && (i < num_pages)) {
page = list_entry(page_list->prev, struct page,
lru);
list_del(&page->lru);
page_cache_release(page);
}
break; break;
} else if (bytes_read > 0) { } else if (bytes_read > 0) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19)
...@@ -1940,13 +2069,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1940,13 +2069,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
this case is ok - if we are at server EOF this case is ok - if we are at server EOF
we will hit it on next read */ we will hit it on next read */
/* while (!list_empty(page_list) && (i < num_pages)) { /* break; */
page = list_entry(page_list->prev,
struct page, list);
list_del(&page->list);
page_cache_release(page);
}
break; */
} }
} else { } else {
cFYI(1, ("No bytes read (%d) at offset %lld . " cFYI(1, ("No bytes read (%d) at offset %lld . "
...@@ -1954,20 +2077,12 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1954,20 +2077,12 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
bytes_read, offset)); bytes_read, offset));
/* BB turn off caching and do new lookup on /* BB turn off caching and do new lookup on
file size at server? */ file size at server? */
while (!list_empty(page_list) && (i < num_pages)) {
page = list_entry(page_list->prev, struct page,
lru);
list_del(&page->lru);
/* BB removeme - replace with zero of page? */
page_cache_release(page);
}
break; break;
} }
if (smb_read_data) { if (smb_read_data) {
if(buf_type == CIFS_SMALL_BUFFER) if (buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(smb_read_data); cifs_small_buf_release(smb_read_data);
else if(buf_type == CIFS_LARGE_BUFFER) else if (buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(smb_read_data); cifs_buf_release(smb_read_data);
smb_read_data = NULL; smb_read_data = NULL;
} }
...@@ -1978,9 +2093,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1978,9 +2093,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
/* need to free smb_read_data buf before exit */ /* need to free smb_read_data buf before exit */
if (smb_read_data) { if (smb_read_data) {
if(buf_type == CIFS_SMALL_BUFFER) if (buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(smb_read_data); cifs_small_buf_release(smb_read_data);
else if(buf_type == CIFS_LARGE_BUFFER) else if (buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(smb_read_data); cifs_buf_release(smb_read_data);
smb_read_data = NULL; smb_read_data = NULL;
} }
...@@ -2005,10 +2120,15 @@ static int cifs_readpage_worker(struct file *file, struct page *page, ...@@ -2005,10 +2120,15 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
if (rc < 0) if (rc < 0)
goto io_error; goto io_error;
else else
cFYI(1, ("Bytes read %d",rc)); cFYI(1, ("Bytes read %d", rc));
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
file->f_dentry->d_inode->i_atime = file->f_dentry->d_inode->i_atime =
current_fs_time(file->f_dentry->d_inode->i_sb); current_fs_time(file->f_dentry->d_inode->i_sb);
#else
file->f_path.dentry->d_inode->i_atime =
current_fs_time(file->f_path.dentry->d_inode->i_sb);
#endif
if (PAGE_CACHE_SIZE > rc) if (PAGE_CACHE_SIZE > rc)
memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc); memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
...@@ -2047,6 +2167,25 @@ static int cifs_readpage(struct file *file, struct page *page) ...@@ -2047,6 +2167,25 @@ static int cifs_readpage(struct file *file, struct page *page)
return rc; return rc;
} }
static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
{
struct cifsFileInfo *open_file;
read_lock(&GlobalSMBSeslock);
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
if (open_file->closePend)
continue;
if (open_file->pfile &&
((open_file->pfile->f_flags & O_RDWR) ||
(open_file->pfile->f_flags & O_WRONLY))) {
read_unlock(&GlobalSMBSeslock);
return 1;
}
}
read_unlock(&GlobalSMBSeslock);
return 0;
}
/* We do not want to update the file size from server for inodes /* We do not want to update the file size from server for inodes
open for write - to avoid races with writepage extending open for write - to avoid races with writepage extending
the file - in the future we could consider allowing the file - in the future we could consider allowing
...@@ -2055,18 +2194,13 @@ static int cifs_readpage(struct file *file, struct page *page) ...@@ -2055,18 +2194,13 @@ static int cifs_readpage(struct file *file, struct page *page)
page caching in the current Linux kernel design */ page caching in the current Linux kernel design */
int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file) int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
{ {
struct cifsFileInfo *open_file = NULL; if (!cifsInode)
return 1;
if (cifsInode)
open_file = find_writable_file(cifsInode);
if(open_file) { if (is_inode_writable(cifsInode)) {
/* This inode is open for write at least once */
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
/* there is not actually a write pending so let
this handle go free and allow it to
be closable if needed */
atomic_dec(&open_file->wrtPending);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb); cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
#else #else
...@@ -2078,7 +2212,7 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file) ...@@ -2078,7 +2212,7 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
return 1; return 1;
} }
if(i_size_read(&cifsInode->vfs_inode) < end_of_file) if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
return 1; return 1;
return 0; return 0;
...@@ -2093,7 +2227,7 @@ static int cifs_prepare_write(struct file *file, struct page *page, ...@@ -2093,7 +2227,7 @@ static int cifs_prepare_write(struct file *file, struct page *page,
loff_t i_size; loff_t i_size;
loff_t offset; loff_t offset;
cFYI(1, ("prepare write for page %p from %d to %d",page,from,to)); cFYI(1, ("prepare write for page %p from %d to %d", page, from, to));
if (PageUptodate(page)) if (PageUptodate(page))
return 0; return 0;
......
/* /*
* fs/cifs/inode.c * fs/cifs/inode.c
* *
* Copyright (C) International Business Machines Corp., 2002,2005 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -32,6 +32,23 @@ ...@@ -32,6 +32,23 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
static inline void clear_nlink(struct inode *inode)
{
inode->i_nlink = 0;
}
static inline void drop_nlink(struct inode *inode)
{
inode->i_nlink--;
}
static inline void inc_nlink(struct inode *inode)
{
inode->i_nlink++;
}
#endif
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)
{ {
...@@ -93,7 +110,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -93,7 +110,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
(*pinode)->i_ino = (*pinode)->i_ino =
(unsigned long)findData.UniqueId; (unsigned long)findData.UniqueId;
} /* note ino incremented to unique num in new_inode */ } /* note ino incremented to unique num in new_inode */
if(sb->s_flags & MS_NOATIME) if (sb->s_flags & MS_NOATIME)
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
insert_inode_hash(*pinode); insert_inode_hash(*pinode);
...@@ -106,7 +123,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -106,7 +123,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
cifsInfo->time = jiffies; cifsInfo->time = jiffies;
cFYI(1, ("New time %ld", cifsInfo->time)); cFYI(1, ("New time %ld", cifsInfo->time));
/* this is ok to set on every inode revalidate */ /* this is ok to set on every inode revalidate */
atomic_set(&cifsInfo->inUse,1); atomic_set(&cifsInfo->inUse, 1);
inode->i_atime = inode->i_atime =
cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime)); cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
...@@ -140,10 +157,19 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -140,10 +157,19 @@ int cifs_get_inode_info_unix(struct inode **pinode,
} else { } else {
/* safest to call it a file if we do not know */ /* safest to call it a file if we do not know */
inode->i_mode |= S_IFREG; inode->i_mode |= S_IFREG;
cFYI(1,("unknown type %d",type)); cFYI(1, ("unknown type %d", type));
} }
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
inode->i_uid = cifs_sb->mnt_uid;
else
inode->i_uid = le64_to_cpu(findData.Uid); inode->i_uid = le64_to_cpu(findData.Uid);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
inode->i_gid = cifs_sb->mnt_gid;
else
inode->i_gid = le64_to_cpu(findData.Gid); inode->i_gid = le64_to_cpu(findData.Gid);
inode->i_nlink = le64_to_cpu(findData.Nlinks); inode->i_nlink = le64_to_cpu(findData.Nlinks);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
...@@ -181,18 +207,17 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -181,18 +207,17 @@ int cifs_get_inode_info_unix(struct inode **pinode,
&cifs_file_direct_nobrl_ops; &cifs_file_direct_nobrl_ops;
else else
inode->i_fop = &cifs_file_direct_ops; inode->i_fop = &cifs_file_direct_ops;
} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_nobrl_ops; inode->i_fop = &cifs_file_nobrl_ops;
else /* not direct, send byte range locks */ else /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops; inode->i_fop = &cifs_file_ops;
inode->i_data.a_ops = &cifs_addr_ops;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
/* check if server can support readpages */ /* check if server can support readpages */
if(pTcon->ses->server->maxBuf < if (pTcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops = &cifs_addr_ops_smallbuf; inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
#endif else
inode->i_data.a_ops = &cifs_addr_ops;
} else if (S_ISDIR(inode->i_mode)) { } else if (S_ISDIR(inode->i_mode)) {
cFYI(1, ("Directory inode")); cFYI(1, ("Directory inode"));
inode->i_op = &cifs_dir_inode_ops; inode->i_op = &cifs_dir_inode_ops;
...@@ -210,7 +235,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -210,7 +235,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
return rc; return rc;
} }
static int decode_sfu_inode(struct inode * inode, __u64 size, static int decode_sfu_inode(struct inode *inode, __u64 size,
const unsigned char *path, const unsigned char *path,
struct cifs_sb_info *cifs_sb, int xid) struct cifs_sb_info *cifs_sb, int xid)
{ {
...@@ -220,11 +245,11 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, ...@@ -220,11 +245,11 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
struct cifsTconInfo *pTcon = cifs_sb->tcon; struct cifsTconInfo *pTcon = cifs_sb->tcon;
char buf[24]; char buf[24];
unsigned int bytes_read; unsigned int bytes_read;
char * pbuf; char *pbuf;
pbuf = buf; pbuf = buf;
if(size == 0) { if (size == 0) {
inode->i_mode |= S_IFIFO; inode->i_mode |= S_IFIFO;
return 0; return 0;
} else if (size < 8) { } else if (size < 8) {
...@@ -236,18 +261,18 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, ...@@ -236,18 +261,18 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) { if (rc == 0) {
int buf_type = CIFS_NO_BUFFER; int buf_type = CIFS_NO_BUFFER;
/* Read header */ /* Read header */
rc = CIFSSMBRead(xid, pTcon, rc = CIFSSMBRead(xid, pTcon,
netfid, netfid,
24 /* length */, 0 /* offset */, 24 /* length */, 0 /* offset */,
&bytes_read, &pbuf, &buf_type); &bytes_read, &pbuf, &buf_type);
if((rc == 0) && (bytes_read >= 8)) { if ((rc == 0) && (bytes_read >= 8)) {
if(memcmp("IntxBLK", pbuf, 8) == 0) { if (memcmp("IntxBLK", pbuf, 8) == 0) {
cFYI(1,("Block device")); cFYI(1, ("Block device"));
inode->i_mode |= S_IFBLK; inode->i_mode |= S_IFBLK;
if(bytes_read == 24) { if (bytes_read == 24) {
/* we have enough to decode dev num */ /* we have enough to decode dev num */
__u64 mjr; /* major */ __u64 mjr; /* major */
__u64 mnr; /* minor */ __u64 mnr; /* minor */
...@@ -255,10 +280,10 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, ...@@ -255,10 +280,10 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
inode->i_rdev = MKDEV(mjr, mnr); inode->i_rdev = MKDEV(mjr, mnr);
} }
} else if(memcmp("IntxCHR", pbuf, 8) == 0) { } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
cFYI(1,("Char device")); cFYI(1, ("Char device"));
inode->i_mode |= S_IFCHR; inode->i_mode |= S_IFCHR;
if(bytes_read == 24) { if (bytes_read == 24) {
/* we have enough to decode dev num */ /* we have enough to decode dev num */
__u64 mjr; /* major */ __u64 mjr; /* major */
__u64 mnr; /* minor */ __u64 mnr; /* minor */
...@@ -266,8 +291,8 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, ...@@ -266,8 +291,8 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
inode->i_rdev = MKDEV(mjr, mnr); inode->i_rdev = MKDEV(mjr, mnr);
} }
} else if(memcmp("IntxLNK", pbuf, 7) == 0) { } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
cFYI(1,("Symlink")); cFYI(1, ("Symlink"));
inode->i_mode |= S_IFLNK; inode->i_mode |= S_IFLNK;
} else { } else {
inode->i_mode |= S_IFREG; /* file? */ inode->i_mode |= S_IFREG; /* file? */
...@@ -280,12 +305,11 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, ...@@ -280,12 +305,11 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
CIFSSMBClose(xid, pTcon, netfid); CIFSSMBClose(xid, pTcon, netfid);
} }
return rc; return rc;
} }
#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
static int get_sfu_uid_mode(struct inode * inode, static int get_sfu_uid_mode(struct inode *inode,
const unsigned char *path, const unsigned char *path,
struct cifs_sb_info *cifs_sb, int xid) struct cifs_sb_info *cifs_sb, int xid)
{ {
...@@ -297,14 +321,14 @@ static int get_sfu_uid_mode(struct inode * inode, ...@@ -297,14 +321,14 @@ static int get_sfu_uid_mode(struct inode * inode,
rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
ea_value, 4 /* size of buf */, cifs_sb->local_nls, ea_value, 4 /* size of buf */, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if(rc < 0) if (rc < 0)
return (int)rc; return (int)rc;
else if (rc > 3) { else if (rc > 3) {
mode = le32_to_cpu(*((__le32 *)ea_value)); mode = le32_to_cpu(*((__le32 *)ea_value));
inode->i_mode &= ~SFBITS_MASK; inode->i_mode &= ~SFBITS_MASK;
cFYI(1,("special bits 0%o org mode 0%o", mode, inode->i_mode)); cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode));
inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode; inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode;
cFYI(1,("special mode bits 0%o", mode)); cFYI(1, ("special mode bits 0%o", mode));
return 0; return 0;
} else { } else {
return 0; return 0;
...@@ -312,8 +336,6 @@ static int get_sfu_uid_mode(struct inode * inode, ...@@ -312,8 +336,6 @@ static int get_sfu_uid_mode(struct inode * inode,
#else #else
return -EOPNOTSUPP; return -EOPNOTSUPP;
#endif #endif
} }
int cifs_get_inode_info(struct inode **pinode, int cifs_get_inode_info(struct inode **pinode,
...@@ -329,11 +351,11 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -329,11 +351,11 @@ int cifs_get_inode_info(struct inode **pinode,
int adjustTZ = FALSE; int adjustTZ = 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));
if ((pfindData == NULL) && (*pinode != NULL)) { if ((pfindData == NULL) && (*pinode != NULL)) {
if (CIFS_I(*pinode)->clientCanCacheRead) { if (CIFS_I(*pinode)->clientCanCacheRead) {
cFYI(1,("No need to revalidate cached inode sizes")); cFYI(1, ("No need to revalidate cached inode sizes"));
return rc; return rc;
} }
} }
...@@ -352,14 +374,13 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -352,14 +374,13 @@ int cifs_get_inode_info(struct inode **pinode,
/* BB optimize code so we do not make the above call /* BB optimize code so we do not make the above call
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, search_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);
adjustTZ = TRUE; adjustTZ = TRUE;
} }
} }
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) { if (rc) {
...@@ -414,7 +435,7 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -414,7 +435,7 @@ int cifs_get_inode_info(struct inode **pinode,
there Windows server or network appliances for which there Windows server or network appliances for which
IndexNumber field is not guaranteed unique? */ IndexNumber field is not guaranteed unique? */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
int rc1 = 0; int rc1 = 0;
__u64 inode_num; __u64 inode_num;
...@@ -424,12 +445,12 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -424,12 +445,12 @@ int cifs_get_inode_info(struct inode **pinode,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc1) { if (rc1) {
cFYI(1,("GetSrvInodeNum rc %d", rc1)); cFYI(1, ("GetSrvInodeNum rc %d", rc1));
/* BB EOPNOSUPP disable SERVER_INUM? */ /* BB EOPNOSUPP disable SERVER_INUM? */
} else /* do we need cast or hash to ino? */ } else /* do we need cast or hash to ino? */
(*pinode)->i_ino = inode_num; (*pinode)->i_ino = inode_num;
} /* else ino incremented to unique num in new_inode*/ } /* else ino incremented to unique num in new_inode*/
if(sb->s_flags & MS_NOATIME) if (sb->s_flags & MS_NOATIME)
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME; (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
insert_inode_hash(*pinode); insert_inode_hash(*pinode);
} }
...@@ -446,7 +467,7 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -446,7 +467,7 @@ int cifs_get_inode_info(struct inode **pinode,
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
/* Linux can not store file creation time so ignore it */ /* Linux can not store file creation time so ignore it */
if(pfindData->LastAccessTime) if (pfindData->LastAccessTime)
inode->i_atime = cifs_NTtimeToUnix inode->i_atime = cifs_NTtimeToUnix
(le64_to_cpu(pfindData->LastAccessTime)); (le64_to_cpu(pfindData->LastAccessTime));
else /* do not need to use current_fs_time - time not stored */ else /* do not need to use current_fs_time - time not stored */
...@@ -456,7 +477,7 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -456,7 +477,7 @@ int cifs_get_inode_info(struct inode **pinode,
inode->i_ctime = inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
cFYI(0, ("Attributes came in as 0x%x", attr)); cFYI(0, ("Attributes came in as 0x%x", attr));
if(adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
} }
...@@ -466,7 +487,8 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -466,7 +487,8 @@ int cifs_get_inode_info(struct inode **pinode,
/* new inode, can safely set these fields */ /* new inode, can safely set these fields */
inode->i_mode = cifs_sb->mnt_file_mode; inode->i_mode = cifs_sb->mnt_file_mode;
else /* since we set the inode type below we need to mask off else /* since we set the inode type below we need to mask off
to avoid strange results if type changes and both get orred in */ to avoid strange results if type changes and both
get orred in */
inode->i_mode &= ~S_IFMT; inode->i_mode &= ~S_IFMT;
/* if (attr & ATTR_REPARSE) */ /* if (attr & ATTR_REPARSE) */
/* We no longer handle these as symlinks because we could not /* We no longer handle these as symlinks because we could not
...@@ -489,9 +511,9 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -489,9 +511,9 @@ int cifs_get_inode_info(struct inode **pinode,
le64_to_cpu(pfindData->EndOfFile), le64_to_cpu(pfindData->EndOfFile),
search_path, search_path,
cifs_sb, xid)) { cifs_sb, xid)) {
cFYI(1,("Unrecognized sfu inode type")); cFYI(1, ("Unrecognized sfu inode type"));
} }
cFYI(1,("sfu mode 0%o",inode->i_mode)); cFYI(1, ("sfu mode 0%o", inode->i_mode));
} else { } else {
inode->i_mode |= S_IFREG; inode->i_mode |= S_IFREG;
/* treat the dos attribute of read-only as read-only /* treat the dos attribute of read-only as read-only
...@@ -512,7 +534,7 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -512,7 +534,7 @@ int cifs_get_inode_info(struct inode **pinode,
if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) { if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) {
/* can not safely shrink the file size here if the /* can not safely shrink the file size here if the
client is writing to it due to potential races */ client is writing to it due to potential races */
i_size_write(inode,le64_to_cpu(pfindData->EndOfFile)); i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
/* 512 bytes (2**9) is the fake blocksize that must be /* 512 bytes (2**9) is the fake blocksize that must be
used for this calculation */ used for this calculation */
...@@ -525,15 +547,17 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -525,15 +547,17 @@ int cifs_get_inode_info(struct inode **pinode,
/* BB fill in uid and gid here? with help from winbind? /* BB fill in uid and gid here? with help from winbind?
or retrieve from NTFS stream extended attribute */ or retrieve from NTFS stream extended attribute */
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
/* fill in uid, gid, mode from server ACL */ /* fill in uid, gid, mode from server ACL */
/* BB FIXME this should also take into account the
* default uid specified on mount if present */
get_sfu_uid_mode(inode, search_path, cifs_sb, xid); get_sfu_uid_mode(inode, search_path, cifs_sb, xid);
} else if (atomic_read(&cifsInfo->inUse) == 0) { } else if (atomic_read(&cifsInfo->inUse) == 0) {
inode->i_uid = cifs_sb->mnt_uid; inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid; inode->i_gid = cifs_sb->mnt_gid;
/* set so we do not keep refreshing these fields with /* set so we do not keep refreshing these fields with
bad data after user has changed them in memory */ bad data after user has changed them in memory */
atomic_set(&cifsInfo->inUse,1); atomic_set(&cifsInfo->inUse, 1);
} }
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
...@@ -545,17 +569,16 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -545,17 +569,16 @@ int cifs_get_inode_info(struct inode **pinode,
&cifs_file_direct_nobrl_ops; &cifs_file_direct_nobrl_ops;
else else
inode->i_fop = &cifs_file_direct_ops; inode->i_fop = &cifs_file_direct_ops;
} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_nobrl_ops; inode->i_fop = &cifs_file_nobrl_ops;
else /* not direct, send byte range locks */ else /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops; inode->i_fop = &cifs_file_ops;
inode->i_data.a_ops = &cifs_addr_ops; if (pTcon->ses->server->maxBuf <
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
if(pTcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops = &cifs_addr_ops_smallbuf; inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
#endif else
inode->i_data.a_ops = &cifs_addr_ops;
} else if (S_ISDIR(inode->i_mode)) { } else if (S_ISDIR(inode->i_mode)) {
cFYI(1, ("Directory inode")); cFYI(1, ("Directory inode"));
inode->i_op = &cifs_dir_inode_ops; inode->i_op = &cifs_dir_inode_ops;
...@@ -580,10 +603,11 @@ void cifs_read_inode(struct inode *inode) ...@@ -580,10 +603,11 @@ void cifs_read_inode(struct inode *inode)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
xid = GetXid(); xid = GetXid();
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid); if (cifs_sb->tcon->unix_ext)
cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
else else
cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid); cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid);
/* can not call macro FreeXid here since in a void func */ /* can not call macro FreeXid here since in a void func */
_FreeXid(xid); _FreeXid(xid);
} }
...@@ -602,7 +626,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -602,7 +626,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
xid = GetXid(); xid = GetXid();
if(inode) if (inode)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
else else
cifs_sb = CIFS_SB(direntry->d_sb); cifs_sb = CIFS_SB(direntry->d_sb);
...@@ -610,19 +634,31 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -610,19 +634,31 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
/* Unlink can be called from rename so we can not grab the sem here /* Unlink can be called from rename so we can not grab the sem here
since we deadlock otherwise */ since we deadlock otherwise */
/* down(&direntry->d_sb->s_vfs_rename_sem);*/ /* mutex_lock(&direntry->d_sb->s_vfs_rename_mutex);*/
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
/* up(&direntry->d_sb->s_vfs_rename_sem);*/ /* mutex_unlock(&direntry->d_sb->s_vfs_rename_mutex);*/
if (full_path == NULL) { if (full_path == NULL) {
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
if ((pTcon->ses->capabilities & CAP_UNIX) &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
rc = CIFSPOSIXDelFile(xid, pTcon, full_path,
SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1,("posix del rc %d",rc));
if ((rc == 0) || (rc == -ENOENT))
goto psx_del_no_retry;
}
rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
psx_del_no_retry:
if (!rc) { if (!rc) {
if (direntry->d_inode) if (direntry->d_inode)
direntry->d_inode->i_nlink--; drop_nlink(direntry->d_inode);
} else if (rc == -ENOENT) { } else if (rc == -ENOENT) {
d_drop(direntry); d_drop(direntry);
} else if (rc == -ETXTBSY) { } else if (rc == -ETXTBSY) {
...@@ -634,14 +670,14 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -634,14 +670,14 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
&netfid, &oplock, NULL, cifs_sb->local_nls, &netfid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) { if (rc == 0) {
CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL, CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, pTcon, netfid); CIFSSMBClose(xid, pTcon, netfid);
if (direntry->d_inode) if (direntry->d_inode)
direntry->d_inode->i_nlink--; drop_nlink(direntry->d_inode);
} }
} else if (rc == -EACCES) { } else if (rc == -EACCES) {
/* try only if r/o attribute set in local lookup data? */ /* try only if r/o attribute set in local lookup data? */
...@@ -679,7 +715,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -679,7 +715,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) { if (rc == 0) {
rc = CIFSSMBSetFileTimes(xid, pTcon, rc = CIFSSMBSetFileTimes(xid, pTcon,
pinfo_buf, pinfo_buf,
netfid); netfid);
...@@ -688,14 +724,14 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -688,14 +724,14 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
} }
kfree(pinfo_buf); kfree(pinfo_buf);
} }
if (rc==0) { if (rc == 0) {
rc = CIFSSMBDelFile(xid, pTcon, full_path, rc = CIFSSMBDelFile(xid, pTcon, full_path,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc) { if (!rc) {
if (direntry->d_inode) if (direntry->d_inode)
direntry->d_inode->i_nlink--; drop_nlink(direntry->d_inode);
} else if (rc == -ETXTBSY) { } else if (rc == -ETXTBSY) {
int oplock = FALSE; int oplock = FALSE;
__u16 netfid; __u16 netfid;
...@@ -708,7 +744,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -708,7 +744,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) { if (rc == 0) {
CIFSSMBRenameOpenFile(xid, pTcon, CIFSSMBRenameOpenFile(xid, pTcon,
netfid, NULL, netfid, NULL,
cifs_sb->local_nls, cifs_sb->local_nls,
...@@ -716,7 +752,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -716,7 +752,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, pTcon, netfid); CIFSSMBClose(xid, pTcon, netfid);
if (direntry->d_inode) if (direntry->d_inode)
direntry->d_inode->i_nlink--; drop_nlink(direntry->d_inode);
} }
/* BB if rc = -ETXTBUSY goto the rename logic BB */ /* BB if rc = -ETXTBUSY goto the rename logic BB */
} }
...@@ -728,7 +764,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -728,7 +764,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
when needed */ when needed */
direntry->d_inode->i_ctime = current_fs_time(inode->i_sb); direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
} }
if(inode) { if (inode) {
inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
cifsInode = CIFS_I(inode); cifsInode = CIFS_I(inode);
cifsInode->time = 0; /* force revalidate of dir as well */ cifsInode->time = 0; /* force revalidate of dir as well */
...@@ -739,6 +775,137 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -739,6 +775,137 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
return rc; return rc;
} }
static void posix_fill_in_inode(struct inode *tmp_inode,
FILE_UNIX_BASIC_INFO *pData, int *pobject_type, int isNewInode)
{
loff_t local_size;
struct timespec local_mtime;
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
__u32 type = le32_to_cpu(pData->Type);
__u64 num_of_bytes = le64_to_cpu(pData->NumOfBytes);
__u64 end_of_file = le64_to_cpu(pData->EndOfFile);
cifsInfo->time = jiffies;
atomic_inc(&cifsInfo->inUse);
/* save mtime and size */
local_mtime = tmp_inode->i_mtime;
local_size = tmp_inode->i_size;
tmp_inode->i_atime =
cifs_NTtimeToUnix(le64_to_cpu(pData->LastAccessTime));
tmp_inode->i_mtime =
cifs_NTtimeToUnix(le64_to_cpu(pData->LastModificationTime));
tmp_inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pData->LastStatusChange));
tmp_inode->i_mode = le64_to_cpu(pData->Permissions);
/* since we set the inode type below we need to mask off type
to avoid strange results if bits above were corrupt */
tmp_inode->i_mode &= ~S_IFMT;
if (type == UNIX_FILE) {
*pobject_type = DT_REG;
tmp_inode->i_mode |= S_IFREG;
} else if (type == UNIX_SYMLINK) {
*pobject_type = DT_LNK;
tmp_inode->i_mode |= S_IFLNK;
} else if (type == UNIX_DIR) {
*pobject_type = DT_DIR;
tmp_inode->i_mode |= S_IFDIR;
} else if (type == UNIX_CHARDEV) {
*pobject_type = DT_CHR;
tmp_inode->i_mode |= S_IFCHR;
tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
le64_to_cpu(pData->DevMinor) & MINORMASK);
} else if (type == UNIX_BLOCKDEV) {
*pobject_type = DT_BLK;
tmp_inode->i_mode |= S_IFBLK;
tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
le64_to_cpu(pData->DevMinor) & MINORMASK);
} else if (type == UNIX_FIFO) {
*pobject_type = DT_FIFO;
tmp_inode->i_mode |= S_IFIFO;
} else if (type == UNIX_SOCKET) {
*pobject_type = DT_SOCK;
tmp_inode->i_mode |= S_IFSOCK;
} else {
/* safest to just call it a file */
*pobject_type = DT_REG;
tmp_inode->i_mode |= S_IFREG;
cFYI(1, ("unknown inode type %d", type));
}
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("object type: %d", type));
#endif
tmp_inode->i_uid = le64_to_cpu(pData->Uid);
tmp_inode->i_gid = le64_to_cpu(pData->Gid);
tmp_inode->i_nlink = le64_to_cpu(pData->Nlinks);
spin_lock(&tmp_inode->i_lock);
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
/* can not safely change the file size here if the
client is writing to it due to potential races */
i_size_write(tmp_inode, end_of_file);
/* 512 bytes (2**9) is the fake blocksize that must be used */
/* for this calculation, not the real blocksize */
tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
}
spin_unlock(&tmp_inode->i_lock);
if (S_ISREG(tmp_inode->i_mode)) {
cFYI(1, ("File inode"));
tmp_inode->i_op = &cifs_file_inode_ops;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
else
tmp_inode->i_fop = &cifs_file_direct_ops;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_nobrl_ops;
else
tmp_inode->i_fop = &cifs_file_ops;
if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
tmp_inode->i_data.a_ops = &cifs_addr_ops;
if (isNewInode)
return; /* No sense invalidating pages for new inode
since we we have not started caching
readahead file data yet */
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
(local_size == tmp_inode->i_size)) {
cFYI(1, ("inode exists but unchanged"));
} else {
/* file may have changed on server */
cFYI(1, ("invalidate inode, readdir detected change"));
invalidate_remote_inode(tmp_inode);
}
} else if (S_ISDIR(tmp_inode->i_mode)) {
cFYI(1, ("Directory inode"));
tmp_inode->i_op = &cifs_dir_inode_ops;
tmp_inode->i_fop = &cifs_dir_ops;
} else if (S_ISLNK(tmp_inode->i_mode)) {
cFYI(1, ("Symbolic Link inode"));
tmp_inode->i_op = &cifs_symlink_inode_ops;
/* tmp_inode->i_fop = *//* do not need to set to anything */
} else {
cFYI(1, ("Special inode"));
init_special_inode(tmp_inode, tmp_inode->i_mode,
tmp_inode->i_rdev);
}
}
int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
{ {
int rc = 0; int rc = 0;
...@@ -760,6 +927,80 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -760,6 +927,80 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
if ((pTcon->ses->capabilities & CAP_UNIX) &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
u32 oplock = 0;
FILE_UNIX_BASIC_INFO * pInfo =
kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
if (pInfo == NULL) {
rc = -ENOMEM;
goto mkdir_out;
}
mode &= ~current->fs->umask;
rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
mode, NULL /* netfid */, pInfo, &oplock,
full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc == -EOPNOTSUPP) {
kfree(pInfo);
goto mkdir_retry_old;
} else if (rc) {
cFYI(1, ("posix mkdir returned 0x%x", rc));
d_drop(direntry);
} else {
int obj_type;
if (pInfo->Type == -1) /* no return info - go query */ {
kfree(pInfo);
goto mkdir_get_info;
}
/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
to set uid/gid */
inc_nlink(inode);
if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops;
else
direntry->d_op = &cifs_dentry_ops;
newinode = new_inode(inode->i_sb);
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
frame was long enough */
posix_fill_in_inode(direntry->d_inode,
pInfo, &obj_type, 1 /* NewInode */);
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("instantiated dentry %p %s to inode %p",
direntry, direntry->d_name.name, newinode));
if (newinode->i_nlink != 2)
cFYI(1, ("unexpected number of links %d",
newinode->i_nlink));
#endif
}
kfree(pInfo);
goto mkdir_out;
}
mkdir_retry_old:
/* BB add setting the equivalent of mode via CreateX w/ACLs */ /* BB add setting the equivalent of mode via CreateX w/ACLs */
rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
...@@ -767,22 +1008,26 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -767,22 +1008,26 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
cFYI(1, ("cifs_mkdir returned 0x%x", rc)); cFYI(1, ("cifs_mkdir returned 0x%x", rc));
d_drop(direntry); d_drop(direntry);
} else { } else {
inode->i_nlink++; mkdir_get_info:
if (pTcon->ses->capabilities & CAP_UNIX) inc_nlink(inode);
if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path, rc = cifs_get_inode_info_unix(&newinode, full_path,
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);
if (pTcon->nocase) if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops; direntry->d_op = &cifs_ci_dentry_ops;
else else
direntry->d_op = &cifs_dentry_ops; direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode); d_instantiate(direntry, newinode);
if (direntry->d_inode) /* setting nlink not necessary except in cases where we
* failed to get it from the server or was set bogus */
if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
direntry->d_inode->i_nlink = 2; direntry->d_inode->i_nlink = 2;
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext) {
mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, CIFSSMBUnixSetPerms(xid, pTcon, full_path,
mode, mode,
...@@ -800,14 +1045,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -800,14 +1045,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
else { } else {
/* BB to be implemented via Windows secrty descriptors /* BB to be implemented via Windows secrty descriptors
eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
-1, -1, local_nls); */ -1, -1, local_nls); */
if(direntry->d_inode) { if (direntry->d_inode) {
direntry->d_inode->i_mode = mode; direntry->d_inode->i_mode = mode;
direntry->d_inode->i_mode |= S_IFDIR; direntry->d_inode->i_mode |= S_IFDIR;
if(cifs_sb->mnt_cifs_flags & if (cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_SET_UID) { CIFS_MOUNT_SET_UID) {
direntry->d_inode->i_uid = direntry->d_inode->i_uid =
current->fsuid; current->fsuid;
...@@ -817,6 +1062,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -817,6 +1062,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
} }
} }
} }
mkdir_out:
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
return rc; return rc;
...@@ -848,10 +1094,10 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) ...@@ -848,10 +1094,10 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc) { if (!rc) {
inode->i_nlink--; drop_nlink(inode);
spin_lock(&direntry->d_inode->i_lock); spin_lock(&direntry->d_inode->i_lock);
i_size_write(direntry->d_inode,0); i_size_write(direntry->d_inode, 0);
direntry->d_inode->i_nlink = 0; clear_nlink(direntry->d_inode);
spin_unlock(&direntry->d_inode->i_lock); spin_unlock(&direntry->d_inode->i_lock);
} }
...@@ -913,7 +1159,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, ...@@ -913,7 +1159,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
if (info_buf_source != NULL) { if (info_buf_source != NULL) {
info_buf_target = info_buf_source + 1; info_buf_target = info_buf_source + 1;
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
info_buf_source, info_buf_source,
cifs_sb_source->local_nls, cifs_sb_source->local_nls,
...@@ -968,7 +1214,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, ...@@ -968,7 +1214,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
cifs_sb_source->local_nls, cifs_sb_source->local_nls,
cifs_sb_source->mnt_cifs_flags & cifs_sb_source->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) { if (rc == 0) {
rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName, rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
cifs_sb_source->local_nls, cifs_sb_source->local_nls,
cifs_sb_source->mnt_cifs_flags & cifs_sb_source->mnt_cifs_flags &
...@@ -1045,9 +1291,9 @@ int cifs_revalidate(struct dentry *direntry) ...@@ -1045,9 +1291,9 @@ int cifs_revalidate(struct dentry *direntry)
local_mtime = direntry->d_inode->i_mtime; local_mtime = direntry->d_inode->i_mtime;
local_size = direntry->d_inode->i_size; local_size = direntry->d_inode->i_size;
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { if (cifs_sb->tcon->unix_ext) {
rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path, rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
direntry->d_sb,xid); direntry->d_sb, xid);
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)
...@@ -1056,7 +1302,7 @@ int cifs_revalidate(struct dentry *direntry) ...@@ -1056,7 +1302,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);
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)
...@@ -1069,7 +1315,7 @@ int cifs_revalidate(struct dentry *direntry) ...@@ -1069,7 +1315,7 @@ int cifs_revalidate(struct dentry *direntry)
/* if not oplocked, we invalidate inode pages if mtime or file size /* if not oplocked, we invalidate inode pages if mtime or file size
had changed on server */ had changed on server */
if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && if (timespec_equal(&local_mtime, &direntry->d_inode->i_mtime) &&
(local_size == direntry->d_inode->i_size)) { (local_size == direntry->d_inode->i_size)) {
cFYI(1, ("cifs_revalidate - inode unchanged")); cFYI(1, ("cifs_revalidate - inode unchanged"));
} else { } else {
...@@ -1096,7 +1342,7 @@ int cifs_revalidate(struct dentry *direntry) ...@@ -1096,7 +1342,7 @@ int cifs_revalidate(struct dentry *direntry)
if (invalidate_inode) { if (invalidate_inode) {
/* shrink_dcache not necessary now that cifs dentry ops /* shrink_dcache not necessary now that cifs dentry ops
are exported for negative dentries */ are exported for negative dentries */
/* if(S_ISDIR(direntry->d_inode->i_mode)) /* if (S_ISDIR(direntry->d_inode->i_mode))
shrink_dcache_parent(direntry); */ shrink_dcache_parent(direntry); */
if (S_ISREG(direntry->d_inode->i_mode)) { if (S_ISREG(direntry->d_inode->i_mode)) {
if (direntry->d_inode->i_mapping) if (direntry->d_inode->i_mapping)
...@@ -1155,7 +1401,7 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from) ...@@ -1155,7 +1401,7 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
return rc; return rc;
} }
static int cifs_vmtruncate(struct inode * inode, loff_t offset) static int cifs_vmtruncate(struct inode *inode, loff_t offset)
{ {
struct address_space *mapping = inode->i_mapping; struct address_space *mapping = inode->i_mapping;
unsigned long limit; unsigned long limit;
...@@ -1173,12 +1419,25 @@ static int cifs_vmtruncate(struct inode * inode, loff_t offset) ...@@ -1173,12 +1419,25 @@ static int cifs_vmtruncate(struct inode * inode, loff_t offset)
} }
i_size_write(inode, offset); i_size_write(inode, offset);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
/*
* unmap_mapping_range is called twice, first simply for efficiency
* so that truncate_inode_pages does fewer single-page unmaps. However
* after this first call, and before truncate_inode_pages finishes,
* it is possible for private pages to be COWed, which remain after
* truncate_inode_pages finishes, hence the second unmap_mapping_range
* call must be made for correctness.
*/
unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
truncate_inode_pages(mapping, offset); truncate_inode_pages(mapping, offset);
unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
goto out_truncate; goto out_truncate;
do_expand: do_expand:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
#else
limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
#endif
if (limit != RLIM_INFINITY && offset > limit) { if (limit != RLIM_INFINITY && offset > limit) {
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
goto out_sig; goto out_sig;
...@@ -1228,7 +1487,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1228,7 +1487,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
/* check if we have permission to change attrs */ /* check if we have permission to change attrs */
rc = inode_change_ok(direntry->d_inode, attrs); rc = inode_change_ok(direntry->d_inode, attrs);
if(rc < 0) { if (rc < 0) {
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} else } else
...@@ -1268,14 +1527,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1268,14 +1527,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
nfid, npid, FALSE); nfid, npid, FALSE);
atomic_dec(&open_file->wrtPending); atomic_dec(&open_file->wrtPending);
cFYI(1,("SetFSize for attrs rc = %d", rc)); cFYI(1, ("SetFSize for attrs rc = %d", rc));
if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
int bytes_written; unsigned int bytes_written;
rc = CIFSSMBWrite(xid, pTcon, rc = CIFSSMBWrite(xid, pTcon,
nfid, 0, attrs->ia_size, nfid, 0, attrs->ia_size,
&bytes_written, NULL, NULL, &bytes_written, NULL, NULL,
1 /* 45 seconds */); 1 /* 45 seconds */);
cFYI(1,("Wrt seteof rc %d", rc)); cFYI(1, ("Wrt seteof rc %d", rc));
} }
} else } else
rc = -EINVAL; rc = -EINVAL;
...@@ -1291,7 +1550,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1291,7 +1550,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
__u16 netfid; __u16 netfid;
int oplock = FALSE; int oplock = FALSE;
...@@ -1302,14 +1561,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1302,14 +1561,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
NULL, cifs_sb->local_nls, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) { if (rc == 0) {
int bytes_written; unsigned int bytes_written;
rc = CIFSSMBWrite(xid, pTcon, rc = CIFSSMBWrite(xid, pTcon,
netfid, 0, netfid, 0,
attrs->ia_size, attrs->ia_size,
&bytes_written, NULL, &bytes_written, NULL,
NULL, 1 /* 45 sec */); NULL, 1 /* 45 sec */);
cFYI(1,("wrt seteof rc %d",rc)); cFYI(1, ("wrt seteof rc %d", rc));
CIFSSMBClose(xid, pTcon, netfid); CIFSSMBClose(xid, pTcon, netfid);
} }
...@@ -1344,7 +1603,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1344,7 +1603,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
mode = attrs->ia_mode; mode = attrs->ia_mode;
} }
if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) if ((pTcon->unix_ext)
&& (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
0 /* dev_t */, cifs_sb->local_nls, 0 /* dev_t */, cifs_sb->local_nls,
...@@ -1359,17 +1618,17 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1359,17 +1618,17 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
cpu_to_le32(cifsInode->cifsAttrs | cpu_to_le32(cifsInode->cifsAttrs |
ATTR_READONLY); ATTR_READONLY);
} }
} else if ((mode & S_IWUGO) == S_IWUGO) { } else if (cifsInode->cifsAttrs & ATTR_READONLY) {
if (cifsInode->cifsAttrs & ATTR_READONLY) { /* If file is readonly on server, we would
not be able to write to it - so if any write
bit is enabled for user or group or other we
need to at least try to remove r/o dos attr */
set_dosattr = TRUE; set_dosattr = TRUE;
time_buf.Attributes = time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
cpu_to_le32(cifsInode->cifsAttrs &
(~ATTR_READONLY)); (~ATTR_READONLY));
/* Windows ignores set to zero */ /* Windows ignores set to zero */
if(time_buf.Attributes == 0) if (time_buf.Attributes == 0)
time_buf.Attributes |= time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
cpu_to_le32(ATTR_NORMAL);
}
} }
/* BB to be implemented - /* BB to be implemented -
via Windows security descriptors or streams */ via Windows security descriptors or streams */
...@@ -1433,7 +1692,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1433,7 +1692,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
NULL, cifs_sb->local_nls, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc==0) { if (rc == 0) {
rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf, rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
netfid); netfid);
CIFSSMBClose(xid, pTcon, netfid); CIFSSMBClose(xid, pTcon, netfid);
...@@ -1451,7 +1710,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1451,7 +1710,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
and this check ensures that we are not being called from and this check ensures that we are not being called from
sys_utimes in which case we ought to fail the call back to sys_utimes in which case we ought to fail the call back to
the user when the server rejects the call */ the user when the server rejects the call */
if((rc) && (attrs->ia_valid & if ((rc) && (attrs->ia_valid &
(ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
rc = 0; rc = 0;
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* vfs operations that deal with io control * vfs operations that deal with io control
* *
* Copyright (C) International Business Machines Corp., 2005 * Copyright (C) International Business Machines Corp., 2005,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
*/ */
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ext2_fs.h>
#include "cifspdu.h" #include "cifspdu.h"
#include "cifsglob.h" #include "cifsglob.h"
#include "cifsproto.h" #include "cifsproto.h"
...@@ -30,8 +29,17 @@ ...@@ -30,8 +29,17 @@
#include "cifsfs.h" #include "cifsfs.h"
#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2) #define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
#ifndef FS_IOC_GETFLAGS
#define FS_IOC_GETFLAGS _IOR('f', 1, long)
#endif
#ifndef FS_IOC_SETFLAGS
#define FS_IOC_SETFLAGS _IOW('f', 2, long)
#endif
#ifndef FS_FL_USER_VISIBLE
#define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
#endif
int cifs_ioctl (struct inode * inode, struct file * filep, int cifs_ioctl (struct inode *inode, struct file *filep,
unsigned int command, unsigned long arg) unsigned int command, unsigned long arg)
{ {
int rc = -ENOTTY; /* strange error - but the precedent */ int rc = -ENOTTY; /* strange error - but the precedent */
...@@ -48,13 +56,13 @@ int cifs_ioctl (struct inode * inode, struct file * filep, ...@@ -48,13 +56,13 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
xid = GetXid(); xid = GetXid();
cFYI(1,("ioctl file %p cmd %u arg %lu",filep,command,arg)); cFYI(1, ("ioctl file %p cmd %u arg %lu", filep, command, arg));
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
tcon = cifs_sb->tcon; tcon = cifs_sb->tcon;
if(tcon) if (tcon)
caps = le64_to_cpu(tcon->fsUnixInfo.Capability); caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
else { else {
rc = -EIO; rc = -EIO;
...@@ -63,33 +71,33 @@ int cifs_ioctl (struct inode * inode, struct file * filep, ...@@ -63,33 +71,33 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
} }
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
switch(command) { switch (command) {
case CIFS_IOC_CHECKUMOUNT: case CIFS_IOC_CHECKUMOUNT:
cFYI(1,("User unmount attempted")); cFYI(1, ("User unmount attempted"));
if(cifs_sb->mnt_uid == current->uid) if (cifs_sb->mnt_uid == current->uid)
rc = 0; rc = 0;
else { else {
rc = -EACCES; rc = -EACCES;
cFYI(1,("uids do not match")); cFYI(1, ("uids do not match"));
} }
break; break;
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
case EXT2_IOC_GETFLAGS: case FS_IOC_GETFLAGS:
if(CIFS_UNIX_EXTATTR_CAP & caps) { if (CIFS_UNIX_EXTATTR_CAP & caps) {
if (pSMBFile == NULL) if (pSMBFile == NULL)
break; break;
rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid, rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
&ExtAttrBits, &ExtAttrMask); &ExtAttrBits, &ExtAttrMask);
if(rc == 0) if (rc == 0)
rc = put_user(ExtAttrBits & rc = put_user(ExtAttrBits &
EXT2_FL_USER_VISIBLE, FS_FL_USER_VISIBLE,
(int __user *)arg); (int __user *)arg);
} }
break; break;
case EXT2_IOC_SETFLAGS: case FS_IOC_SETFLAGS:
if(CIFS_UNIX_EXTATTR_CAP & caps) { if (CIFS_UNIX_EXTATTR_CAP & caps) {
if(get_user(ExtAttrBits,(int __user *)arg)) { if (get_user(ExtAttrBits, (int __user *)arg)) {
rc = -EFAULT; rc = -EFAULT;
break; break;
} }
...@@ -97,13 +105,12 @@ int cifs_ioctl (struct inode * inode, struct file * filep, ...@@ -97,13 +105,12 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
break; break;
/* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid, /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
extAttrBits, &ExtAttrMask);*/ extAttrBits, &ExtAttrMask);*/
} }
cFYI(1,("set flags not implemented yet")); cFYI(1, ("set flags not implemented yet"));
break; break;
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
default: default:
cFYI(1,("unsupported ioctl")); cFYI(1, ("unsupported ioctl"));
break; break;
} }
......
...@@ -53,12 +53,13 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, ...@@ -53,12 +53,13 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
fromName = build_path_from_dentry(old_file); fromName = build_path_from_dentry(old_file);
toName = build_path_from_dentry(direntry); toName = build_path_from_dentry(direntry);
if((fromName == NULL) || (toName == NULL)) { if ((fromName == NULL) || (toName == NULL)) {
rc = -ENOMEM; rc = -ENOMEM;
goto cifs_hl_exit; goto cifs_hl_exit;
} }
if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX) /* if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/
if (pTcon->unix_ext)
rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
cifs_sb_target->local_nls, cifs_sb_target->local_nls,
cifs_sb_target->mnt_cifs_flags & cifs_sb_target->mnt_cifs_flags &
...@@ -68,7 +69,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, ...@@ -68,7 +69,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
cifs_sb_target->local_nls, cifs_sb_target->local_nls,
cifs_sb_target->mnt_cifs_flags & cifs_sb_target->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if((rc == -EIO) || (rc == -EINVAL)) if ((rc == -EIO) || (rc == -EINVAL))
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
} }
...@@ -76,9 +77,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, ...@@ -76,9 +77,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
/* if source file is cached (oplocked) revalidate will not go to server /* if source file is cached (oplocked) revalidate will not go to server
until the file is closed or oplock broken so update nlinks locally */ until the file is closed or oplock broken so update nlinks locally */
if(old_file->d_inode) { if (old_file->d_inode) {
cifsInode = CIFS_I(old_file->d_inode); cifsInode = CIFS_I(old_file->d_inode);
if(rc == 0) { if (rc == 0) {
old_file->d_inode->i_nlink++; old_file->d_inode->i_nlink++;
/* BB should we make this contingent on superblock flag NOATIME? */ /* BB should we make this contingent on superblock flag NOATIME? */
/* old_file->d_inode->i_ctime = CURRENT_TIME;*/ /* old_file->d_inode->i_ctime = CURRENT_TIME;*/
...@@ -116,7 +117,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -116,7 +117,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
int rc = -EACCES; int rc = -EACCES;
int xid; int xid;
char *full_path = NULL; char *full_path = NULL;
char * target_path = ERR_PTR(-ENOMEM); char *target_path = ERR_PTR(-ENOMEM);
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
...@@ -136,13 +137,19 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -136,13 +137,19 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
goto out; goto out;
} }
/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ /* We could change this to:
if (pTcon->unix_ext)
but there does not seem any point in refusing to
get symlink info if we can, even if unix extensions
turned off for this mount */
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
target_path, target_path,
PATH_MAX-1, PATH_MAX-1,
cifs_sb->local_nls); cifs_sb->local_nls);
else { else {
/* BB add read reparse point symlink code here */
/* rc = CIFSSMBQueryReparseLinkInfo */ /* rc = CIFSSMBQueryReparseLinkInfo */
/* BB Add code to Query ReparsePoint info */ /* BB Add code to Query ReparsePoint info */
/* BB Add MAC style xsymlink check here if enabled */ /* BB Add MAC style xsymlink check here if enabled */
...@@ -192,7 +199,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) ...@@ -192,7 +199,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if(full_path == NULL) { if (full_path == NULL) {
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
...@@ -201,19 +208,20 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) ...@@ -201,19 +208,20 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
cFYI(1, ("symname is %s", symname)); cFYI(1, ("symname is %s", symname));
/* BB what if DFS and this volume is on different share? BB */ /* BB what if DFS and this volume is on different share? BB */
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
cifs_sb->local_nls); cifs_sb->local_nls);
/* else /* else
rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */ rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
cifs_sb_target->local_nls); */
if (rc == 0) { if (rc == 0) {
if (pTcon->ses->capabilities & CAP_UNIX) if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path, rc = cifs_get_inode_info_unix(&newinode, full_path,
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);
if (rc != 0) { if (rc != 0) {
cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d", cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
...@@ -243,9 +251,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) ...@@ -243,9 +251,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
char *full_path = NULL; char *full_path = NULL;
char *tmp_path = NULL; char *tmp_path = NULL;
char * tmpbuffer; char *tmpbuffer;
unsigned char * referrals = NULL; unsigned char *referrals = NULL;
int num_referrals = 0; unsigned int num_referrals = 0;
int len; int len;
__u16 fid; __u16 fid;
...@@ -255,11 +263,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) ...@@ -255,11 +263,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
/* BB would it be safe against deadlock to grab this sem /* BB would it be safe against deadlock to grab this sem
even though rename itself grabs the sem and calls lookup? */ even though rename itself grabs the sem and calls lookup? */
/* down(&inode->i_sb->s_vfs_rename_sem);*/ /* mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
/* up(&inode->i_sb->s_vfs_rename_sem);*/ /* mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/
if(full_path == NULL) { if (full_path == NULL) {
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
...@@ -267,70 +275,80 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) ...@@ -267,70 +275,80 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
cFYI(1, cFYI(1,
("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d", ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
full_path, inode, pBuffer, buflen)); full_path, inode, pBuffer, buflen));
if(buflen > PATH_MAX) if (buflen > PATH_MAX)
len = PATH_MAX; len = PATH_MAX;
else else
len = buflen; len = buflen;
tmpbuffer = kmalloc(len,GFP_KERNEL); tmpbuffer = kmalloc(len, GFP_KERNEL);
if(tmpbuffer == NULL) { if (tmpbuffer == NULL) {
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ /* BB add read reparse point symlink code and
Unix extensions symlink code here BB */
/* We could disable this based on pTcon->unix_ext flag instead ... but why? */
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
tmpbuffer, tmpbuffer,
len - 1, len - 1,
cifs_sb->local_nls); cifs_sb->local_nls);
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
cERROR(1,("SFU style symlinks not implemented yet")); cERROR(1, ("SFU style symlinks not implemented yet"));
/* add open and read as in fs/cifs/inode.c */ /* add open and read as in fs/cifs/inode.c */
} else { } else {
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
OPEN_REPARSE_POINT,&fid, &oplock, NULL, OPEN_REPARSE_POINT, &fid, &oplock, NULL,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if(!rc) { if (!rc) {
rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
tmpbuffer, tmpbuffer,
len - 1, len - 1,
fid, fid,
cifs_sb->local_nls); cifs_sb->local_nls);
if(CIFSSMBClose(xid, pTcon, fid)) { if (CIFSSMBClose(xid, pTcon, fid)) {
cFYI(1,("Error closing junction point (open for ioctl)")); cFYI(1, ("Error closing junction point "
"(open for ioctl)"));
} }
if(rc == -EIO) { if (rc == -EIO) {
/* Query if DFS Junction */ /* Query if DFS Junction */
tmp_path = tmp_path =
kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1, kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
GFP_KERNEL); GFP_KERNEL);
if (tmp_path) { if (tmp_path) {
strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); strncpy(tmp_path, pTcon->treeName,
strncat(tmp_path, full_path, MAX_PATHCONF); MAX_TREE_SIZE);
rc = get_dfs_path(xid, pTcon->ses, tmp_path, strncat(tmp_path, full_path,
MAX_PATHCONF);
rc = get_dfs_path(xid, pTcon->ses,
tmp_path,
cifs_sb->local_nls, cifs_sb->local_nls,
&num_referrals, &referrals, &num_referrals, &referrals,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc)); cFYI(1, ("Get DFS for %s rc = %d ",
if((num_referrals == 0) && (rc == 0)) tmp_path, rc));
if ((num_referrals == 0) && (rc == 0))
rc = -EACCES; rc = -EACCES;
else { else {
cFYI(1,("num referral: %d",num_referrals)); cFYI(1, ("num referral: %d",
if(referrals) { num_referrals));
cFYI(1,("referral string: %s",referrals)); if (referrals) {
strncpy(tmpbuffer, referrals, len-1); cFYI(1,("referral string: %s", referrals));
strncpy(tmpbuffer,
referrals,
len-1);
} }
} }
kfree(referrals); kfree(referrals);
kfree(tmp_path); kfree(tmp_path);
} }
/* BB add code like else decode referrals then memcpy to /* BB add code like else decode referrals
tmpbuffer and free referrals string array BB */ then memcpy to tmpbuffer and free referrals
string array BB */
} }
} }
} }
......
...@@ -170,7 +170,7 @@ mdfour(unsigned char *out, unsigned char *in, int n) ...@@ -170,7 +170,7 @@ mdfour(unsigned char *out, unsigned char *in, int n)
while (n > 64) { while (n > 64) {
copy64(M, in); copy64(M, in);
mdfour64(M,&A,&B, &C, &D); mdfour64(M, &A, &B, &C, &D);
in += 64; in += 64;
n -= 64; n -= 64;
} }
......
...@@ -252,10 +252,11 @@ MD5Transform(__u32 buf[4], __u32 const in[16]) ...@@ -252,10 +252,11 @@ MD5Transform(__u32 buf[4], __u32 const in[16])
buf[3] += d; buf[3] += d;
} }
#if 0 /* currently unused */
/*********************************************************************** /***********************************************************************
the rfc 2104 version of hmac_md5 initialisation. the rfc 2104 version of hmac_md5 initialisation.
***********************************************************************/ ***********************************************************************/
void static void
hmac_md5_init_rfc2104(unsigned char *key, int key_len, hmac_md5_init_rfc2104(unsigned char *key, int key_len,
struct HMACMD5Context *ctx) struct HMACMD5Context *ctx)
{ {
...@@ -289,6 +290,7 @@ hmac_md5_init_rfc2104(unsigned char *key, int key_len, ...@@ -289,6 +290,7 @@ hmac_md5_init_rfc2104(unsigned char *key, int key_len,
MD5Init(&ctx->ctx); MD5Init(&ctx->ctx);
MD5Update(&ctx->ctx, ctx->k_ipad, 64); MD5Update(&ctx->ctx, ctx->k_ipad, 64);
} }
#endif
/*********************************************************************** /***********************************************************************
the microsoft version of hmac_md5 initialisation. the microsoft version of hmac_md5 initialisation.
...@@ -350,7 +352,8 @@ hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) ...@@ -350,7 +352,8 @@ hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx)
single function to calculate an HMAC MD5 digest from data. single function to calculate an HMAC MD5 digest from data.
use the microsoft hmacmd5 init method because the key is 16 bytes. use the microsoft hmacmd5 init method because the key is 16 bytes.
************************************************************/ ************************************************************/
void #if 0 /* currently unused */
static void
hmac_md5(unsigned char key[16], unsigned char *data, int data_len, hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
unsigned char *digest) unsigned char *digest)
{ {
...@@ -361,3 +364,4 @@ hmac_md5(unsigned char key[16], unsigned char *data, int data_len, ...@@ -361,3 +364,4 @@ hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
} }
hmac_md5_final(digest, &ctx); hmac_md5_final(digest, &ctx);
} }
#endif
...@@ -27,12 +27,12 @@ void MD5Final(unsigned char digest[16], struct MD5Context *context); ...@@ -27,12 +27,12 @@ void MD5Final(unsigned char digest[16], struct MD5Context *context);
/* The following definitions come from lib/hmacmd5.c */ /* The following definitions come from lib/hmacmd5.c */
void hmac_md5_init_rfc2104(unsigned char *key, int key_len, /* void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
struct HMACMD5Context *ctx); struct HMACMD5Context *ctx);*/
void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
struct HMACMD5Context *ctx); struct HMACMD5Context *ctx);
void hmac_md5_update(const unsigned char *text, int text_len, void hmac_md5_update(const unsigned char *text, int text_len,
struct HMACMD5Context *ctx); struct HMACMD5Context *ctx);
void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx); void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx);
void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, /* void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
unsigned char *digest); unsigned char *digest);*/
/* /*
* fs/cifs/misc.c * fs/cifs/misc.c
* *
* Copyright (C) International Business Machines Corp., 2002,2005 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -40,7 +40,7 @@ extern mempool_t *cifs_req_poolp; ...@@ -40,7 +40,7 @@ extern mempool_t *cifs_req_poolp;
extern kmem_cache_t *cifs_sm_req_cachep; extern kmem_cache_t *cifs_sm_req_cachep;
extern kmem_cache_t *cifs_req_cachep; extern kmem_cache_t *cifs_req_cachep;
#endif #endif
extern struct task_struct * oplockThread; extern struct task_struct *oplockThread;
/* The xid serves as a useful identifier for each incoming vfs request, /* The xid serves as a useful identifier for each incoming vfs request,
in a similar way to the mid which is useful to track each sent smb, in a similar way to the mid which is useful to track each sent smb,
...@@ -55,10 +55,12 @@ _GetXid(void) ...@@ -55,10 +55,12 @@ _GetXid(void)
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
GlobalTotalActiveXid++; GlobalTotalActiveXid++;
/* keep high water mark for number of simultaneous ops in filesystem */
if (GlobalTotalActiveXid > GlobalMaxActiveXid) if (GlobalTotalActiveXid > GlobalMaxActiveXid)
GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ GlobalMaxActiveXid = GlobalTotalActiveXid;
if(GlobalTotalActiveXid > 65000) if (GlobalTotalActiveXid > 65000)
cFYI(1,("warning: more than 65000 requests active")); cFYI(1, ("warning: more than 65000 requests active"));
xid = GlobalCurrentXid++; xid = GlobalCurrentXid++;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
return xid; return xid;
...@@ -68,7 +70,7 @@ void ...@@ -68,7 +70,7 @@ void
_FreeXid(unsigned int xid) _FreeXid(unsigned int xid)
{ {
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
/* if(GlobalTotalActiveXid == 0) /* if (GlobalTotalActiveXid == 0)
BUG(); */ BUG(); */
GlobalTotalActiveXid--; GlobalTotalActiveXid--;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -156,13 +158,13 @@ cifs_buf_get(void) ...@@ -156,13 +158,13 @@ cifs_buf_get(void)
but it may be more efficient to always alloc same size but it may be more efficient to always alloc same size
albeit slightly larger than necessary and maxbuffersize albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */ defaults to this and can not be bigger */
ret_buf =
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
(struct smb_hdr *) mempool_alloc(cifs_req_poolp, SLAB_KERNEL | SLAB_NOFS); ret_buf = (struct smb_hdr *) mempool_alloc(cifs_req_poolp,
GFP_KERNEL | GFP_NOFS);
#else #else
(struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL); ret_buf = (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep,
SLAB_KERNEL);
#endif #endif
/* clear the first few header bytes */ /* clear the first few header bytes */
/* for most paths, more is cleared in header_assemble */ /* for most paths, more is cleared in header_assemble */
if (ret_buf) { if (ret_buf) {
...@@ -185,10 +187,11 @@ cifs_buf_release(void *buf_to_free) ...@@ -185,10 +187,11 @@ cifs_buf_release(void *buf_to_free)
return; return;
} }
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
mempool_free(buf_to_free,cifs_req_poolp); mempool_free(buf_to_free, cifs_req_poolp);
#else #else
kmem_cache_free(cifs_req_cachep, buf_to_free); kmem_cache_free(cifs_req_cachep, buf_to_free);
#endif #endif
atomic_dec(&bufAllocCount); atomic_dec(&bufAllocCount);
return; return;
} }
...@@ -202,11 +205,12 @@ cifs_small_buf_get(void) ...@@ -202,11 +205,12 @@ cifs_small_buf_get(void)
but it may be more efficient to always alloc same size but it may be more efficient to always alloc same size
albeit slightly larger than necessary and maxbuffersize albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */ defaults to this and can not be bigger */
ret_buf =
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
(struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, SLAB_KERNEL | SLAB_NOFS); ret_buf = (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp,
GFP_KERNEL | GFP_NOFS);
#else #else
(struct smb_hdr *) kmem_cache_alloc(cifs_sm_req_cachep, SLAB_KERNEL); ret_buf = (struct smb_hdr *) kmem_cache_alloc(cifs_sm_req_cachep,
SLAB_KERNEL);
#endif #endif
if (ret_buf) { if (ret_buf) {
/* No need to clear memory here, cleared in header assemble */ /* No need to clear memory here, cleared in header assemble */
...@@ -229,7 +233,7 @@ cifs_small_buf_release(void *buf_to_free) ...@@ -229,7 +233,7 @@ cifs_small_buf_release(void *buf_to_free)
return; return;
} }
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
mempool_free(buf_to_free,cifs_sm_req_poolp); mempool_free(buf_to_free, cifs_sm_req_poolp);
#else #else
kmem_cache_free(cifs_sm_req_cachep, buf_to_free); kmem_cache_free(cifs_sm_req_cachep, buf_to_free);
#endif #endif
...@@ -265,7 +269,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server) ...@@ -265,7 +269,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
__u16 last_mid; __u16 last_mid;
int collision; int collision;
if(server == NULL) if (server == NULL)
return mid; return mid;
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
...@@ -278,12 +282,12 @@ __u16 GetNextMid(struct TCP_Server_Info *server) ...@@ -278,12 +282,12 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
takes longer than the 64 thousand requests before it takes longer than the 64 thousand requests before it
(and it would also have to have been a request that (and it would also have to have been a request that
did not time out) */ did not time out) */
while(server->CurrentMid != last_mid) { while (server->CurrentMid != last_mid) {
struct list_head *tmp; struct list_head *tmp;
struct mid_q_entry *mid_entry; struct mid_q_entry *mid_entry;
collision = 0; collision = 0;
if(server->CurrentMid == 0) if (server->CurrentMid == 0)
server->CurrentMid++; server->CurrentMid++;
list_for_each(tmp, &server->pending_mid_q) { list_for_each(tmp, &server->pending_mid_q) {
...@@ -296,7 +300,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server) ...@@ -296,7 +300,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
break; break;
} }
} }
if(collision == 0) { if (collision == 0) {
mid = server->CurrentMid; mid = server->CurrentMid;
break; break;
} }
...@@ -313,11 +317,11 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -313,11 +317,11 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
const struct cifsTconInfo *treeCon, int word_count const struct cifsTconInfo *treeCon, int word_count
/* length of fixed section (word count) in two byte units */) /* length of fixed section (word count) in two byte units */)
{ {
struct list_head* temp_item; struct list_head *temp_item;
struct cifsSesInfo * ses; struct cifsSesInfo *ses;
char *temp = (char *) buffer; char *temp = (char *) buffer;
memset(temp,0,256); /* bigger than MAX_CIFS_HDR_SIZE */ memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
buffer->smb_buf_length = buffer->smb_buf_length =
(2 * word_count) + sizeof (struct smb_hdr) - (2 * word_count) + sizeof (struct smb_hdr) -
...@@ -348,7 +352,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -348,7 +352,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
/* Uid is not converted */ /* Uid is not converted */
buffer->Uid = treeCon->ses->Suid; buffer->Uid = treeCon->ses->Suid;
buffer->Mid = GetNextMid(treeCon->ses->server); buffer->Mid = GetNextMid(treeCon->ses->server);
if(multiuser_mount != 0) { if (multiuser_mount != 0) {
/* For the multiuser case, there are few obvious technically */ /* For the multiuser case, there are few obvious technically */
/* possible mechanisms to match the local linux user (uid) */ /* possible mechanisms to match the local linux user (uid) */
/* to a valid remote smb user (smb_uid): */ /* to a valid remote smb user (smb_uid): */
...@@ -373,19 +377,20 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -373,19 +377,20 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
/* BB Add support for establishing new tCon and SMB Session */ /* BB Add support for establishing new tCon and SMB Session */
/* with userid/password pairs found on the smb session */ /* with userid/password pairs found on the smb session */
/* for other target tcp/ip addresses BB */ /* for other target tcp/ip addresses BB */
if(current->fsuid != treeCon->ses->linux_uid) { if (current->fsuid != treeCon->ses->linux_uid) {
cFYI(1,("Multiuser mode and UID did not match tcon uid")); cFYI(1, ("Multiuser mode and UID "
"did not match tcon uid"));
read_lock(&GlobalSMBSeslock); read_lock(&GlobalSMBSeslock);
list_for_each(temp_item, &GlobalSMBSessionList) { list_for_each(temp_item, &GlobalSMBSessionList) {
ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
if(ses->linux_uid == current->fsuid) { if (ses->linux_uid == current->fsuid) {
if(ses->server == treeCon->ses->server) { if (ses->server == treeCon->ses->server) {
cFYI(1,("found matching uid substitute right smb_uid")); cFYI(1, ("found matching uid substitute right smb_uid"));
buffer->Uid = ses->Suid; buffer->Uid = ses->Suid;
break; break;
} else { } else {
/* BB eventually call cifs_setup_session here */ /* BB eventually call cifs_setup_session here */
cFYI(1,("local UID found but smb sess with this server does not exist")); cFYI(1, ("local UID found but no smb sess with this server exists"));
} }
} }
} }
...@@ -397,8 +402,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -397,8 +402,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
buffer->Flags2 |= SMBFLG2_DFS; buffer->Flags2 |= SMBFLG2_DFS;
if (treeCon->nocase) if (treeCon->nocase)
buffer->Flags |= SMBFLG_CASELESS; buffer->Flags |= SMBFLG_CASELESS;
if((treeCon->ses) && (treeCon->ses->server)) if ((treeCon->ses) && (treeCon->ses->server))
if(treeCon->ses->server->secMode & if (treeCon->ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
} }
...@@ -408,21 +413,21 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ...@@ -408,21 +413,21 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
return; return;
} }
int static int
checkSMBhdr(struct smb_hdr *smb, __u16 mid) checkSMBhdr(struct smb_hdr *smb, __u16 mid)
{ {
/* Make sure that this really is an SMB, that it is a response, /* Make sure that this really is an SMB, that it is a response,
and that the message ids match */ and that the message ids match */
if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) && if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
(mid == smb->Mid)) { (mid == smb->Mid)) {
if(smb->Flags & SMBFLG_RESPONSE) if (smb->Flags & SMBFLG_RESPONSE)
return 0; return 0;
else { else {
/* only one valid case where server sends us request */ /* only one valid case where server sends us request */
if(smb->Command == SMB_COM_LOCKING_ANDX) if (smb->Command == SMB_COM_LOCKING_ANDX)
return 0; return 0;
else else
cERROR(1, ("Rcvd Request not response")); cERROR(1, ("Received Request not response"));
} }
} else { /* bad signature or mid */ } else { /* bad signature or mid */
if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
...@@ -451,7 +456,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) ...@@ -451,7 +456,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
return 0; return 0;
} else if ((length == sizeof(struct smb_hdr) + 1) && } else if ((length == sizeof(struct smb_hdr) + 1) &&
(smb->WordCount == 0)) { (smb->WordCount == 0)) {
char * tmp = (char *)smb; char *tmp = (char *)smb;
/* Need to work around a bug in two servers here */ /* Need to work around a bug in two servers here */
/* First, check if the part of bcc they sent was zero */ /* First, check if the part of bcc they sent was zero */
if (tmp[sizeof(struct smb_hdr)] == 0) { if (tmp[sizeof(struct smb_hdr)] == 0) {
...@@ -465,7 +470,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) ...@@ -465,7 +470,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
tmp[sizeof(struct smb_hdr)+1] = 0; tmp[sizeof(struct smb_hdr)+1] = 0;
return 0; return 0;
} }
cERROR(1,("rcvd invalid byte count (bcc)")); cERROR(1, ("rcvd invalid byte count (bcc)"));
} else { } else {
cERROR(1, ("Length less than smb header size")); cERROR(1, ("Length less than smb header size"));
} }
...@@ -481,16 +486,17 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) ...@@ -481,16 +486,17 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
return 1; return 1;
clc_len = smbCalcSize_LE(smb); clc_len = smbCalcSize_LE(smb);
if(4 + len != length) { if (4 + len != length) {
cERROR(1, ("Length read does not match RFC1001 length %d",len)); cERROR(1, ("Length read does not match RFC1001 length %d",
len));
return 1; return 1;
} }
if (4 + len != clc_len) { if (4 + len != clc_len) {
/* check if bcc wrapped around for large read responses */ /* check if bcc wrapped around for large read responses */
if((len > 64 * 1024) && (len > clc_len)) { if ((len > 64 * 1024) && (len > clc_len)) {
/* check if lengths match mod 64K */ /* check if lengths match mod 64K */
if(((4 + len) & 0xFFFF) == (clc_len & 0xFFFF)) if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
return 0; /* bcc wrapped */ return 0; /* bcc wrapped */
} }
cFYI(1, ("Calculated size %d vs length %d mismatch for mid %d", cFYI(1, ("Calculated size %d vs length %d mismatch for mid %d",
...@@ -506,7 +512,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) ...@@ -506,7 +512,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
but server says length is 0x21 bytes too long as if the server but server says length is 0x21 bytes too long as if the server
forget to reset the smb rfc1001 length when it reset the forget to reset the smb rfc1001 length when it reset the
wct and bcc to minimum size and drop the t2 parms and data */ wct and bcc to minimum size and drop the t2 parms and data */
if((4+len > clc_len) && (len <= clc_len + 512)) if ((4+len > clc_len) && (len <= clc_len + 512))
return 0; return 0;
else { else {
cERROR(1, ("RFC1001 size %d bigger than SMB for Mid=%d", cERROR(1, ("RFC1001 size %d bigger than SMB for Mid=%d",
...@@ -519,46 +525,48 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) ...@@ -519,46 +525,48 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
int int
is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
{ {
struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf; struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
struct list_head *tmp; struct list_head *tmp;
struct list_head *tmp1; struct list_head *tmp1;
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
struct cifsFileInfo *netfile; struct cifsFileInfo *netfile;
cFYI(1,("Checking for oplock break or dnotify response")); cFYI(1, ("Checking for oplock break or dnotify response"));
if((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) && if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
(pSMB->hdr.Flags & SMBFLG_RESPONSE)) { (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
struct smb_com_transaction_change_notify_rsp * pSMBr = struct smb_com_transaction_change_notify_rsp *pSMBr =
(struct smb_com_transaction_change_notify_rsp *)buf; (struct smb_com_transaction_change_notify_rsp *)buf;
struct file_notify_information * pnotify; struct file_notify_information *pnotify;
__u32 data_offset = 0; __u32 data_offset = 0;
if(pSMBr->ByteCount > sizeof(struct file_notify_information)) { if (pSMBr->ByteCount > sizeof(struct file_notify_information)) {
data_offset = le32_to_cpu(pSMBr->DataOffset); data_offset = le32_to_cpu(pSMBr->DataOffset);
pnotify = (struct file_notify_information *) pnotify = (struct file_notify_information *)
((char *)&pSMBr->hdr.Protocol + data_offset); ((char *)&pSMBr->hdr.Protocol + data_offset);
cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName, cFYI(1, ("dnotify on %s Action: 0x%x",
pnotify->FileName,
pnotify->Action)); /* BB removeme BB */ pnotify->Action)); /* BB removeme BB */
/* cifs_dump_mem("Rcvd notify Data: ",buf, /* cifs_dump_mem("Rcvd notify Data: ",buf,
sizeof(struct smb_hdr)+60); */ sizeof(struct smb_hdr)+60); */
return TRUE; return TRUE;
} }
if(pSMBr->hdr.Status.CifsError) { if (pSMBr->hdr.Status.CifsError) {
cFYI(1,("notify err 0x%d",pSMBr->hdr.Status.CifsError)); cFYI(1, ("notify err 0x%d",
pSMBr->hdr.Status.CifsError));
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
return FALSE; return FALSE;
if(pSMB->hdr.Flags & SMBFLG_RESPONSE) { if (pSMB->hdr.Flags & SMBFLG_RESPONSE) {
/* no sense logging error on invalid handle on oplock /* no sense logging error on invalid handle on oplock
break - harmless race between close request and oplock break - harmless race between close request and oplock
break response is expected from time to time writing out break response is expected from time to time writing out
large dirty files cached on the client */ large dirty files cached on the client */
if ((NT_STATUS_INVALID_HANDLE) == if ((NT_STATUS_INVALID_HANDLE) ==
le32_to_cpu(pSMB->hdr.Status.CifsError)) { le32_to_cpu(pSMB->hdr.Status.CifsError)) {
cFYI(1,("invalid handle on oplock break")); cFYI(1, ("invalid handle on oplock break"));
return TRUE; return TRUE;
} else if (ERRbadfid == } else if (ERRbadfid ==
le16_to_cpu(pSMB->hdr.Status.DosError.Error)) { le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
...@@ -567,11 +575,12 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) ...@@ -567,11 +575,12 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
return FALSE; /* on valid oplock brk we get "request" */ return FALSE; /* on valid oplock brk we get "request" */
} }
} }
if(pSMB->hdr.WordCount != 8) if (pSMB->hdr.WordCount != 8)
return FALSE; return FALSE;
cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel)); cFYI(1, ("oplock type 0x%d level 0x%d",
if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) pSMB->LockType, pSMB->OplockLevel));
if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
return FALSE; return FALSE;
/* look up tcon based on tid & uid */ /* look up tcon based on tid & uid */
...@@ -580,36 +589,38 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) ...@@ -580,36 +589,38 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) { if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) {
cifs_stats_inc(&tcon->num_oplock_brks); cifs_stats_inc(&tcon->num_oplock_brks);
list_for_each(tmp1,&tcon->openFileList){ list_for_each(tmp1, &tcon->openFileList) {
netfile = list_entry(tmp1,struct cifsFileInfo, netfile = list_entry(tmp1, struct cifsFileInfo,
tlist); tlist);
if(pSMB->Fid == netfile->netfid) { if (pSMB->Fid == netfile->netfid) {
struct cifsInodeInfo *pCifsInode; struct cifsInodeInfo *pCifsInode;
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
cFYI(1,("file id match, oplock break")); cFYI(1,
("file id match, oplock break"));
pCifsInode = pCifsInode =
CIFS_I(netfile->pInode); CIFS_I(netfile->pInode);
pCifsInode->clientCanCacheAll = FALSE; pCifsInode->clientCanCacheAll = FALSE;
if(pSMB->OplockLevel == 0) if (pSMB->OplockLevel == 0)
pCifsInode->clientCanCacheRead pCifsInode->clientCanCacheRead
= FALSE; = FALSE;
pCifsInode->oplockPending = TRUE; pCifsInode->oplockPending = TRUE;
AllocOplockQEntry(netfile->pInode, AllocOplockQEntry(netfile->pInode,
netfile->netfid, netfile->netfid,
tcon); tcon);
cFYI(1,("about to wake up oplock thd")); cFYI(1,
if(oplockThread) ("about to wake up oplock thread"));
if (oplockThread)
wake_up_process(oplockThread); wake_up_process(oplockThread);
return TRUE; return TRUE;
} }
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
cFYI(1,("No matching file for oplock break")); cFYI(1, ("No matching file for oplock break"));
return TRUE; return TRUE;
} }
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
cFYI(1,("Can not process oplock break for non-existent connection")); cFYI(1, ("Can not process oplock break for non-existent connection"));
return TRUE; return TRUE;
} }
...@@ -666,13 +677,13 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) ...@@ -666,13 +677,13 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
only legal in POSIX-like OS (if they are present in the string). Path only legal in POSIX-like OS (if they are present in the string). Path
names are little endian 16 bit Unicode on the wire */ names are little endian 16 bit Unicode on the wire */
int int
cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
const struct nls_table * cp) const struct nls_table *cp)
{ {
int i,j,len; int i, j, len;
__u16 src_char; __u16 src_char;
for(i = 0, j = 0; i < maxlen; i++) { for (i = 0, j = 0; i < maxlen; i++) {
src_char = le16_to_cpu(source[i]); src_char = le16_to_cpu(source[i]);
switch (src_char) { switch (src_char) {
case 0: case 0:
...@@ -704,7 +715,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, ...@@ -704,7 +715,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
default: default:
len = cp->uni2char(src_char, &target[j], len = cp->uni2char(src_char, &target[j],
NLS_MAX_CHARSET_SIZE); NLS_MAX_CHARSET_SIZE);
if(len > 0) { if (len > 0) {
j += len; j += len;
continue; continue;
} else { } else {
...@@ -713,7 +724,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, ...@@ -713,7 +724,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
} }
j++; j++;
/* make sure we do not overrun callers allocated temp buffer */ /* make sure we do not overrun callers allocated temp buffer */
if(j >= (2 * NAME_MAX)) if (j >= (2 * NAME_MAX))
break; break;
} }
cUCS_out: cUCS_out:
...@@ -726,18 +737,18 @@ cUCS_out: ...@@ -726,18 +737,18 @@ cUCS_out:
only legal in POSIX-like OS (if they are present in the string). Path only legal in POSIX-like OS (if they are present in the string). Path
names are little endian 16 bit Unicode on the wire */ names are little endian 16 bit Unicode on the wire */
int int
cifsConvertToUCS(__le16 * target, const char *source, int maxlen, cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
const struct nls_table * cp, int mapChars) const struct nls_table *cp, int mapChars)
{ {
int i,j,charlen; int i, j, charlen;
int len_remaining = maxlen; int len_remaining = maxlen;
char src_char; char src_char;
__u16 temp; __u16 temp;
if(!mapChars) if (!mapChars)
return cifs_strtoUCS(target, source, PATH_MAX, cp); return cifs_strtoUCS(target, source, PATH_MAX, cp);
for(i = 0, j = 0; i < maxlen; j++) { for (i = 0, j = 0; i < maxlen; j++) {
src_char = source[i]; src_char = source[i];
switch (src_char) { switch (src_char) {
case 0: case 0:
...@@ -772,7 +783,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, ...@@ -772,7 +783,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
len_remaining, &temp); len_remaining, &temp);
/* if no match, use question mark, which /* if no match, use question mark, which
at least in some cases servers as wild card */ at least in some cases servers as wild card */
if(charlen < 1) { if (charlen < 1) {
target[j] = cpu_to_le16(0x003f); target[j] = cpu_to_le16(0x003f);
charlen = 1; charlen = 1;
} else } else
...@@ -781,7 +792,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, ...@@ -781,7 +792,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
/* character may take more than one byte in the /* character may take more than one byte in the
the source string, but will take exactly two the source string, but will take exactly two
bytes in the target string */ bytes in the target string */
i+= charlen; i += charlen;
continue; continue;
} }
i++; /* move to next char in source string */ i++; /* move to next char in source string */
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
* Error mapping routines from Samba libsmb/errormap.c * Error mapping routines from Samba libsmb/errormap.c
* Copyright (C) Andrew Tridgell 2001 * Copyright (C) Andrew Tridgell 2001
* *
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
...@@ -30,6 +29,7 @@ ...@@ -30,6 +29,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <asm/div64.h> #include <asm/div64.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/inet.h>
#include "cifsfs.h" #include "cifsfs.h"
#include "cifspdu.h" #include "cifspdu.h"
#include "cifsglob.h" #include "cifsglob.h"
...@@ -64,22 +64,22 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { ...@@ -64,22 +64,22 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
{ERRbadshare, -ETXTBSY}, {ERRbadshare, -ETXTBSY},
{ERRlock, -EACCES}, {ERRlock, -EACCES},
{ERRunsup, -EINVAL}, {ERRunsup, -EINVAL},
{ERRnosuchshare,-ENXIO}, {ERRnosuchshare, -ENXIO},
{ERRfilexists, -EEXIST}, {ERRfilexists, -EEXIST},
{ERRinvparm, -EINVAL}, {ERRinvparm, -EINVAL},
{ERRdiskfull, -ENOSPC}, {ERRdiskfull, -ENOSPC},
{ERRinvname, -ENOENT}, {ERRinvname, -ENOENT},
{ERRinvlevel,-EOPNOTSUPP}, {ERRinvlevel, -EOPNOTSUPP},
{ERRdirnotempty, -ENOTEMPTY}, {ERRdirnotempty, -ENOTEMPTY},
{ERRnotlocked, -ENOLCK}, {ERRnotlocked, -ENOLCK},
{ERRcancelviolation, -ENOLCK}, {ERRcancelviolation, -ENOLCK},
{ERRalreadyexists, -EEXIST}, {ERRalreadyexists, -EEXIST},
{ERRmoredata, -EOVERFLOW}, {ERRmoredata, -EOVERFLOW},
{ERReasnotsupported,-EOPNOTSUPP}, {ERReasnotsupported, -EOPNOTSUPP},
{ErrQuota, -EDQUOT}, {ErrQuota, -EDQUOT},
{ErrNotALink, -ENOLINK}, {ErrNotALink, -ENOLINK},
{ERRnetlogonNotStarted,-ENOPROTOOPT}, {ERRnetlogonNotStarted, -ENOPROTOOPT},
{ErrTooManyLinks,-EMLINK}, {ErrTooManyLinks, -EMLINK},
{0, 0} {0, 0}
}; };
...@@ -129,11 +129,27 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = { ...@@ -129,11 +129,27 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
/* Convert string containing dotted ip address to binary form */ /* Convert string containing dotted ip address to binary form */
/* returns 0 if invalid address */ /* returns 0 if invalid address */
/* BB add address family, change rc to status flag and return union or for ipv6 */
/* will need parent to call something like inet_pton to convert ipv6 address BB */
int int
cifs_inet_pton(int address_family, char *cp,void *dst) cifs_inet_pton(int address_family, char *cp, void *dst)
{ {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)
int ret = 0;
/* calculate length by finding first slash or NULL */
/* BB Should we convert '/' slash to '\' here since it seems already
* done before this */
if ( address_family == AF_INET ) {
ret = in4_pton(cp, -1 /* len */, dst , '\\', NULL);
} else if ( address_family == AF_INET6 ) {
ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
}
#ifdef CONFIG_CIFS_DEBUG2
cFYI(1, ("address conversion returned %d for %s", ret, cp));
#endif
if (ret > 0)
ret = 1;
return ret;
#else /* pre-2.6.20 */
int value; int value;
int digit; int digit;
int i; int i;
...@@ -192,6 +208,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst) ...@@ -192,6 +208,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst)
*((__be32 *)dst) = *((__be32 *) bytes) | htonl(value); *((__be32 *)dst) = *((__be32 *) bytes) | htonl(value);
return 1; /* success */ return 1; /* success */
#endif
} }
/***************************************************************************** /*****************************************************************************
...@@ -373,8 +390,8 @@ static const struct { ...@@ -373,8 +390,8 @@ static const struct {
ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, { ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, {
ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED}, ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
/* { This NT error code was 'sqashed' /* { This NT error code was 'sqashed'
from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES from NT_STATUS_INSUFFICIENT_RESOURCES to
during the session setup } */ NT_STATUS_INSUFF_SERVER_RESOURCES during the session setup } */
{ {
ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, { ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, {
ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, { ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, {
...@@ -618,8 +635,8 @@ static const struct { ...@@ -618,8 +635,8 @@ static const struct {
ERRDOS, 19, NT_STATUS_TOO_LATE}, { ERRDOS, 19, NT_STATUS_TOO_LATE}, {
ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET}, ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET},
/* { This NT error code was 'sqashed' /* { This NT error code was 'sqashed'
from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE from NT_STATUS_NO_TRUST_SAM_ACCOUNT to
during the session setup } */ NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE during the session setup } */
{ {
ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, { ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, {
ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, { ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, {
...@@ -769,7 +786,7 @@ cifs_print_status(__u32 status_code) ...@@ -769,7 +786,7 @@ cifs_print_status(__u32 status_code)
if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) == if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==
(status_code & 0xFFFFFF)) { (status_code & 0xFFFFFF)) {
printk(KERN_NOTICE "Status code returned 0x%08x %s\n", printk(KERN_NOTICE "Status code returned 0x%08x %s\n",
status_code,nt_errs[idx].nt_errstr); status_code, nt_errs[idx].nt_errstr);
} }
idx++; idx++;
} }
...@@ -812,9 +829,10 @@ map_smb_to_linux_error(struct smb_hdr *smb) ...@@ -812,9 +829,10 @@ map_smb_to_linux_error(struct smb_hdr *smb)
return 0; return 0;
if (smb->Flags2 & SMBFLG2_ERR_STATUS) { if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
/* translate the newer STATUS codes to old style errors and then to POSIX errors */ /* translate the newer STATUS codes to old style SMB errors
* and then to POSIX errors */
__u32 err = le32_to_cpu(smb->Status.CifsError); __u32 err = le32_to_cpu(smb->Status.CifsError);
if(cifsFYI & CIFS_RC) if (cifsFYI & CIFS_RC)
cifs_print_status(err); cifs_print_status(err);
ntstatus_to_dos(err, &smberrclass, &smberrcode); ntstatus_to_dos(err, &smberrclass, &smberrcode);
} else { } else {
...@@ -825,18 +843,19 @@ map_smb_to_linux_error(struct smb_hdr *smb) ...@@ -825,18 +843,19 @@ map_smb_to_linux_error(struct smb_hdr *smb)
/* old style errors */ /* old style errors */
/* DOS class smb error codes - map DOS */ /* DOS class smb error codes - map DOS */
if (smberrclass == ERRDOS) { /* one byte field no need to byte reverse */ if (smberrclass == ERRDOS) { /* 1 byte field no need to byte reverse */
for (i = 0; for (i = 0;
i < i <
sizeof (mapping_table_ERRDOS) / sizeof (mapping_table_ERRDOS) /
sizeof (struct smb_to_posix_error); i++) { sizeof (struct smb_to_posix_error); i++) {
if (mapping_table_ERRDOS[i].smb_err == 0) if (mapping_table_ERRDOS[i].smb_err == 0)
break; break;
else if (mapping_table_ERRDOS[i].smb_err == smberrcode) { else if (mapping_table_ERRDOS[i].smb_err ==
smberrcode) {
rc = mapping_table_ERRDOS[i].posix_code; rc = mapping_table_ERRDOS[i].posix_code;
break; break;
} }
/* else try the next error mapping one to see if it will match */ /* else try next error mapping one to see if match */
} }
} else if (smberrclass == ERRSRV) { /* server class of error codes */ } else if (smberrclass == ERRSRV) { /* server class of error codes */
for (i = 0; for (i = 0;
...@@ -845,18 +864,21 @@ map_smb_to_linux_error(struct smb_hdr *smb) ...@@ -845,18 +864,21 @@ map_smb_to_linux_error(struct smb_hdr *smb)
sizeof (struct smb_to_posix_error); i++) { sizeof (struct smb_to_posix_error); i++) {
if (mapping_table_ERRSRV[i].smb_err == 0) if (mapping_table_ERRSRV[i].smb_err == 0)
break; break;
else if (mapping_table_ERRSRV[i].smb_err == smberrcode) { else if (mapping_table_ERRSRV[i].smb_err ==
smberrcode) {
rc = mapping_table_ERRSRV[i].posix_code; rc = mapping_table_ERRSRV[i].posix_code;
break; break;
} }
/* else try the next error mapping one to see if it will match */ /* else try next error mapping to see if match */
} }
} }
/* else ERRHRD class errors or junk - return EIO */ /* else ERRHRD class errors or junk - return EIO */
cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", smberrcode,rc)); cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!",
smberrcode, rc));
/* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */ /* generic corrective action e.g. reconnect SMB session on
* ERRbaduid could be added */
return rc; return rc;
} }
...@@ -888,11 +910,9 @@ smbCalcSize_LE(struct smb_hdr *ptr) ...@@ -888,11 +910,9 @@ smbCalcSize_LE(struct smb_hdr *ptr)
* into Unix UTC (based 1970-01-01, in seconds). * into Unix UTC (based 1970-01-01, in seconds).
*/ */
static int total_days_of_prev_months[] = static int total_days_of_prev_months[] =
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
__le64 cnvrtDosCifsTm(__u16 date, __u16 time) __le64 cnvrtDosCifsTm(__u16 date, __u16 time)
{ {
return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time))); return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time)));
...@@ -922,6 +942,7 @@ cifs_UnixTimeToNT(struct timespec t) ...@@ -922,6 +942,7 @@ cifs_UnixTimeToNT(struct timespec t)
return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET; return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET;
} }
struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
{ {
struct timespec ts; struct timespec ts;
...@@ -929,20 +950,20 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) ...@@ -929,20 +950,20 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
SMB_TIME * st = (SMB_TIME *)&time; SMB_TIME * st = (SMB_TIME *)&time;
SMB_DATE * sd = (SMB_DATE *)&date; SMB_DATE * sd = (SMB_DATE *)&date;
cFYI(1,("date %d time %d",date, time)); cFYI(1, ("date %d time %d", date, time));
sec = 2 * st->TwoSeconds; sec = 2 * st->TwoSeconds;
min = st->Minutes; min = st->Minutes;
if((sec > 59) || (min > 59)) if ((sec > 59) || (min > 59))
cERROR(1,("illegal time min %d sec %d", min, sec)); cERROR(1, ("illegal time min %d sec %d", min, sec));
sec += (min * 60); sec += (min * 60);
sec += 60 * 60 * st->Hours; sec += 60 * 60 * st->Hours;
if(st->Hours > 24) if (st->Hours > 24)
cERROR(1,("illegal hours %d",st->Hours)); cERROR(1, ("illegal hours %d", st->Hours));
days = sd->Day; days = sd->Day;
month = sd->Month; month = sd->Month;
if((days > 31) || (month > 12)) if ((days > 31) || (month > 12))
cERROR(1,("illegal date, month %d day: %d", month, days)); cERROR(1, ("illegal date, month %d day: %d", month, days));
month -= 1; month -= 1;
days += total_days_of_prev_months[month]; days += total_days_of_prev_months[month];
days += 3652; /* account for difference in days between 1980 and 1970 */ days += 3652; /* account for difference in days between 1980 and 1970 */
...@@ -955,11 +976,11 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) ...@@ -955,11 +976,11 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
consider 2 special case years, ie the years 2000 and 2100, and only consider 2 special case years, ie the years 2000 and 2100, and only
adjust for the lack of leap year for the year 2100, as 2000 was a adjust for the lack of leap year for the year 2100, as 2000 was a
leap year (divisable by 400) */ leap year (divisable by 400) */
if(year >= 120) /* the year 2100 */ if (year >= 120) /* the year 2100 */
days = days - 1; /* do not count leap year for the year 2100 */ days = days - 1; /* do not count leap year for the year 2100 */
/* adjust for leap year where we are still before leap day */ /* adjust for leap year where we are still before leap day */
if(year != 120) if (year != 120)
days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0);
sec += 24 * 60 * 60 * days; sec += 24 * 60 * 60 * days;
......
/* /*
* fs/cifs/ntlmssp.h * fs/cifs/ntlmssp.h
* *
* Copyright (c) International Business Machines Corp., 2002,2006 * Copyright (c) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -27,18 +27,18 @@ ...@@ -27,18 +27,18 @@
#define UnknownMessage cpu_to_le32(8) #define UnknownMessage cpu_to_le32(8)
/* Negotiate Flags */ /* Negotiate Flags */
#define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode #define NTLMSSP_NEGOTIATE_UNICODE 0x01 /* Text strings are in unicode */
#define NTLMSSP_NEGOTIATE_OEM 0x02 // Text strings are in OEM #define NTLMSSP_NEGOTIATE_OEM 0x02 /* Text strings are in OEM */
#define NTLMSSP_REQUEST_TARGET 0x04 // Server return its auth realm #define NTLMSSP_REQUEST_TARGET 0x04 /* Server return its auth realm */
#define NTLMSSP_NEGOTIATE_SIGN 0x0010 // Request signature capability #define NTLMSSP_NEGOTIATE_SIGN 0x0010 /* Request signature capability */
#define NTLMSSP_NEGOTIATE_SEAL 0x0020 // Request confidentiality #define NTLMSSP_NEGOTIATE_SEAL 0x0020 /* Request confidentiality */
#define NTLMSSP_NEGOTIATE_DGRAM 0x0040 #define NTLMSSP_NEGOTIATE_DGRAM 0x0040
#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 // Use LM session key for sign/seal #define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 /* Sign/seal use LM session key */
#define NTLMSSP_NEGOTIATE_NTLM 0x0200 // NTLM authentication #define NTLMSSP_NEGOTIATE_NTLM 0x0200 /* NTLM authentication */
#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000
#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 // client/server on same machine #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 /* client/server on same machine */
#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 // Sign for all security levels #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 /* Sign for all security levels */
#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000
#define NTLMSSP_TARGET_TYPE_SERVER 0x20000 #define NTLMSSP_TARGET_TYPE_SERVER 0x20000
#define NTLMSSP_TARGET_TYPE_SHARE 0x40000 #define NTLMSSP_TARGET_TYPE_SHARE 0x40000
......
...@@ -35,24 +35,23 @@ ...@@ -35,24 +35,23 @@
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
static void dump_cifs_file_struct(struct file *file, char *label) static void dump_cifs_file_struct(struct file *file, char *label)
{ {
struct cifsFileInfo * cf; struct cifsFileInfo *cf;
if(file) { if (file) {
cf = file->private_data; cf = file->private_data;
if(cf == NULL) { if (cf == NULL) {
cFYI(1,("empty cifs private file data")); cFYI(1, ("empty cifs private file data"));
return; return;
} }
if(cf->invalidHandle) { if (cf->invalidHandle) {
cFYI(1,("invalid handle")); cFYI(1, ("invalid handle"));
} }
if(cf->srch_inf.endOfSearch) { if (cf->srch_inf.endOfSearch) {
cFYI(1,("end of search")); cFYI(1, ("end of search"));
} }
if(cf->srch_inf.emptyDir) { if (cf->srch_inf.emptyDir) {
cFYI(1,("empty dir")); cFYI(1, ("empty dir"));
} }
} }
} }
#endif /* DEBUG2 */ #endif /* DEBUG2 */
...@@ -68,46 +67,69 @@ static int construct_dentry(struct qstr *qstring, struct file *file, ...@@ -68,46 +67,69 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
int rc = 0; int rc = 0;
cFYI(1, ("For %s", qstring->name)); cFYI(1, ("For %s", qstring->name));
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
qstring->hash = full_name_hash(qstring->name, qstring->len); qstring->hash = full_name_hash(qstring->name, qstring->len);
tmp_dentry = d_lookup(file->f_dentry, qstring); tmp_dentry = d_lookup(file->f_dentry, qstring);
if (tmp_dentry) { if (tmp_dentry) {
cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode)); cFYI(0, ("existing dentry with inode 0x%p",
tmp_dentry->d_inode));
*ptmp_inode = 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??*/ /* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
if(*ptmp_inode == NULL) { if (*ptmp_inode == NULL) {
*ptmp_inode = new_inode(file->f_dentry->d_sb); *ptmp_inode = new_inode(file->f_dentry->d_sb);
if(*ptmp_inode == NULL) #else
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) {
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);
#endif
if (*ptmp_inode == NULL)
return rc; return rc;
rc = 1; rc = 1;
} }
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19)
if(file->f_path.dentry->d_sb->s_flags & MS_NOATIME) if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
#else #else
if(file->f_dentry->d_sb->s_flags & MS_NOATIME) if (file->f_dentry->d_sb->s_flags & MS_NOATIME)
#endif #endif
(*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
} else { } else {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
tmp_dentry = d_alloc(file->f_dentry, qstring); tmp_dentry = d_alloc(file->f_dentry, qstring);
if(tmp_dentry == NULL) { #else
cERROR(1,("Failed allocating dentry")); tmp_dentry = d_alloc(file->f_path.dentry, qstring);
#endif
if (tmp_dentry == NULL) {
cERROR(1, ("Failed allocating dentry"));
*ptmp_inode = NULL; *ptmp_inode = NULL;
return rc; return rc;
} }
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
*ptmp_inode = new_inode(file->f_dentry->d_sb); *ptmp_inode = new_inode(file->f_dentry->d_sb);
#else
*ptmp_inode = new_inode(file->f_path.dentry->d_sb);
#endif
if (pTcon->nocase) if (pTcon->nocase)
tmp_dentry->d_op = &cifs_ci_dentry_ops; tmp_dentry->d_op = &cifs_ci_dentry_ops;
else else
tmp_dentry->d_op = &cifs_dentry_ops; tmp_dentry->d_op = &cifs_dentry_ops;
if(*ptmp_inode == NULL) if (*ptmp_inode == NULL)
return rc; return rc;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19)
if(file->f_path.dentry->d_sb->s_flags & MS_NOATIME) if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
#else #else
if(file->f_dentry->d_sb->s_flags & MS_NOATIME) if (file->f_dentry->d_sb->s_flags & MS_NOATIME)
#endif #endif
(*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME; (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
rc = 2; rc = 2;
...@@ -118,9 +140,9 @@ static int construct_dentry(struct qstr *qstring, struct file *file, ...@@ -118,9 +140,9 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
return rc; return rc;
} }
static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode) static void AdjustForTZ(struct cifsTconInfo *tcon, struct inode *inode)
{ {
if((tcon) && (tcon->ses) && (tcon->ses->server)) { if ((tcon) && (tcon->ses) && (tcon->ses->server)) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
inode->i_ctime.tv_sec += tcon->ses->server->timeAdj; inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
inode->i_mtime.tv_sec += tcon->ses->server->timeAdj; inode->i_mtime.tv_sec += tcon->ses->server->timeAdj;
...@@ -136,7 +158,7 @@ static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode) ...@@ -136,7 +158,7 @@ static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
char * buf, int *pobject_type, int isNewInode) char *buf, int *pobject_type, int isNewInode)
{ {
loff_t local_size; loff_t local_size;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
...@@ -145,6 +167,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, ...@@ -145,6 +167,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
time_t local_mtime; time_t local_mtime;
#endif #endif
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
__u32 attr; __u32 attr;
...@@ -155,7 +178,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, ...@@ -155,7 +178,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
local_mtime = tmp_inode->i_mtime; local_mtime = tmp_inode->i_mtime;
local_size = tmp_inode->i_size; local_size = tmp_inode->i_size;
if(new_buf_type) { if (new_buf_type) {
FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf; FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
attr = le32_to_cpu(pfindData->ExtFileAttributes); attr = le32_to_cpu(pfindData->ExtFileAttributes);
...@@ -185,13 +208,6 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, ...@@ -185,13 +208,6 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
attr = le16_to_cpu(pfindData->Attributes); attr = le16_to_cpu(pfindData->Attributes);
allocation_size = le32_to_cpu(pfindData->AllocationSize); allocation_size = le32_to_cpu(pfindData->AllocationSize);
end_of_file = le32_to_cpu(pfindData->DataSize); end_of_file = le32_to_cpu(pfindData->DataSize);
/* do not need to use current_fs_time helper function since
time not stored for this case so atime can not "go backwards"
by pulling newer older from disk when inode refrenshed */
tmp_inode->i_atime = CURRENT_TIME;
/* tmp_inode->i_mtime = BB FIXME - add dos time handling
tmp_inode->i_ctime = 0; BB FIXME */
} }
/* Linux can not store file creation time unfortunately so ignore it */ /* Linux can not store file creation time unfortunately so ignore it */
...@@ -218,7 +234,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, ...@@ -218,7 +234,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
if (attr & ATTR_DIRECTORY) { if (attr & ATTR_DIRECTORY) {
*pobject_type = DT_DIR; *pobject_type = DT_DIR;
/* override default perms since we do not lock dirs */ /* override default perms since we do not lock dirs */
if(atomic_read(&cifsInfo->inUse) == 0) { if (atomic_read(&cifsInfo->inUse) == 0) {
tmp_inode->i_mode = cifs_sb->mnt_dir_mode; tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
} }
tmp_inode->i_mode |= S_IFDIR; tmp_inode->i_mode |= S_IFDIR;
...@@ -275,25 +291,24 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, ...@@ -275,25 +291,24 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
if (S_ISREG(tmp_inode->i_mode)) { if (S_ISREG(tmp_inode->i_mode)) {
cFYI(1, ("File inode")); cFYI(1, ("File inode"));
tmp_inode->i_op = &cifs_file_inode_ops; tmp_inode->i_op = &cifs_file_inode_ops;
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
else else
tmp_inode->i_fop = &cifs_file_direct_ops; tmp_inode->i_fop = &cifs_file_direct_ops;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_nobrl_ops; tmp_inode->i_fop = &cifs_file_nobrl_ops;
else else
tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_fop = &cifs_file_ops;
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf < (cifs_sb->tcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else else
tmp_inode->i_data.a_ops = &cifs_addr_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops;
if(isNewInode) if (isNewInode)
return; /* No sense invalidating pages for new inode return; /* No sense invalidating pages for new inode
since have not started caching readahead file since have not started caching readahead file
data yet */ data yet */
...@@ -383,10 +398,16 @@ static void unix_fill_in_inode(struct inode *tmp_inode, ...@@ -383,10 +398,16 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
/* safest to just call it a file */ /* safest to just call it a file */
*pobject_type = DT_REG; *pobject_type = DT_REG;
tmp_inode->i_mode |= S_IFREG; tmp_inode->i_mode |= S_IFREG;
cFYI(1,("unknown inode type %d",type)); cFYI(1, ("unknown inode type %d", type));
} }
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
tmp_inode->i_uid = cifs_sb->mnt_uid;
else
tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
tmp_inode->i_gid = cifs_sb->mnt_gid;
else
tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
...@@ -406,27 +427,27 @@ static void unix_fill_in_inode(struct inode *tmp_inode, ...@@ -406,27 +427,27 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
cFYI(1, ("File inode")); cFYI(1, ("File inode"));
tmp_inode->i_op = &cifs_file_inode_ops; tmp_inode->i_op = &cifs_file_inode_ops;
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
else else
tmp_inode->i_fop = &cifs_file_direct_ops; tmp_inode->i_fop = &cifs_file_direct_ops;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_nobrl_ops; tmp_inode->i_fop = &cifs_file_nobrl_ops;
else else
tmp_inode->i_fop = &cifs_file_ops; tmp_inode->i_fop = &cifs_file_ops;
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf < (cifs_sb->tcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else else
tmp_inode->i_data.a_ops = &cifs_addr_ops; tmp_inode->i_data.a_ops = &cifs_addr_ops;
if(isNewInode) if (isNewInode)
return; /* No sense invalidating pages for new inode since we return; /* No sense invalidating pages for new inode
have not started caching readahead file data yet */ since we have not started caching readahead
file data for it yet */
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
(local_size == tmp_inode->i_size)) { (local_size == tmp_inode->i_size)) {
...@@ -454,39 +475,45 @@ static void unix_fill_in_inode(struct inode *tmp_inode, ...@@ -454,39 +475,45 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
static int initiate_cifs_search(const int xid, struct file *file) static int initiate_cifs_search(const int xid, struct file *file)
{ {
int rc = 0; int rc = 0;
char * full_path; char *full_path;
struct cifsFileInfo * cifsFile; struct cifsFileInfo *cifsFile;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
if(file->private_data == NULL) { if (file->private_data == NULL) {
file->private_data = file->private_data =
kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL); kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
} }
if(file->private_data == NULL) { if (file->private_data == NULL)
return -ENOMEM; return -ENOMEM;
} else {
memset(file->private_data,0,sizeof(struct cifsFileInfo));
}
cifsFile = file->private_data; cifsFile = file->private_data;
cifsFile->invalidHandle = TRUE; cifsFile->invalidHandle = TRUE;
cifsFile->srch_inf.endOfSearch = FALSE; cifsFile->srch_inf.endOfSearch = FALSE;
if(file->f_dentry == NULL) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
return -ENOENT;
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
if(cifs_sb == NULL) if (cifs_sb == NULL)
return -EINVAL; return -EINVAL;
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if(pTcon == NULL) if (pTcon == NULL)
return -EINVAL; return -EINVAL;
full_path = build_path_from_dentry(file->f_dentry); full_path = build_path_from_dentry(file->f_dentry);
#else
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
if (cifs_sb == NULL)
return -EINVAL;
if(full_path == NULL) { pTcon = cifs_sb->tcon;
if (pTcon == NULL)
return -EINVAL;
full_path = build_path_from_dentry(file->f_path.dentry);
#endif
if (full_path == NULL) {
return -ENOMEM; return -ENOMEM;
} }
...@@ -494,7 +521,9 @@ static int initiate_cifs_search(const int xid, struct file *file) ...@@ -494,7 +521,9 @@ static int initiate_cifs_search(const int xid, struct file *file)
ffirst_retry: ffirst_retry:
/* test for Unix extensions */ /* test for Unix extensions */
if (pTcon->ses->capabilities & CAP_UNIX) { /* but now check for them on the share/mount not on the SMB session */
/* if (pTcon->ses->capabilities & CAP_UNIX) { */
if (pTcon->unix_ext) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
} else if ((pTcon->ses->capabilities & } else if ((pTcon->ses->capabilities &
(CAP_NT_SMBS | CAP_NT_FIND)) == 0) { (CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
...@@ -505,13 +534,13 @@ ffirst_retry: ...@@ -505,13 +534,13 @@ ffirst_retry:
cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO; cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
} }
rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
&cifsFile->netfid, &cifsFile->srch_inf, &cifsFile->netfid, &cifsFile->srch_inf,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
if(rc == 0) if (rc == 0)
cifsFile->invalidHandle = FALSE; cifsFile->invalidHandle = FALSE;
if((rc == -EOPNOTSUPP) && if ((rc == -EOPNOTSUPP) &&
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
goto ffirst_retry; goto ffirst_retry;
...@@ -526,20 +555,20 @@ static int cifs_unicode_bytelen(char *str) ...@@ -526,20 +555,20 @@ static int cifs_unicode_bytelen(char *str)
int len; int len;
__le16 * ustr = (__le16 *)str; __le16 * ustr = (__le16 *)str;
for(len=0;len <= PATH_MAX;len++) { for (len = 0; len <= PATH_MAX; len++) {
if(ustr[len] == 0) if (ustr[len] == 0)
return len << 1; return len << 1;
} }
cFYI(1,("Unicode string longer than PATH_MAX found")); cFYI(1, ("Unicode string longer than PATH_MAX found"));
return len << 1; return len << 1;
} }
static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
{ {
char * new_entry; char *new_entry;
FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
if(level == SMB_FIND_FILE_INFO_STANDARD) { if (level == SMB_FIND_FILE_INFO_STANDARD) {
FIND_FILE_STANDARD_INFO * pfData; FIND_FILE_STANDARD_INFO * pfData;
pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo; pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
...@@ -547,18 +576,18 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) ...@@ -547,18 +576,18 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
pfData->FileNameLength; pfData->FileNameLength;
} else } else
new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); cFYI(1, ("new entry %p old entry %p", new_entry, old_entry));
/* validate that new_entry is not past end of SMB */ /* validate that new_entry is not past end of SMB */
if(new_entry >= end_of_smb) { if (new_entry >= end_of_smb) {
cERROR(1, cERROR(1,
("search entry %p began after end of SMB %p old entry %p", ("search entry %p began after end of SMB %p old entry %p",
new_entry, end_of_smb, old_entry)); new_entry, end_of_smb, old_entry));
return NULL; return NULL;
} else if(((level == SMB_FIND_FILE_INFO_STANDARD) && } else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
(new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) || (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
((level != SMB_FIND_FILE_INFO_STANDARD) && || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
(new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) { (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) {
cERROR(1,("search entry %p extends after end of SMB %p", cERROR(1, ("search entry %p extends after end of SMB %p",
new_entry, end_of_smb)); new_entry, end_of_smb));
return NULL; return NULL;
} else } else
...@@ -572,69 +601,70 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) ...@@ -572,69 +601,70 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
{ {
int rc = 0; int rc = 0;
char * filename = NULL; char *filename = NULL;
int len = 0; int len = 0;
if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) { if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
if(cfile->srch_inf.unicode) { if (cfile->srch_inf.unicode) {
len = cifs_unicode_bytelen(filename); len = cifs_unicode_bytelen(filename);
} else { } else {
/* BB should we make this strnlen of PATH_MAX? */ /* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, 5); len = strnlen(filename, 5);
} }
} else if(cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) { } else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
FILE_DIRECTORY_INFO * pFindData = FILE_DIRECTORY_INFO * pFindData =
(FILE_DIRECTORY_INFO *)current_entry; (FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
} else if(cfile->srch_inf.info_level == } else if (cfile->srch_inf.info_level ==
SMB_FIND_FILE_FULL_DIRECTORY_INFO) { SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
FILE_FULL_DIRECTORY_INFO * pFindData = FILE_FULL_DIRECTORY_INFO * pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry; (FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
} else if(cfile->srch_inf.info_level == } else if (cfile->srch_inf.info_level ==
SMB_FIND_FILE_ID_FULL_DIR_INFO) { SMB_FIND_FILE_ID_FULL_DIR_INFO) {
SEARCH_ID_FULL_DIR_INFO * pFindData = SEARCH_ID_FULL_DIR_INFO * pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry; (SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
} else if(cfile->srch_inf.info_level == } else if (cfile->srch_inf.info_level ==
SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
FILE_BOTH_DIRECTORY_INFO * pFindData = FILE_BOTH_DIRECTORY_INFO * pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry; (FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
} else if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) { } else if (cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
FIND_FILE_STANDARD_INFO * pFindData = FIND_FILE_STANDARD_INFO * pFindData =
(FIND_FILE_STANDARD_INFO *)current_entry; (FIND_FILE_STANDARD_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = pFindData->FileNameLength;
} else { } else {
cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); cFYI(1, ("Unknown findfirst level %d",
cfile->srch_inf.info_level));
} }
if(filename) { if (filename) {
if(cfile->srch_inf.unicode) { if (cfile->srch_inf.unicode) {
__le16 *ufilename = (__le16 *)filename; __le16 *ufilename = (__le16 *)filename;
if(len == 2) { if (len == 2) {
/* check for . */ /* check for . */
if(ufilename[0] == UNICODE_DOT) if (ufilename[0] == UNICODE_DOT)
rc = 1; rc = 1;
} else if(len == 4) { } else if (len == 4) {
/* check for .. */ /* check for .. */
if((ufilename[0] == UNICODE_DOT) if ((ufilename[0] == UNICODE_DOT)
&&(ufilename[1] == UNICODE_DOT)) && (ufilename[1] == UNICODE_DOT))
rc = 2; rc = 2;
} }
} else /* ASCII */ { } else /* ASCII */ {
if(len == 1) { if (len == 1) {
if(filename[0] == '.') if (filename[0] == '.')
rc = 1; rc = 1;
} else if(len == 2) { } else if (len == 2) {
if((filename[0] == '.') && (filename[1] == '.')) if ((filename[0] == '.') && (filename[1] == '.'))
rc = 2; rc = 2;
} }
} }
...@@ -645,22 +675,16 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) ...@@ -645,22 +675,16 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
/* Check if directory that we are searching has changed so we can decide /* Check if directory that we are searching has changed so we can decide
whether we can use the cached search results from the previous search */ whether we can use the cached search results from the previous search */
static int is_dir_changed(struct file * file) static int is_dir_changed(struct file *file)
{ {
struct inode * inode; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
struct cifsInodeInfo *cifsInfo; struct inode *inode = file->f_dentry->d_inode;
#else
if(file->f_dentry == NULL) struct inode *inode = file->f_path.dentry->d_inode;
return 0; #endif
struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
inode = file->f_dentry->d_inode;
if(inode == NULL)
return 0;
cifsInfo = CIFS_I(inode);
if(cifsInfo->time == 0) if (cifsInfo->time == 0)
return 1; /* directory was changed, perhaps due to unlink */ return 1; /* directory was changed, perhaps due to unlink */
else else
return 0; return 0;
...@@ -680,10 +704,10 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, ...@@ -680,10 +704,10 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
int pos_in_buf = 0; int pos_in_buf = 0;
loff_t first_entry_in_buffer; loff_t first_entry_in_buffer;
loff_t index_to_find = file->f_pos; loff_t index_to_find = file->f_pos;
struct cifsFileInfo * cifsFile = file->private_data; struct cifsFileInfo *cifsFile = file->private_data;
/* check if index in the buffer */ /* check if index in the buffer */
if((cifsFile == NULL) || (ppCurrentEntry == NULL) || if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
(num_to_ret == NULL)) (num_to_ret == NULL))
return -ENOENT; return -ENOENT;
...@@ -701,45 +725,46 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, ...@@ -701,45 +725,46 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
dump_cifs_file_struct(file, "In fce "); dump_cifs_file_struct(file, "In fce ");
#endif #endif
if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
is_dir_changed(file)) || is_dir_changed(file)) ||
(index_to_find < first_entry_in_buffer)) { (index_to_find < first_entry_in_buffer)) {
/* close and restart search */ /* close and restart search */
cFYI(1,("search backing up - close and restart search")); cFYI(1, ("search backing up - close and restart search"));
cifsFile->invalidHandle = TRUE; cifsFile->invalidHandle = TRUE;
CIFSFindClose(xid, pTcon, cifsFile->netfid); CIFSFindClose(xid, pTcon, cifsFile->netfid);
kfree(cifsFile->search_resume_name); kfree(cifsFile->search_resume_name);
cifsFile->search_resume_name = NULL; cifsFile->search_resume_name = NULL;
if(cifsFile->srch_inf.ntwrk_buf_start) { if (cifsFile->srch_inf.ntwrk_buf_start) {
cFYI(1,("freeing SMB ff cache buf on search rewind")); cFYI(1, ("freeing SMB ff cache buf on search rewind"));
if(cifsFile->srch_inf.smallBuf) if (cifsFile->srch_inf.smallBuf)
cifs_small_buf_release(cifsFile->srch_inf. cifs_small_buf_release(cifsFile->srch_inf.
ntwrk_buf_start); ntwrk_buf_start);
else else
cifs_buf_release(cifsFile->srch_inf. cifs_buf_release(cifsFile->srch_inf.
ntwrk_buf_start); ntwrk_buf_start);
} }
rc = initiate_cifs_search(xid,file); rc = initiate_cifs_search(xid, file);
if(rc) { if (rc) {
cFYI(1,("error %d reinitiating a search on rewind",rc)); cFYI(1, ("error %d reinitiating a search on rewind",
rc));
return rc; return rc;
} }
} }
while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
(rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)) {
cFYI(1,("calling findnext2")); cFYI(1, ("calling findnext2"));
rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
&cifsFile->srch_inf); &cifsFile->srch_inf);
if(rc) if (rc)
return -ENOENT; return -ENOENT;
} }
if(index_to_find < cifsFile->srch_inf.index_of_last_entry) { if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
/* we found the buffer that contains the entry */ /* we found the buffer that contains the entry */
/* scan and find it */ /* scan and find it */
int i; int i;
char * current_entry; char *current_entry;
char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
smbCalcSize((struct smb_hdr *) smbCalcSize((struct smb_hdr *)
cifsFile->srch_inf.ntwrk_buf_start); cifsFile->srch_inf.ntwrk_buf_start);
...@@ -747,28 +772,28 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, ...@@ -747,28 +772,28 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
- cifsFile->srch_inf.entries_in_buffer; - cifsFile->srch_inf.entries_in_buffer;
pos_in_buf = index_to_find - first_entry_in_buffer; pos_in_buf = index_to_find - first_entry_in_buffer;
cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); cFYI(1, ("found entry - pos_in_buf %d", pos_in_buf));
for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { for (i=0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
/* go entry by entry figuring out which is first */ /* go entry by entry figuring out which is first */
current_entry = nxt_dir_entry(current_entry,end_of_smb, current_entry = nxt_dir_entry(current_entry, end_of_smb,
cifsFile->srch_inf.info_level); cifsFile->srch_inf.info_level);
} }
if((current_entry == NULL) && (i < pos_in_buf)) { if ((current_entry == NULL) && (i < pos_in_buf)) {
/* BB fixme - check if we should flag this error */ /* BB fixme - check if we should flag this error */
cERROR(1,("reached end of buf searching for pos in buf" cERROR(1, ("reached end of buf searching for pos in buf"
" %d index to find %lld rc %d", " %d index to find %lld rc %d",
pos_in_buf,index_to_find,rc)); pos_in_buf, index_to_find, rc));
} }
rc = 0; rc = 0;
*ppCurrentEntry = current_entry; *ppCurrentEntry = current_entry;
} else { } else {
cFYI(1,("index not in buffer - could not findnext into it")); cFYI(1, ("index not in buffer - could not findnext into it"));
return 0; return 0;
} }
if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
cFYI(1,("can not return entries pos_in_buf beyond last entry")); cFYI(1, ("can not return entries pos_in_buf beyond last"));
*num_to_ret = 0; *num_to_ret = 0;
} else } else
*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
...@@ -779,81 +804,81 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, ...@@ -779,81 +804,81 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
/* inode num, inode type and filename returned */ /* inode num, inode type and filename returned */
static int cifs_get_name_from_search_buf(struct qstr *pqst, static int cifs_get_name_from_search_buf(struct qstr *pqst,
char *current_entry, __u16 level, unsigned int unicode, 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, ino_t *pinum)
{ {
int rc = 0; int rc = 0;
unsigned int len = 0; unsigned int len = 0;
char * filename; char *filename;
struct nls_table * nlt = cifs_sb->local_nls; struct nls_table *nlt = cifs_sb->local_nls;
*pinum = 0; *pinum = 0;
if(level == SMB_FIND_FILE_UNIX) { if (level == SMB_FIND_FILE_UNIX) {
FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
if(unicode) { if (unicode) {
len = cifs_unicode_bytelen(filename); len = cifs_unicode_bytelen(filename);
} else { } else {
/* BB should we make this strnlen of PATH_MAX? */ /* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, PATH_MAX); len = strnlen(filename, PATH_MAX);
} }
/* BB fixme - hash low and high 32 bits if not 64 bit arch BB fixme */ /* BB fixme - hash low and high 32 bits if not 64 bit arch BB */
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
*pinum = pFindData->UniqueId; *pinum = pFindData->UniqueId;
} else if(level == SMB_FIND_FILE_DIRECTORY_INFO) { } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
FILE_DIRECTORY_INFO * pFindData = FILE_DIRECTORY_INFO *pFindData =
(FILE_DIRECTORY_INFO *)current_entry; (FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
} else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
FILE_FULL_DIRECTORY_INFO * pFindData = FILE_FULL_DIRECTORY_INFO *pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry; (FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
} else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
SEARCH_ID_FULL_DIR_INFO * pFindData = SEARCH_ID_FULL_DIR_INFO *pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry; (SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
*pinum = pFindData->UniqueId; *pinum = pFindData->UniqueId;
} else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
FILE_BOTH_DIRECTORY_INFO * pFindData = FILE_BOTH_DIRECTORY_INFO *pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry; (FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
} else if(level == SMB_FIND_FILE_INFO_STANDARD) { } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
FIND_FILE_STANDARD_INFO * pFindData = FIND_FILE_STANDARD_INFO * pFindData =
(FIND_FILE_STANDARD_INFO *)current_entry; (FIND_FILE_STANDARD_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
/* one byte length, no name conversion */ /* one byte length, no name conversion */
len = (unsigned int)pFindData->FileNameLength; len = (unsigned int)pFindData->FileNameLength;
} else { } else {
cFYI(1,("Unknown findfirst level %d",level)); cFYI(1, ("Unknown findfirst level %d", level));
return -EINVAL; return -EINVAL;
} }
if(len > max_len) { if (len > max_len) {
cERROR(1,("bad search response length %d past smb end", len)); cERROR(1, ("bad search response length %d past smb end", len));
return -EINVAL; return -EINVAL;
} }
if(unicode) { if (unicode) {
/* BB fixme - test with long names */ /* BB fixme - test with long names */
/* Note converted filename can be longer than in unicode */ /* Note converted filename can be longer than in unicode */
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
pqst->len = cifs_convertUCSpath((char *)pqst->name, pqst->len = cifs_convertUCSpath((char *)pqst->name,
(__le16 *)filename, len/2, nlt); (__le16 *)filename, len/2, nlt);
else else
pqst->len = cifs_strfromUCS_le((char *)pqst->name, pqst->len = cifs_strfromUCS_le((char *)pqst->name,
(__le16 *)filename,len/2,nlt); (__le16 *)filename, len/2, nlt);
} else { } else {
pqst->name = filename; pqst->name = filename;
pqst->len = len; pqst->len = len;
} }
pqst->hash = full_name_hash(pqst->name,pqst->len); pqst->hash = full_name_hash(pqst->name, pqst->len);
/* cFYI(1,("filldir on %s",pqst->name)); */ /* cFYI(1, ("filldir on %s",pqst->name)); */
return rc; return rc;
} }
...@@ -862,52 +887,54 @@ static int cifs_filldir(char *pfindEntry, struct file *file, ...@@ -862,52 +887,54 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
{ {
int rc = 0; int rc = 0;
struct qstr qstring; struct qstr qstring;
struct cifsFileInfo * pCifsF; struct cifsFileInfo *pCifsF;
unsigned obj_type; unsigned obj_type;
ino_t inum; ino_t inum;
struct cifs_sb_info * cifs_sb; struct cifs_sb_info *cifs_sb;
struct inode *tmp_inode; struct inode *tmp_inode;
struct dentry *tmp_dentry; struct dentry *tmp_dentry;
/* get filename and len into qstring */ /* get filename and len into qstring */
/* get dentry */ /* get dentry */
/* decide whether to create and populate ionde */ /* decide whether to create and populate ionde */
if((direntry == NULL) || (file == NULL)) if ((direntry == NULL) || (file == NULL))
return -EINVAL; return -EINVAL;
pCifsF = file->private_data; pCifsF = file->private_data;
if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL)) if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
return -ENOENT; return -ENOENT;
if(file->f_dentry == NULL) rc = cifs_entry_is_dot(pfindEntry, pCifsF);
return -ENOENT;
rc = cifs_entry_is_dot(pfindEntry,pCifsF);
/* skip . and .. since we added them first */ /* skip . and .. since we added them first */
if(rc != 0) if (rc != 0)
return 0; return 0;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
#else
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
#endif
qstring.name = scratch_buf; qstring.name = scratch_buf;
rc = cifs_get_name_from_search_buf(&qstring,pfindEntry, rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
pCifsF->srch_inf.info_level, pCifsF->srch_inf.info_level,
pCifsF->srch_inf.unicode,cifs_sb, pCifsF->srch_inf.unicode, cifs_sb,
max_len, max_len,
&inum /* returned */); &inum /* returned */);
if(rc) if (rc)
return rc; return rc;
rc = construct_dentry(&qstring,file,&tmp_inode, &tmp_dentry); rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry);
if((tmp_inode == NULL) || (tmp_dentry == NULL)) if ((tmp_inode == NULL) || (tmp_dentry == NULL))
return -ENOMEM; return -ENOMEM;
if(rc) { if (rc) {
/* inode created, we need to hash it with right inode number */ /* inode created, we need to hash it with right inode number */
if(inum != 0) { if (inum != 0) {
/* BB fixme - hash the 2 32 quantities bits together if necessary BB */ /* BB fixme - hash the 2 32 quantities bits together if
* necessary BB */
tmp_inode->i_ino = inum; tmp_inode->i_ino = inum;
} }
insert_inode_hash(tmp_inode); insert_inode_hash(tmp_inode);
...@@ -916,27 +943,27 @@ static int cifs_filldir(char *pfindEntry, struct file *file, ...@@ -916,27 +943,27 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
/* we pass in rc below, indicating whether it is a new inode, /* we pass in rc below, indicating whether it is a new inode,
so we can figure out whether to invalidate the inode cached so we can figure out whether to invalidate the inode cached
data if the file has changed */ data if the file has changed */
if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
unix_fill_in_inode(tmp_inode, unix_fill_in_inode(tmp_inode,
(FILE_UNIX_INFO *)pfindEntry, (FILE_UNIX_INFO *)pfindEntry,
&obj_type, rc); &obj_type, rc);
else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */, fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
pfindEntry, &obj_type, rc); pfindEntry, &obj_type, rc);
else else
fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
if(rc) /* new inode - needs to be tied to dentry */ { if (rc) /* new inode - needs to be tied to dentry */ {
d_instantiate(tmp_dentry, tmp_inode); d_instantiate(tmp_dentry, tmp_inode);
if(rc == 2) if (rc == 2)
d_rehash(tmp_dentry); d_rehash(tmp_dentry);
} }
rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
tmp_inode->i_ino,obj_type); tmp_inode->i_ino, obj_type);
if(rc) { if (rc) {
cFYI(1,("filldir rc = %d",rc)); cFYI(1, ("filldir rc = %d", rc));
/* we can not return filldir errors to the caller /* we can not return filldir errors to the caller
since they are "normal" when the stat blocksize since they are "normal" when the stat blocksize
is too small - we return remapped error instead */ is too small - we return remapped error instead */
...@@ -953,57 +980,57 @@ static int cifs_save_resume_key(const char *current_entry, ...@@ -953,57 +980,57 @@ static int cifs_save_resume_key(const char *current_entry,
int rc = 0; int rc = 0;
unsigned int len = 0; unsigned int len = 0;
__u16 level; __u16 level;
char * filename; char *filename;
if((cifsFile == NULL) || (current_entry == NULL)) if ((cifsFile == NULL) || (current_entry == NULL))
return -EINVAL; return -EINVAL;
level = cifsFile->srch_inf.info_level; level = cifsFile->srch_inf.info_level;
if(level == SMB_FIND_FILE_UNIX) { if (level == SMB_FIND_FILE_UNIX) {
FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
if(cifsFile->srch_inf.unicode) { if (cifsFile->srch_inf.unicode) {
len = cifs_unicode_bytelen(filename); len = cifs_unicode_bytelen(filename);
} else { } else {
/* BB should we make this strnlen of PATH_MAX? */ /* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, PATH_MAX); len = strnlen(filename, PATH_MAX);
} }
cifsFile->srch_inf.resume_key = pFindData->ResumeKey; cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
} else if(level == SMB_FIND_FILE_DIRECTORY_INFO) { } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
FILE_DIRECTORY_INFO * pFindData = FILE_DIRECTORY_INFO *pFindData =
(FILE_DIRECTORY_INFO *)current_entry; (FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex; cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) { } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
FILE_FULL_DIRECTORY_INFO * pFindData = FILE_FULL_DIRECTORY_INFO *pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry; (FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex; cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) { } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
SEARCH_ID_FULL_DIR_INFO * pFindData = SEARCH_ID_FULL_DIR_INFO *pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry; (SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex; cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
FILE_BOTH_DIRECTORY_INFO * pFindData = FILE_BOTH_DIRECTORY_INFO *pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry; (FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength); len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex; cifsFile->srch_inf.resume_key = pFindData->FileIndex;
} else if(level == SMB_FIND_FILE_INFO_STANDARD) { } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
FIND_FILE_STANDARD_INFO * pFindData = FIND_FILE_STANDARD_INFO *pFindData =
(FIND_FILE_STANDARD_INFO *)current_entry; (FIND_FILE_STANDARD_INFO *)current_entry;
filename = &pFindData->FileName[0]; filename = &pFindData->FileName[0];
/* one byte length, no name conversion */ /* one byte length, no name conversion */
len = (unsigned int)pFindData->FileNameLength; len = (unsigned int)pFindData->FileNameLength;
cifsFile->srch_inf.resume_key = pFindData->ResumeKey; cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
} else { } else {
cFYI(1,("Unknown findfirst level %d",level)); cFYI(1, ("Unknown findfirst level %d", level));
return -EINVAL; return -EINVAL;
} }
cifsFile->srch_inf.resume_name_len = len; cifsFile->srch_inf.resume_name_len = len;
...@@ -1014,26 +1041,22 @@ static int cifs_save_resume_key(const char *current_entry, ...@@ -1014,26 +1041,22 @@ static int cifs_save_resume_key(const char *current_entry,
int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
{ {
int rc = 0; int rc = 0;
int xid,i; int xid, i;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct cifsFileInfo *cifsFile = NULL; struct cifsFileInfo *cifsFile = NULL;
char * current_entry; char *current_entry;
int num_to_fill = 0; int num_to_fill = 0;
char * tmp_buf = NULL; char *tmp_buf = NULL;
char * end_of_smb; char *end_of_smb;
int max_len; int max_len;
xid = GetXid(); xid = GetXid();
if(file->f_dentry == NULL) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
FreeXid(xid);
return -EIO;
}
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if(pTcon == NULL) if (pTcon == NULL)
return -EINVAL; return -EINVAL;
switch ((int) file->f_pos) { switch ((int) file->f_pos) {
...@@ -1048,6 +1071,25 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1048,6 +1071,25 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
case 1: case 1:
if (filldir(direntry, "..", 2, file->f_pos, if (filldir(direntry, "..", 2, file->f_pos,
file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
#else
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if (pTcon == NULL)
return -EINVAL;
switch ((int) file->f_pos) {
case 0:
if (filldir(direntry, ".", 1, file->f_pos,
file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) {
cERROR(1, ("Filldir for current dir failed"));
rc = -ENOMEM;
break;
}
file->f_pos++;
case 1:
if (filldir(direntry, "..", 2, file->f_pos,
file->f_path.dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
#endif
cERROR(1, ("Filldir for parent dir failed")); cERROR(1, ("Filldir for parent dir failed"));
rc = -ENOMEM; rc = -ENOMEM;
break; break;
...@@ -1059,22 +1101,22 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1059,22 +1101,22 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
if it before then restart search if it before then restart search
if after then keep searching till find it */ if after then keep searching till find it */
if(file->private_data == NULL) { if (file->private_data == NULL) {
rc = initiate_cifs_search(xid,file); rc = initiate_cifs_search(xid, file);
cFYI(1,("initiate cifs search rc %d",rc)); cFYI(1, ("initiate cifs search rc %d", rc));
if(rc) { if (rc) {
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
} }
if(file->private_data == NULL) { if (file->private_data == NULL) {
rc = -EINVAL; rc = -EINVAL;
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
cifsFile = file->private_data; cifsFile = file->private_data;
if (cifsFile->srch_inf.endOfSearch) { if (cifsFile->srch_inf.endOfSearch) {
if(cifsFile->srch_inf.emptyDir) { if (cifsFile->srch_inf.emptyDir) {
cFYI(1, ("End of search, empty dir")); cFYI(1, ("End of search, empty dir"));
rc = 0; rc = 0;
break; break;
...@@ -1086,19 +1128,19 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1086,19 +1128,19 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
kfree(cifsFile->search_resume_name); kfree(cifsFile->search_resume_name);
cifsFile->search_resume_name = NULL; */ cifsFile->search_resume_name = NULL; */
rc = find_cifs_entry(xid,pTcon, file, rc = find_cifs_entry(xid, pTcon, file,
&current_entry,&num_to_fill); &current_entry, &num_to_fill);
if(rc) { if (rc) {
cFYI(1,("fce error %d",rc)); cFYI(1, ("fce error %d", rc));
goto rddir2_exit; goto rddir2_exit;
} else if (current_entry != NULL) { } else if (current_entry != NULL) {
cFYI(1,("entry %lld found",file->f_pos)); cFYI(1, ("entry %lld found", file->f_pos));
} else { } else {
cFYI(1,("could not find entry")); cFYI(1, ("could not find entry"));
goto rddir2_exit; goto rddir2_exit;
} }
cFYI(1,("loop through %d times filling dir for net buf %p", cFYI(1, ("loop through %d times filling dir for net buf %p",
num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); num_to_fill, cifsFile->srch_inf.ntwrk_buf_start));
max_len = smbCalcSize((struct smb_hdr *) max_len = smbCalcSize((struct smb_hdr *)
cifsFile->srch_inf.ntwrk_buf_start); cifsFile->srch_inf.ntwrk_buf_start);
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
...@@ -1108,10 +1150,10 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1108,10 +1150,10 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
such multibyte target UTF-8 characters. cifs_unicode.c, such multibyte target UTF-8 characters. cifs_unicode.c,
which actually does the conversion, has the same limit */ which actually does the conversion, has the same limit */
tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL);
for(i=0;(i<num_to_fill) && (rc == 0);i++) { for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
if(current_entry == NULL) { if (current_entry == NULL) {
/* evaluate whether this case is an error */ /* evaluate whether this case is an error */
cERROR(1,("past end of SMB num to fill %d i %d", cERROR(1, ("past SMB end, num to fill %d i %d",
num_to_fill, i)); num_to_fill, i));
break; break;
} }
...@@ -1119,17 +1161,17 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ...@@ -1119,17 +1161,17 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
we want to check for that here? */ we want to check for that here? */
rc = cifs_filldir(current_entry, file, rc = cifs_filldir(current_entry, file,
filldir, direntry, tmp_buf, max_len); filldir, direntry, tmp_buf, max_len);
if(rc == -EOVERFLOW) { if (rc == -EOVERFLOW) {
rc = 0; rc = 0;
break; break;
} }
file->f_pos++; file->f_pos++;
if(file->f_pos == if (file->f_pos ==
cifsFile->srch_inf.index_of_last_entry) { cifsFile->srch_inf.index_of_last_entry) {
cFYI(1,("last entry in buf at pos %lld %s", cFYI(1, ("last entry in buf at pos %lld %s",
file->f_pos,tmp_buf)); file->f_pos, tmp_buf));
cifs_save_resume_key(current_entry,cifsFile); cifs_save_resume_key(current_entry, cifsFile);
break; break;
} else } else
current_entry = current_entry =
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* SMB/CIFS session setup handling routines * SMB/CIFS session setup handling routines
* *
* Copyright (c) International Business Machines Corp., 2006 * Copyright (c) International Business Machines Corp., 2006, 2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -52,7 +52,8 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) ...@@ -52,7 +52,8 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) if (ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
if (ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
...@@ -67,18 +68,17 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) ...@@ -67,18 +68,17 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
pSMB->req.hdr.Flags2 |= SMBFLG2_DFS; pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
capabilities |= CAP_DFS; capabilities |= CAP_DFS;
} }
if (ses->capabilities & CAP_UNIX) { if (ses->capabilities & CAP_UNIX)
capabilities |= CAP_UNIX; capabilities |= CAP_UNIX;
}
/* BB check whether to init vcnum BB */ /* BB check whether to init vcnum BB */
return capabilities; return capabilities;
} }
static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
const struct nls_table * nls_cp) const struct nls_table *nls_cp)
{ {
char * bcc_ptr = *pbcc_area; char *bcc_ptr = *pbcc_area;
int bytes_ret = 0; int bytes_ret = 0;
/* BB FIXME add check that strings total less /* BB FIXME add check that strings total less
...@@ -90,7 +90,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, ...@@ -90,7 +90,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
bcc_ptr++; bcc_ptr++;
} */ } */
/* copy user */ /* copy user */
if(ses->userName == NULL) { if (ses->userName == NULL) {
/* null user mount */ /* null user mount */
*bcc_ptr = 0; *bcc_ptr = 0;
*(bcc_ptr+1) = 0; *(bcc_ptr+1) = 0;
...@@ -101,7 +101,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, ...@@ -101,7 +101,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
bcc_ptr += 2 * bytes_ret; bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* account for null termination */ bcc_ptr += 2; /* account for null termination */
/* copy domain */ /* copy domain */
if(ses->domainName == NULL) { if (ses->domainName == NULL) {
/* Sending null domain better than using a bogus domain name (as /* Sending null domain better than using a bogus domain name (as
we did briefly in 2.6.18) since server will use its default */ we did briefly in 2.6.18) since server will use its default */
*bcc_ptr = 0; *bcc_ptr = 0;
...@@ -118,7 +118,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, ...@@ -118,7 +118,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
nls_cp); nls_cp);
bcc_ptr += 2 * bytes_ret; bcc_ptr += 2 * bytes_ret;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release,
32, nls_cp); 32, nls_cp);
#else #else
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
...@@ -135,15 +135,15 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, ...@@ -135,15 +135,15 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
*pbcc_area = bcc_ptr; *pbcc_area = bcc_ptr;
} }
static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
const struct nls_table * nls_cp) const struct nls_table *nls_cp)
{ {
char * bcc_ptr = *pbcc_area; char *bcc_ptr = *pbcc_area;
/* copy user */ /* copy user */
/* BB what about null user mounts - check that we do this BB */ /* BB what about null user mounts - check that we do this BB */
/* copy user */ /* copy user */
if(ses->userName == NULL) { if (ses->userName == NULL) {
/* BB what about null user mounts - check that we do this BB */ /* BB what about null user mounts - check that we do this BB */
} else { /* 300 should be long enough for any conceivable user name */ } else { /* 300 should be long enough for any conceivable user name */
strncpy(bcc_ptr, ses->userName, 300); strncpy(bcc_ptr, ses->userName, 300);
...@@ -155,7 +155,7 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, ...@@ -155,7 +155,7 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
/* copy domain */ /* copy domain */
if(ses->domainName != NULL) { if (ses->domainName != NULL) {
strncpy(bcc_ptr, ses->domainName, 256); strncpy(bcc_ptr, ses->domainName, 256);
bcc_ptr += strnlen(ses->domainName, 256); bcc_ptr += strnlen(ses->domainName, 256);
} /* else we will send a null domain name } /* else we will send a null domain name
...@@ -168,29 +168,29 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, ...@@ -168,29 +168,29 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
strcpy(bcc_ptr, "Linux version "); strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version "); bcc_ptr += strlen("Linux version ");
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18)
strcpy(bcc_ptr, utsname()->release); strcpy(bcc_ptr, init_utsname()->release);
bcc_ptr += strlen(utsname()->release) + 1; bcc_ptr += strlen(init_utsname()->release) + 1;
#else #else
strcpy(bcc_ptr, system_utsname.release); strcpy(bcc_ptr, system_utsname.release);
bcc_ptr += strlen(system_utsname.release) + 1; bcc_ptr += strlen(system_utsname.release) + 1;
#endif #endif
strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
*pbcc_area = bcc_ptr; *pbcc_area = bcc_ptr;
} }
static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, static int decode_unicode_ssetup(char **pbcc_area, int bleft,
const struct nls_table * nls_cp) struct cifsSesInfo *ses,
const struct nls_table *nls_cp)
{ {
int rc = 0; int rc = 0;
int words_left, len; int words_left, len;
char * data = *pbcc_area; char *data = *pbcc_area;
cFYI(1,("bleft %d",bleft)); cFYI(1, ("bleft %d", bleft));
/* SMB header is unaligned, so cifs servers word align start of /* SMB header is unaligned, so cifs servers word align start of
...@@ -209,34 +209,30 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf ...@@ -209,34 +209,30 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
/* We look for obvious messed up bcc or strings in response so we do not go off /* We look for obvious messed up bcc or strings in response so we do not go off
the end since (at least) WIN2K and Windows XP have a major bug in not null the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */ terminating last Unicode string in response */
if(len >= words_left) if (len >= words_left)
return rc; return rc;
if(ses->serverOS)
kfree(ses->serverOS); kfree(ses->serverOS);
/* UTF-8 string will not grow more than four times as big as UCS-16 */ /* 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, GFP_KERNEL);
if(ses->serverOS != NULL) { if (ses->serverOS != NULL)
cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp);
nls_cp);
}
data += 2 * (len + 1); data += 2 * (len + 1);
words_left -= len + 1; words_left -= len + 1;
/* save off server network operating system */ /* save off server network operating system */
len = UniStrnlen((wchar_t *) data, words_left); len = UniStrnlen((wchar_t *) data, words_left);
if(len >= words_left) if (len >= words_left)
return rc; return rc;
if(ses->serverNOS)
kfree(ses->serverNOS); kfree(ses->serverNOS);
ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */ ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
if(ses->serverNOS != NULL) { if (ses->serverNOS != NULL) {
cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
nls_cp); nls_cp);
if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) { if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) {
cFYI(1,("NT4 server")); cFYI(1, ("NT4 server"));
ses->flags |= CIFS_SES_NT4; ses->flags |= CIFS_SES_NT4;
} }
} }
...@@ -246,13 +242,12 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf ...@@ -246,13 +242,12 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
/* save off server domain */ /* save off server domain */
len = UniStrnlen((wchar_t *) data, words_left); len = UniStrnlen((wchar_t *) data, words_left);
if(len > words_left) if (len > words_left)
return rc; return rc;
if(ses->serverDomain)
kfree(ses->serverDomain); kfree(ses->serverDomain);
ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
if(ses->serverDomain != NULL) { if (ses->serverDomain != NULL) {
cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
nls_cp); nls_cp);
ses->serverDomain[2*len] = 0; ses->serverDomain[2*len] = 0;
...@@ -261,32 +256,32 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf ...@@ -261,32 +256,32 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
data += 2 * (len + 1); data += 2 * (len + 1);
words_left -= len + 1; words_left -= len + 1;
cFYI(1,("words left: %d",words_left)); cFYI(1, ("words left: %d", words_left));
return rc; return rc;
} }
static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, static int decode_ascii_ssetup(char **pbcc_area, int bleft,
const struct nls_table * nls_cp) struct cifsSesInfo *ses,
const struct nls_table *nls_cp)
{ {
int rc = 0; int rc = 0;
int len; int len;
char * bcc_ptr = *pbcc_area; char *bcc_ptr = *pbcc_area;
cFYI(1,("decode sessetup ascii. bleft %d", bleft)); cFYI(1, ("decode sessetup ascii. bleft %d", bleft));
len = strnlen(bcc_ptr, bleft); len = strnlen(bcc_ptr, bleft);
if(len >= bleft) if (len >= bleft)
return rc; return rc;
if(ses->serverOS)
kfree(ses->serverOS); kfree(ses->serverOS);
ses->serverOS = kzalloc(len + 1, GFP_KERNEL); ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
if(ses->serverOS) if (ses->serverOS)
strncpy(ses->serverOS, bcc_ptr, len); strncpy(ses->serverOS, bcc_ptr, len);
if(strncmp(ses->serverOS, "OS/2",4) == 0) { if (strncmp(ses->serverOS, "OS/2", 4) == 0) {
cFYI(1,("OS/2 server")); cFYI(1, ("OS/2 server"));
ses->flags |= CIFS_SES_OS2; ses->flags |= CIFS_SES_OS2;
} }
...@@ -294,21 +289,20 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo ...@@ -294,21 +289,20 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo
bleft -= len + 1; bleft -= len + 1;
len = strnlen(bcc_ptr, bleft); len = strnlen(bcc_ptr, bleft);
if(len >= bleft) if (len >= bleft)
return rc; return rc;
if(ses->serverNOS)
kfree(ses->serverNOS); kfree(ses->serverNOS);
ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
if(ses->serverNOS) if (ses->serverNOS)
strncpy(ses->serverNOS, bcc_ptr, len); strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len + 1; bcc_ptr += len + 1;
bleft -= len + 1; bleft -= len + 1;
len = strnlen(bcc_ptr, bleft); len = strnlen(bcc_ptr, bleft);
if(len > bleft) if (len > bleft)
return rc; return rc;
/* No domain field in LANMAN case. Domain is /* No domain field in LANMAN case. Domain is
...@@ -316,7 +310,7 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo ...@@ -316,7 +310,7 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo
/* BB For newer servers which do not support Unicode, /* BB For newer servers which do not support Unicode,
but thus do return domain here we could add parsing but thus do return domain here we could add parsing
for it later, but it is not very important */ for it later, but it is not very important */
cFYI(1,("ascii: bytes left %d",bleft)); cFYI(1, ("ascii: bytes left %d", bleft));
return rc; return rc;
} }
...@@ -339,13 +333,13 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -339,13 +333,13 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
__u16 action; __u16 action;
int bytes_remaining; int bytes_remaining;
if(ses == NULL) if (ses == NULL)
return -EINVAL; return -EINVAL;
type = ses->server->secType; type = ses->server->secType;
cFYI(1,("sess setup type %d",type)); cFYI(1, ("sess setup type %d", type));
if(type == LANMAN) { if (type == LANMAN) {
#ifndef CONFIG_CIFS_WEAK_PW_HASH #ifndef CONFIG_CIFS_WEAK_PW_HASH
/* LANMAN and plaintext are less secure and off by default. /* LANMAN and plaintext are less secure and off by default.
So we make this explicitly be turned on in kconfig (in the So we make this explicitly be turned on in kconfig (in the
...@@ -355,15 +349,15 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -355,15 +349,15 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
return -EOPNOTSUPP; return -EOPNOTSUPP;
#endif #endif
wct = 10; /* lanman 2 style sessionsetup */ wct = 10; /* lanman 2 style sessionsetup */
} else if((type == NTLM) || (type == NTLMv2)) { } else if ((type == NTLM) || (type == NTLMv2)) {
/* For NTLMv2 failures eventually may need to retry NTLM */ /* For NTLMv2 failures eventually may need to retry NTLM */
wct = 13; /* old style NTLM sessionsetup */ wct = 13; /* old style NTLM sessionsetup */
} else /* same size for negotiate or auth, NTLMSSP or extended security */ } else /* same size: negotiate or auth, NTLMSSP or extended security */
wct = 12; wct = 12;
rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
(void **)&smb_buf); (void **)&smb_buf);
if(rc) if (rc)
return rc; return rc;
pSMB = (SESSION_SETUP_ANDX *)smb_buf; pSMB = (SESSION_SETUP_ANDX *)smb_buf;
...@@ -380,17 +374,21 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -380,17 +374,21 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
/* 2000 big enough to fit max user, domain, NOS name etc. */ /* 2000 big enough to fit max user, domain, NOS name etc. */
str_area = kmalloc(2000, GFP_KERNEL); str_area = kmalloc(2000, GFP_KERNEL);
if (str_area == NULL) {
cifs_small_buf_release(smb_buf);
return -ENOMEM;
}
bcc_ptr = str_area; bcc_ptr = str_area;
ses->flags &= ~CIFS_SES_LANMAN; ses->flags &= ~CIFS_SES_LANMAN;
if(type == LANMAN) { if (type == LANMAN) {
#ifdef CONFIG_CIFS_WEAK_PW_HASH #ifdef CONFIG_CIFS_WEAK_PW_HASH
char lnm_session_key[CIFS_SESS_KEY_SIZE]; char lnm_session_key[CIFS_SESS_KEY_SIZE];
/* no capabilities flags in old lanman negotiation */ /* no capabilities flags in old lanman negotiation */
pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE; pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
/* BB calculate hash with password */ /* BB calculate hash with password */
/* and copy into bcc */ /* and copy into bcc */
...@@ -408,7 +406,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -408,7 +406,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
changed to do higher than lanman dialect and changed to do higher than lanman dialect and
we reconnected would we ever calc signing_key? */ we reconnected would we ever calc signing_key? */
cFYI(1,("Negotiating LANMAN setting up strings")); cFYI(1, ("Negotiating LANMAN setting up strings"));
/* Unicode not allowed for LANMAN dialects */ /* Unicode not allowed for LANMAN dialects */
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
#endif #endif
...@@ -425,17 +423,17 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -425,17 +423,17 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
SMBNTencrypt(ses->password, ses->server->cryptKey, SMBNTencrypt(ses->password, ses->server->cryptKey,
ntlm_session_key); ntlm_session_key);
if(first_time) /* should this be moved into common code if (first_time) /* should this be moved into common code
with similar ntlmv2 path? */ with similar ntlmv2 path? */
cifs_calculate_mac_key(ses->server->mac_signing_key, cifs_calculate_mac_key(&ses->server->mac_signing_key,
ntlm_session_key, ses->password); ntlm_session_key, ses->password);
/* copy session key */ /* copy session key */
memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE);
bcc_ptr += CIFS_SESS_KEY_SIZE; bcc_ptr += CIFS_SESS_KEY_SIZE;
memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE);
bcc_ptr += CIFS_SESS_KEY_SIZE; bcc_ptr += CIFS_SESS_KEY_SIZE;
if(ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
/* unicode strings must be word aligned */ /* unicode strings must be word aligned */
if (iov[0].iov_len % 2) { if (iov[0].iov_len % 2) {
*bcc_ptr = 0; *bcc_ptr = 0;
...@@ -445,13 +443,13 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -445,13 +443,13 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
} else } else
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
} else if (type == NTLMv2) { } else if (type == NTLMv2) {
char * v2_sess_key = char *v2_sess_key =
kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL); kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL);
/* BB FIXME change all users of v2_sess_key to /* BB FIXME change all users of v2_sess_key to
struct ntlmv2_resp */ struct ntlmv2_resp */
if(v2_sess_key == NULL) { if (v2_sess_key == NULL) {
cifs_small_buf_release(smb_buf); cifs_small_buf_release(smb_buf);
return -ENOMEM; return -ENOMEM;
} }
...@@ -467,7 +465,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -467,7 +465,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
/* calculate session key */ /* calculate session key */
setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
if(first_time) /* should this be moved into common code if (first_time) /* should this be moved into common code
with similar ntlmv2 path? */ with similar ntlmv2 path? */
/* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key,
response BB FIXME, v2_sess_key); */ response BB FIXME, v2_sess_key); */
...@@ -476,13 +474,15 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -476,13 +474,15 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
/* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE); /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE);
bcc_ptr += LM2_SESS_KEY_SIZE; */ bcc_ptr += LM2_SESS_KEY_SIZE; */
memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp)); memcpy(bcc_ptr, (char *)v2_sess_key,
sizeof(struct ntlmv2_resp));
bcc_ptr += sizeof(struct ntlmv2_resp); bcc_ptr += sizeof(struct ntlmv2_resp);
kfree(v2_sess_key); kfree(v2_sess_key);
if(ses->capabilities & CAP_UNICODE) { if (ses->capabilities & CAP_UNICODE) {
if(iov[0].iov_len % 2) { if (iov[0].iov_len % 2) {
*bcc_ptr = 0; *bcc_ptr = 0;
} bcc_ptr++; bcc_ptr++;
}
unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
} else } else
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
...@@ -503,16 +503,16 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -503,16 +503,16 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0); rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0);
/* SMB request buf freed in SendReceive2 */ /* SMB request buf freed in SendReceive2 */
cFYI(1,("ssetup rc from sendrecv2 is %d",rc)); cFYI(1, ("ssetup rc from sendrecv2 is %d", rc));
if(rc) if (rc)
goto ssetup_exit; goto ssetup_exit;
pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
smb_buf = (struct smb_hdr *)iov[0].iov_base; smb_buf = (struct smb_hdr *)iov[0].iov_base;
if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
rc = -EIO; rc = -EIO;
cERROR(1,("bad word count %d", smb_buf->WordCount)); cERROR(1, ("bad word count %d", smb_buf->WordCount));
goto ssetup_exit; goto ssetup_exit;
} }
action = le16_to_cpu(pSMB->resp.Action); action = le16_to_cpu(pSMB->resp.Action);
...@@ -525,12 +525,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -525,12 +525,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
bytes_remaining = BCC(smb_buf); bytes_remaining = BCC(smb_buf);
bcc_ptr = pByteArea(smb_buf); bcc_ptr = pByteArea(smb_buf);
if(smb_buf->WordCount == 4) { if (smb_buf->WordCount == 4) {
__u16 blob_len; __u16 blob_len;
blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
bcc_ptr += blob_len; bcc_ptr += blob_len;
if(blob_len > bytes_remaining) { if (blob_len > bytes_remaining) {
cERROR(1,("bad security blob length %d", blob_len)); cERROR(1, ("bad security blob length %d", blob_len));
rc = -EINVAL; rc = -EINVAL;
goto ssetup_exit; goto ssetup_exit;
} }
...@@ -538,18 +538,19 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ...@@ -538,18 +538,19 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
} }
/* BB check if Unicode and decode strings */ /* BB check if Unicode and decode strings */
if(smb_buf->Flags2 & SMBFLG2_UNICODE) if (smb_buf->Flags2 & SMBFLG2_UNICODE)
rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
ses, nls_cp); ses, nls_cp);
else else
rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp); rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining,
ses, nls_cp);
ssetup_exit: ssetup_exit:
kfree(str_area); kfree(str_area);
if(resp_buf_type == CIFS_SMALL_BUFFER) { if (resp_buf_type == CIFS_SMALL_BUFFER) {
cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base)); cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base));
cifs_small_buf_release(iov[0].iov_base); cifs_small_buf_release(iov[0].iov_base);
} else if(resp_buf_type == CIFS_LARGE_BUFFER) } else if (resp_buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(iov[0].iov_base); cifs_buf_release(iov[0].iov_base);
return rc; return rc;
......
...@@ -153,7 +153,7 @@ static uchar sbox[8][4][16] = { ...@@ -153,7 +153,7 @@ static uchar sbox[8][4][16] = {
}; };
static void static void
permute(char *out, char *in, uchar * p, int n) permute(char *out, char *in, uchar *p, int n)
{ {
int i; int i;
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
...@@ -202,18 +202,18 @@ dohash(char *out, char *in, char *key, int forw) ...@@ -202,18 +202,18 @@ dohash(char *out, char *in, char *key, int forw)
char *rl; char *rl;
/* Have to reduce stack usage */ /* Have to reduce stack usage */
pk1 = kmalloc(56+56+64+64,GFP_KERNEL); pk1 = kmalloc(56+56+64+64, GFP_KERNEL);
if(pk1 == NULL) if (pk1 == NULL)
return; return;
ki = kmalloc(16*48, GFP_KERNEL); ki = kmalloc(16*48, GFP_KERNEL);
if(ki == NULL) { if (ki == NULL) {
kfree(pk1); kfree(pk1);
return; return;
} }
cd = pk1 + 56; cd = pk1 + 56;
pd1= cd + 56; pd1 = cd + 56;
rl = pd1 + 64; rl = pd1 + 64;
permute(pk1, key, perm1, 56); permute(pk1, key, perm1, 56);
...@@ -247,7 +247,7 @@ dohash(char *out, char *in, char *key, int forw) ...@@ -247,7 +247,7 @@ dohash(char *out, char *in, char *key, int forw)
char *r2; /* r2[32] */ char *r2; /* r2[32] */
er = kmalloc(48+48+32+32+32, GFP_KERNEL); er = kmalloc(48+48+32+32+32, GFP_KERNEL);
if(er == NULL) { if (er == NULL) {
kfree(pk1); kfree(pk1);
kfree(ki); kfree(ki);
return; return;
...@@ -327,8 +327,8 @@ smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw) ...@@ -327,8 +327,8 @@ smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
char *keyb; /* keyb[64] */ char *keyb; /* keyb[64] */
unsigned char key2[8]; unsigned char key2[8];
outb = kmalloc(64 * 3,GFP_KERNEL); outb = kmalloc(64 * 3, GFP_KERNEL);
if(outb == NULL) if (outb == NULL)
return; return;
inb = outb + 64; inb = outb + 64;
...@@ -372,20 +372,20 @@ E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) ...@@ -372,20 +372,20 @@ E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
smbhash(p24 + 16, c8, p21 + 14, 1); smbhash(p24 + 16, c8, p21 + 14, 1);
} }
void #if 0 /* currently unsued */
static void
D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
{ {
smbhash(out, in, p14, 0); smbhash(out, in, p14, 0);
smbhash(out + 8, in + 8, p14 + 7, 0); smbhash(out + 8, in + 8, p14 + 7, 0);
} }
void static void
E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out)
{ {
smbhash(out, in, p14, 1); smbhash(out, in, p14, 1);
smbhash(out + 8, in + 8, p14 + 7, 1); smbhash(out + 8, in + 8, p14 + 7, 1);
} }
#if 0
/* these routines are currently unneeded, but may be /* these routines are currently unneeded, but may be
needed later */ needed later */
void void
......
...@@ -51,11 +51,8 @@ ...@@ -51,11 +51,8 @@
void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
void E_md4hash(const unsigned char *passwd, unsigned char *p16); void E_md4hash(const unsigned char *passwd, unsigned char *p16);
void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]);
static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
unsigned char p24[24]); unsigned char p24[24]);
void NTLMSSPOWFencrypt(unsigned char passwd[8],
unsigned char *ntlmchalresp, unsigned char p24[24]);
void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
/* /*
...@@ -77,8 +74,8 @@ SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) ...@@ -77,8 +74,8 @@ SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
SMBOWFencrypt(p21, c8, p24); SMBOWFencrypt(p21, c8, p24);
memset(p14,0,15); memset(p14, 0, 15);
memset(p21,0,21); memset(p21, 0, 21);
} }
/* Routines for Windows NT MD4 Hash functions. */ /* Routines for Windows NT MD4 Hash functions. */
...@@ -100,7 +97,7 @@ _my_wcslen(__u16 * str) ...@@ -100,7 +97,7 @@ _my_wcslen(__u16 * str)
static int static int
_my_mbstowcs(__u16 * dst, const unsigned char *src, int len) _my_mbstowcs(__u16 * dst, const unsigned char *src, int len)
{ /* not a very good conversion routine - change/fix */ { /* BB not a very good conversion routine - change/fix */
int i; int i;
__u16 val; __u16 val;
...@@ -126,7 +123,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16) ...@@ -126,7 +123,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
__u16 wpwd[129]; __u16 wpwd[129];
/* Password cannot be longer than 128 characters */ /* Password cannot be longer than 128 characters */
if(passwd) { if (passwd) {
len = strlen((char *) passwd); len = strlen((char *) passwd);
if (len > 128) { if (len > 128) {
len = 128; len = 128;
...@@ -141,11 +138,12 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16) ...@@ -141,11 +138,12 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
len = _my_wcslen(wpwd) * sizeof (__u16); len = _my_wcslen(wpwd) * sizeof (__u16);
mdfour(p16, (unsigned char *) wpwd, len); mdfour(p16, (unsigned char *) wpwd, len);
memset(wpwd,0,129 * 2); memset(wpwd, 0, 129 * 2);
} }
#if 0 /* currently unused */
/* Does both the NT and LM owfs of a user's password */ /* Does both the NT and LM owfs of a user's password */
void static void
nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
{ {
char passwd[514]; char passwd[514];
...@@ -171,6 +169,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) ...@@ -171,6 +169,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
/* clear out local copy of user's password (just being paranoid). */ /* clear out local copy of user's password (just being paranoid). */
memset(passwd, '\0', sizeof (passwd)); memset(passwd, '\0', sizeof (passwd));
} }
#endif
/* Does the NTLMv2 owfs of a user's password */ /* Does the NTLMv2 owfs of a user's password */
#if 0 /* function not needed yet - but will be soon */ #if 0 /* function not needed yet - but will be soon */
...@@ -179,14 +178,14 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n, ...@@ -179,14 +178,14 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
const char *domain_n, unsigned char kr_buf[16], const char *domain_n, unsigned char kr_buf[16],
const struct nls_table *nls_codepage) const struct nls_table *nls_codepage)
{ {
wchar_t * user_u; wchar_t *user_u;
wchar_t * dom_u; wchar_t *dom_u;
int user_l, domain_l; int user_l, domain_l;
struct HMACMD5Context ctx; struct HMACMD5Context ctx;
/* might as well do one alloc to hold both (user_u and dom_u) */ /* might as well do one alloc to hold both (user_u and dom_u) */
user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL); user_u = kmalloc(2048 * sizeof(wchar_t), GFP_KERNEL);
if(user_u == NULL) if (user_u == NULL)
return; return;
dom_u = user_u + 1024; dom_u = user_u + 1024;
...@@ -223,7 +222,8 @@ SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, ...@@ -223,7 +222,8 @@ SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
} }
/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
void #if 0 /* currently unused */
static void
NTLMSSPOWFencrypt(unsigned char passwd[8], NTLMSSPOWFencrypt(unsigned char passwd[8],
unsigned char *ntlmchalresp, unsigned char p24[24]) unsigned char *ntlmchalresp, unsigned char p24[24])
{ {
...@@ -235,6 +235,7 @@ NTLMSSPOWFencrypt(unsigned char passwd[8], ...@@ -235,6 +235,7 @@ NTLMSSPOWFencrypt(unsigned char passwd[8],
E_P24(p21, ntlmchalresp, p24); E_P24(p21, ntlmchalresp, p24);
} }
#endif
/* Does the NT MD4 hash then des encryption. */ /* Does the NT MD4 hash then des encryption. */
...@@ -255,8 +256,8 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) ...@@ -255,8 +256,8 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
#if 0 #if 0
static void static void
SMBOWFencrypt_ntv2(const unsigned char kr[16], SMBOWFencrypt_ntv2(const unsigned char kr[16],
const struct data_blob * srv_chal, const struct data_blob *srv_chal,
const struct data_blob * cli_chal, unsigned char resp_buf[16]) const struct data_blob *cli_chal, unsigned char resp_buf[16])
{ {
struct HMACMD5Context ctx; struct HMACMD5Context ctx;
......
/* /*
* fs/cifs/transport.c * fs/cifs/transport.c
* *
* Copyright (C) International Business Machines Corp., 2002,2005 * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* Jeremy Allison (jra@samba.org) 2006. * Jeremy Allison (jra@samba.org) 2006.
* *
...@@ -40,7 +40,7 @@ extern kmem_cache_t *cifs_mid_cachep; ...@@ -40,7 +40,7 @@ extern kmem_cache_t *cifs_mid_cachep;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
extern mempool_t *cifs_mid_poolp; extern mempool_t *cifs_mid_poolp;
#endif #endif
extern kmem_cache_t *cifs_oplock_cachep; extern struct kmem_cache *cifs_oplock_cachep;
static struct mid_q_entry * static struct mid_q_entry *
AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
...@@ -58,17 +58,16 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) ...@@ -58,17 +58,16 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp, temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
SLAB_KERNEL | SLAB_NOFS); GFP_KERNEL | GFP_NOFS);
#else #else
temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep, temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep,
SLAB_KERNEL); SLAB_KERNEL);
#endif #endif
if (temp == NULL) if (temp == NULL)
return temp; return temp;
else { else {
memset(temp, 0, sizeof (struct mid_q_entry)); memset(temp, 0, sizeof(struct mid_q_entry));
temp->mid = smb_buffer->Mid; /* always LE */ temp->mid = smb_buffer->Mid; /* always LE */
temp->pid = current->pid; temp->pid = current->pid;
temp->command = smb_buffer->Command; temp->command = smb_buffer->Command;
...@@ -99,7 +98,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) ...@@ -99,7 +98,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
list_del(&midEntry->qhead); list_del(&midEntry->qhead);
atomic_dec(&midCount); atomic_dec(&midCount);
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
if(midEntry->largeBuf) if (midEntry->largeBuf)
cifs_buf_release(midEntry->resp_buf); cifs_buf_release(midEntry->resp_buf);
else else
cifs_small_buf_release(midEntry->resp_buf); cifs_small_buf_release(midEntry->resp_buf);
...@@ -107,8 +106,8 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) ...@@ -107,8 +106,8 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
now = jiffies; now = jiffies;
/* commands taking longer than one second are indications that /* commands taking longer than one second are indications that
something is wrong, unless it is quite a slow link or server */ something is wrong, unless it is quite a slow link or server */
if((now - midEntry->when_alloc) > HZ) { if ((now - midEntry->when_alloc) > HZ) {
if((cifsFYI & CIFS_TIMER) && if ((cifsFYI & CIFS_TIMER) &&
(midEntry->command != SMB_COM_LOCKING_ANDX)) { (midEntry->command != SMB_COM_LOCKING_ANDX)) {
printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d", printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
midEntry->command, midEntry->mid); midEntry->command, midEntry->mid);
...@@ -127,15 +126,15 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) ...@@ -127,15 +126,15 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
} }
struct oplock_q_entry * struct oplock_q_entry *
AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon) AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
{ {
struct oplock_q_entry *temp; struct oplock_q_entry *temp;
if ((pinode== NULL) || (tcon == NULL)) { if ((pinode == NULL) || (tcon == NULL)) {
cERROR(1, ("Null parms passed to AllocOplockQEntry")); cERROR(1, ("Null parms passed to AllocOplockQEntry"));
return NULL; return NULL;
} }
temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep, temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
SLAB_KERNEL); GFP_KERNEL);
if (temp == NULL) if (temp == NULL)
return temp; return temp;
else { else {
...@@ -150,7 +149,7 @@ AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon) ...@@ -150,7 +149,7 @@ AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
} }
void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry) void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
{ {
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
/* should we check if list empty first? */ /* should we check if list empty first? */
...@@ -172,13 +171,13 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, ...@@ -172,13 +171,13 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
mm_segment_t temp_fs; mm_segment_t temp_fs;
#endif #endif
if(ssocket == NULL) if (ssocket == NULL)
return -ENOTSOCK; /* BB eventually add reconnect code here */ return -ENOTSOCK; /* BB eventually add reconnect code here */
iov.iov_base = smb_buffer; iov.iov_base = smb_buffer;
iov.iov_len = len; iov.iov_len = len;
smb_msg.msg_name = sin; smb_msg.msg_name = sin;
smb_msg.msg_namelen = sizeof (struct sockaddr); smb_msg.msg_namelen = sizeof(struct sockaddr);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8)
smb_msg.msg_iov = &iov; smb_msg.msg_iov = &iov;
smb_msg.msg_iovlen = 1; smb_msg.msg_iovlen = 1;
...@@ -211,7 +210,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, ...@@ -211,7 +210,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
/* smaller timeout here than send2 since smaller size */ /* smaller timeout here than send2 since smaller size */
/* Although it may not be required, this also is smaller /* Although it may not be required, this also is smaller
oplock break time */ oplock break time */
if(i > 12) { if (i > 12) {
cERROR(1, cERROR(1,
("sends on sock %p stuck for 7 seconds", ("sends on sock %p stuck for 7 seconds",
ssocket)); ssocket));
...@@ -234,7 +233,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, ...@@ -234,7 +233,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
#endif #endif
if (rc < 0) { if (rc < 0) {
cERROR(1,("Error %d sending data on socket to server", rc)); cERROR(1, ("Error %d sending data on socket to server", rc));
} else { } else {
rc = 0; rc = 0;
} }
...@@ -262,11 +261,11 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, ...@@ -262,11 +261,11 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
mm_segment_t temp_fs; mm_segment_t temp_fs;
#endif #endif
if(ssocket == NULL) if (ssocket == NULL)
return -ENOTSOCK; /* BB eventually add reconnect code here */ return -ENOTSOCK; /* BB eventually add reconnect code here */
smb_msg.msg_name = sin; smb_msg.msg_name = sin;
smb_msg.msg_namelen = sizeof (struct sockaddr); smb_msg.msg_namelen = sizeof(struct sockaddr);
smb_msg.msg_control = NULL; smb_msg.msg_control = NULL;
smb_msg.msg_controllen = 0; smb_msg.msg_controllen = 0;
smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
...@@ -300,7 +299,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, ...@@ -300,7 +299,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
#endif #endif
if ((rc == -ENOSPC) || (rc == -EAGAIN)) { if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
i++; i++;
if(i >= 14) { if (i >= 14) {
cERROR(1, cERROR(1,
("sends on sock %p stuck for 15 seconds", ("sends on sock %p stuck for 15 seconds",
ssocket)); ssocket));
...@@ -314,18 +313,13 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, ...@@ -314,18 +313,13 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
break; break;
if (rc >= total_len) { if (rc >= total_len) {
if(rc > total_len) { WARN_ON(rc > total_len);
cERROR(1,("unexpected length received"));
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 19)
dump_stack();
#endif
}
break; break;
} }
if(rc == 0) { if (rc == 0) {
/* should never happen, letting socket clear before /* should never happen, letting socket clear before
retrying is our only obvious option here */ retrying is our only obvious option here */
cERROR(1,("tcp sent no data")); cERROR(1, ("tcp sent no data"));
msleep(500); msleep(500);
continue; continue;
} }
...@@ -351,7 +345,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, ...@@ -351,7 +345,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
#endif #endif
if (rc < 0) { if (rc < 0) {
cERROR(1,("Error %d sending data on socket to server", rc)); cERROR(1, ("Error %d sending data on socket to server", rc));
} else } else
rc = 0; rc = 0;
...@@ -364,13 +358,13 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, ...@@ -364,13 +358,13 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
{ {
if(long_op == -1) { if (long_op == -1) {
/* oplock breaks must not be held up */ /* oplock breaks must not be held up */
atomic_inc(&ses->server->inFlight); atomic_inc(&ses->server->inFlight);
} else { } else {
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
while(1) { while (1) {
if(atomic_read(&ses->server->inFlight) >= if (atomic_read(&ses->server->inFlight) >=
cifs_max_pending){ cifs_max_pending){
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
...@@ -384,13 +378,13 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) ...@@ -384,13 +378,13 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
#endif #endif
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
} else { } else {
if(ses->server->tcpStatus == CifsExiting) { if (ses->server->tcpStatus == CifsExiting) {
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
return -ENOENT; return -ENOENT;
} }
/* can not count locking commands against total since /* can not count locking commands against total
they are allowed to block on server */ as they are allowed to block on server */
/* update # of requests on the wire to server */ /* update # of requests on the wire to server */
if (long_op < 3) if (long_op < 3)
...@@ -409,19 +403,18 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, ...@@ -409,19 +403,18 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
if (ses->server->tcpStatus == CifsExiting) { if (ses->server->tcpStatus == CifsExiting) {
return -ENOENT; return -ENOENT;
} else if (ses->server->tcpStatus == CifsNeedReconnect) { } else if (ses->server->tcpStatus == CifsNeedReconnect) {
cFYI(1,("tcp session dead - return to caller to retry")); cFYI(1, ("tcp session dead - return to caller to retry"));
return -EAGAIN; return -EAGAIN;
} else if (ses->status != CifsGood) { } else if (ses->status != CifsGood) {
/* check if SMB session is bad because we are setting it up */ /* check if SMB session is bad because we are setting it up */
if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
(in_buf->Command != SMB_COM_NEGOTIATE)) { (in_buf->Command != SMB_COM_NEGOTIATE)) {
return -EAGAIN; return -EAGAIN;
} /* else ok - we are setting up session */ } /* else ok - we are setting up session */
} }
*ppmidQ = AllocMidQEntry(in_buf, ses); *ppmidQ = AllocMidQEntry(in_buf, ses);
if (*ppmidQ == NULL) { if (*ppmidQ == NULL)
return -ENOMEM; return -ENOMEM;
}
return 0; return 0;
} }
...@@ -463,7 +456,7 @@ static int wait_for_response(struct cifsSesInfo *ses, ...@@ -463,7 +456,7 @@ static int wait_for_response(struct cifsSesInfo *ses,
lrt += time_to_wait; lrt += time_to_wait;
if (time_after(jiffies, lrt)) { if (time_after(jiffies, lrt)) {
/* No replies for time_to_wait. */ /* No replies for time_to_wait. */
cERROR(1,("server not responding")); cERROR(1, ("server not responding"));
return -1; return -1;
} }
} else { } else {
...@@ -474,7 +467,7 @@ static int wait_for_response(struct cifsSesInfo *ses, ...@@ -474,7 +467,7 @@ static int wait_for_response(struct cifsSesInfo *ses,
int int
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
struct kvec *iov, int n_vec, int * pRespBufType /* ret */, struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
const int long_op) const int long_op)
{ {
int rc = 0; int rc = 0;
...@@ -487,11 +480,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -487,11 +480,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
if ((ses == NULL) || (ses->server == NULL)) { if ((ses == NULL) || (ses->server == NULL)) {
cifs_small_buf_release(in_buf); cifs_small_buf_release(in_buf);
cERROR(1,("Null session")); cERROR(1, ("Null session"));
return -EIO; return -EIO;
} }
if(ses->server->tcpStatus == CifsExiting) { if (ses->server->tcpStatus == CifsExiting) {
cifs_small_buf_release(in_buf); cifs_small_buf_release(in_buf);
return -ENOENT; return -ENOENT;
} }
...@@ -538,7 +531,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -538,7 +531,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
up(&ses->server->tcpSem); up(&ses->server->tcpSem);
cifs_small_buf_release(in_buf); cifs_small_buf_release(in_buf);
if(rc < 0) if (rc < 0)
goto out; goto out;
if (long_op == -1) if (long_op == -1)
...@@ -567,10 +560,10 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -567,10 +560,10 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
receive_len = midQ->resp_buf->smb_buf_length; receive_len = midQ->resp_buf->smb_buf_length;
} else { } else {
cERROR(1,("No response to cmd %d mid %d", cERROR(1, ("No response to cmd %d mid %d",
midQ->command, midQ->mid)); midQ->command, midQ->mid));
if(midQ->midState == MID_REQUEST_SUBMITTED) { if (midQ->midState == MID_REQUEST_SUBMITTED) {
if(ses->server->tcpStatus == CifsExiting) if (ses->server->tcpStatus == CifsExiting)
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
else { else {
ses->server->tcpStatus = CifsNeedReconnect; ses->server->tcpStatus = CifsNeedReconnect;
...@@ -579,9 +572,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -579,9 +572,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
} }
if (rc != -EHOSTDOWN) { if (rc != -EHOSTDOWN) {
if(midQ->midState == MID_RETRY_NEEDED) { if (midQ->midState == MID_RETRY_NEEDED) {
rc = -EAGAIN; rc = -EAGAIN;
cFYI(1,("marking request for retry")); cFYI(1, ("marking request for retry"));
} else { } else {
rc = -EIO; rc = -EIO;
} }
...@@ -603,7 +596,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -603,7 +596,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
(midQ->midState == MID_RESPONSE_RECEIVED)) { (midQ->midState == MID_RESPONSE_RECEIVED)) {
iov[0].iov_base = (char *)midQ->resp_buf; iov[0].iov_base = (char *)midQ->resp_buf;
if(midQ->largeBuf) if (midQ->largeBuf)
*pRespBufType = CIFS_LARGE_BUFFER; *pRespBufType = CIFS_LARGE_BUFFER;
else else
*pRespBufType = CIFS_SMALL_BUFFER; *pRespBufType = CIFS_SMALL_BUFFER;
...@@ -611,14 +604,14 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -611,14 +604,14 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
dump_smb(midQ->resp_buf, 80); dump_smb(midQ->resp_buf, 80);
/* convert the length into a more usable form */ /* convert the length into a more usable form */
if((receive_len > 24) && if ((receive_len > 24) &&
(ses->server->secMode & (SECMODE_SIGN_REQUIRED | (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) { SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(midQ->resp_buf, rc = cifs_verify_signature(midQ->resp_buf,
ses->server->mac_signing_key, &ses->server->mac_signing_key,
midQ->sequence_number+1); midQ->sequence_number+1);
if(rc) { if (rc) {
cERROR(1,("Unexpected SMB signature")); cERROR(1, ("Unexpected SMB signature"));
/* BB FIXME add code to kill session */ /* BB FIXME add code to kill session */
} }
} }
...@@ -628,9 +621,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -628,9 +621,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
rc = map_smb_to_linux_error(midQ->resp_buf); rc = map_smb_to_linux_error(midQ->resp_buf);
/* convert ByteCount if necessary */ /* convert ByteCount if necessary */
if (receive_len >= if (receive_len >= sizeof(struct smb_hdr) - 4
sizeof (struct smb_hdr) - /* do not count RFC1001 header */ +
4 /* do not count RFC1001 header */ +
(2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
BCC(midQ->resp_buf) = BCC(midQ->resp_buf) =
le16_to_cpu(BCC_LE(midQ->resp_buf)); le16_to_cpu(BCC_LE(midQ->resp_buf));
...@@ -638,7 +630,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -638,7 +630,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
by DeleteMidQEntry */ by DeleteMidQEntry */
} else { } else {
rc = -EIO; rc = -EIO;
cFYI(1,("Bad MID state?")); cFYI(1, ("Bad MID state?"));
} }
} }
...@@ -661,15 +653,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -661,15 +653,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
struct mid_q_entry *midQ; struct mid_q_entry *midQ;
if (ses == NULL) { if (ses == NULL) {
cERROR(1,("Null smb session")); cERROR(1, ("Null smb session"));
return -EIO; return -EIO;
} }
if(ses->server == NULL) { if (ses->server == NULL) {
cERROR(1,("Null tcp session")); cERROR(1, ("Null tcp session"));
return -EIO; return -EIO;
} }
if(ses->server->tcpStatus == CifsExiting) if (ses->server->tcpStatus == CifsExiting)
return -ENOENT; return -ENOENT;
/* Ensure that we do not send more than 50 overlapping requests /* Ensure that we do not send more than 50 overlapping requests
...@@ -720,7 +712,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -720,7 +712,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
#endif #endif
up(&ses->server->tcpSem); up(&ses->server->tcpSem);
if(rc < 0) if (rc < 0)
goto out; goto out;
if (long_op == -1) if (long_op == -1)
...@@ -748,10 +740,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -748,10 +740,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
receive_len = midQ->resp_buf->smb_buf_length; receive_len = midQ->resp_buf->smb_buf_length;
} else { } else {
cERROR(1,("No response for cmd %d mid %d", cERROR(1, ("No response for cmd %d mid %d",
midQ->command, midQ->mid)); midQ->command, midQ->mid));
if(midQ->midState == MID_REQUEST_SUBMITTED) { if (midQ->midState == MID_REQUEST_SUBMITTED) {
if(ses->server->tcpStatus == CifsExiting) if (ses->server->tcpStatus == CifsExiting)
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
else { else {
ses->server->tcpStatus = CifsNeedReconnect; ses->server->tcpStatus = CifsNeedReconnect;
...@@ -760,9 +752,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -760,9 +752,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
} }
if (rc != -EHOSTDOWN) { if (rc != -EHOSTDOWN) {
if(midQ->midState == MID_RETRY_NEEDED) { if (midQ->midState == MID_RETRY_NEEDED) {
rc = -EAGAIN; rc = -EAGAIN;
cFYI(1,("marking request for retry")); cFYI(1, ("marking request for retry"));
} else { } else {
rc = -EIO; rc = -EIO;
} }
...@@ -790,14 +782,14 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -790,14 +782,14 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
dump_smb(out_buf, 92); dump_smb(out_buf, 92);
/* convert the length into a more usable form */ /* convert the length into a more usable form */
if((receive_len > 24) && if ((receive_len > 24) &&
(ses->server->secMode & (SECMODE_SIGN_REQUIRED | (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) { SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(out_buf, rc = cifs_verify_signature(out_buf,
ses->server->mac_signing_key, &ses->server->mac_signing_key,
midQ->sequence_number+1); midQ->sequence_number+1);
if(rc) { if (rc) {
cERROR(1,("Unexpected SMB signature")); cERROR(1, ("Unexpected SMB signature"));
/* BB FIXME add code to kill session */ /* BB FIXME add code to kill session */
} }
} }
...@@ -808,14 +800,13 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -808,14 +800,13 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
rc = map_smb_to_linux_error(out_buf); rc = map_smb_to_linux_error(out_buf);
/* convert ByteCount if necessary */ /* convert ByteCount if necessary */
if (receive_len >= if (receive_len >= sizeof(struct smb_hdr) - 4
sizeof (struct smb_hdr) - /* do not count RFC1001 header */ +
4 /* do not count RFC1001 header */ +
(2 * out_buf->WordCount) + 2 /* bcc */ ) (2 * out_buf->WordCount) + 2 /* bcc */ )
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
} else { } else {
rc = -EIO; rc = -EIO;
cERROR(1,("Bad MID state?")); cERROR(1, ("Bad MID state?"));
} }
} }
...@@ -888,17 +879,17 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, ...@@ -888,17 +879,17 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
struct cifsSesInfo *ses; struct cifsSesInfo *ses;
if (tcon == NULL || tcon->ses == NULL) { if (tcon == NULL || tcon->ses == NULL) {
cERROR(1,("Null smb session")); cERROR(1, ("Null smb session"));
return -EIO; return -EIO;
} }
ses = tcon->ses; ses = tcon->ses;
if(ses->server == NULL) { if (ses->server == NULL) {
cERROR(1,("Null tcp session")); cERROR(1, ("Null tcp session"));
return -EIO; return -EIO;
} }
if(ses->server->tcpStatus == CifsExiting) if (ses->server->tcpStatus == CifsExiting)
return -ENOENT; return -ENOENT;
/* Ensure that we do not send more than 50 overlapping requests /* Ensure that we do not send more than 50 overlapping requests
...@@ -943,7 +934,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, ...@@ -943,7 +934,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
#endif #endif
up(&ses->server->tcpSem); up(&ses->server->tcpSem);
if(rc < 0) { if (rc < 0) {
DeleteMidQEntry(midQ); DeleteMidQEntry(midQ);
return rc; return rc;
} }
...@@ -984,7 +975,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, ...@@ -984,7 +975,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
} }
/* Wait 5 seconds for the response. */ /* Wait 5 seconds for the response. */
if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ)==0) { if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
/* We got the response - restart system call. */ /* We got the response - restart system call. */
rstart = 1; rstart = 1;
} }
...@@ -995,10 +986,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, ...@@ -995,10 +986,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
receive_len = midQ->resp_buf->smb_buf_length; receive_len = midQ->resp_buf->smb_buf_length;
} else { } else {
cERROR(1,("No response for cmd %d mid %d", cERROR(1, ("No response for cmd %d mid %d",
midQ->command, midQ->mid)); midQ->command, midQ->mid));
if(midQ->midState == MID_REQUEST_SUBMITTED) { if (midQ->midState == MID_REQUEST_SUBMITTED) {
if(ses->server->tcpStatus == CifsExiting) if (ses->server->tcpStatus == CifsExiting)
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
else { else {
ses->server->tcpStatus = CifsNeedReconnect; ses->server->tcpStatus = CifsNeedReconnect;
...@@ -1007,9 +998,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, ...@@ -1007,9 +998,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
} }
if (rc != -EHOSTDOWN) { if (rc != -EHOSTDOWN) {
if(midQ->midState == MID_RETRY_NEEDED) { if (midQ->midState == MID_RETRY_NEEDED) {
rc = -EAGAIN; rc = -EAGAIN;
cFYI(1,("marking request for retry")); cFYI(1, ("marking request for retry"));
} else { } else {
rc = -EIO; rc = -EIO;
} }
...@@ -1034,14 +1025,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, ...@@ -1034,14 +1025,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
dump_smb(out_buf, 92); dump_smb(out_buf, 92);
/* convert the length into a more usable form */ /* convert the length into a more usable form */
if((receive_len > 24) && if ((receive_len > 24) &&
(ses->server->secMode & (SECMODE_SIGN_REQUIRED | (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) { SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(out_buf, rc = cifs_verify_signature(out_buf,
ses->server->mac_signing_key, &ses->server->mac_signing_key,
midQ->sequence_number+1); midQ->sequence_number+1);
if(rc) { if (rc) {
cERROR(1,("Unexpected SMB signature")); cERROR(1, ("Unexpected SMB signature"));
/* BB FIXME add code to kill session */ /* BB FIXME add code to kill session */
} }
} }
...@@ -1052,14 +1043,13 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, ...@@ -1052,14 +1043,13 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
rc = map_smb_to_linux_error(out_buf); rc = map_smb_to_linux_error(out_buf);
/* convert ByteCount if necessary */ /* convert ByteCount if necessary */
if (receive_len >= if (receive_len >= sizeof(struct smb_hdr) - 4
sizeof (struct smb_hdr) - /* do not count RFC1001 header */ +
4 /* do not count RFC1001 header */ +
(2 * out_buf->WordCount) + 2 /* bcc */ ) (2 * out_buf->WordCount) + 2 /* bcc */ )
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
} else { } else {
rc = -EIO; rc = -EIO;
cERROR(1,("Bad MID state?")); cERROR(1, ("Bad MID state?"));
} }
} }
DeleteMidQEntry(midQ); DeleteMidQEntry(midQ);
......
/* /*
* fs/cifs/xattr.c * fs/cifs/xattr.c
* *
* Copyright (c) International Business Machines Corp., 2003 * Copyright (c) International Business Machines Corp., 2003, 2007
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -43,22 +43,22 @@ ...@@ -43,22 +43,22 @@
int cifs_removexattr(struct dentry * direntry, const char * ea_name) int cifs_removexattr(struct dentry *direntry, const char *ea_name)
{ {
int rc = -EOPNOTSUPP; int rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR #ifdef CONFIG_CIFS_XATTR
int xid; int xid;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct super_block * sb; struct super_block *sb;
char * full_path; char *full_path;
if(direntry == NULL) if (direntry == NULL)
return -EIO; return -EIO;
if(direntry->d_inode == NULL) if (direntry->d_inode == NULL)
return -EIO; return -EIO;
sb = direntry->d_inode->i_sb; sb = direntry->d_inode->i_sb;
if(sb == NULL) if (sb == NULL)
return -EIO; return -EIO;
xid = GetXid(); xid = GetXid();
...@@ -66,24 +66,26 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name) ...@@ -66,24 +66,26 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name)
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if(full_path == NULL) { if (full_path == NULL) {
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
if(ea_name == NULL) { if (ea_name == NULL) {
cFYI(1,("Null xattr names not supported")); cFYI(1, ("Null xattr names not supported"));
} else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5)
&& (strncmp(ea_name,CIFS_XATTR_OS2_PREFIX,4))) { && (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) {
cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name)); cFYI(1,
("illegal xattr request %s (only user namespace supported)",
ea_name));
/* BB what if no namespace prefix? */ /* BB what if no namespace prefix? */
/* Should we just pass them to server, except for /* Should we just pass them to server, except for
system and perhaps security prefixes? */ system and perhaps security prefixes? */
} else { } else {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto remove_ea_exit; goto remove_ea_exit;
ea_name+=5; /* skip past user. prefix */ ea_name += 5; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,NULL, rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL,
(__u16)0, cifs_sb->local_nls, (__u16)0, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
...@@ -94,23 +96,23 @@ remove_ea_exit: ...@@ -94,23 +96,23 @@ remove_ea_exit:
return rc; return rc;
} }
int cifs_setxattr(struct dentry * direntry, const char * ea_name, int cifs_setxattr(struct dentry *direntry, const char *ea_name,
const void * ea_value, size_t value_size, int flags) const void *ea_value, size_t value_size, int flags)
{ {
int rc = -EOPNOTSUPP; int rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR #ifdef CONFIG_CIFS_XATTR
int xid; int xid;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct super_block * sb; struct super_block *sb;
char * full_path; char *full_path;
if(direntry == NULL) if (direntry == NULL)
return -EIO; return -EIO;
if(direntry->d_inode == NULL) if (direntry->d_inode == NULL)
return -EIO; return -EIO;
sb = direntry->d_inode->i_sb; sb = direntry->d_inode->i_sb;
if(sb == NULL) if (sb == NULL)
return -EIO; return -EIO;
xid = GetXid(); xid = GetXid();
...@@ -118,7 +120,7 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, ...@@ -118,7 +120,7 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if(full_path == NULL) { if (full_path == NULL) {
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
...@@ -128,63 +130,65 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, ...@@ -128,63 +130,65 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
/* if proc/fs/cifs/streamstoxattr is set then /* if proc/fs/cifs/streamstoxattr is set then
search server for EAs or streams to search server for EAs or streams to
returns as xattrs */ returns as xattrs */
if(value_size > MAX_EA_VALUE_SIZE) { if (value_size > MAX_EA_VALUE_SIZE) {
cFYI(1,("size of EA value too large")); cFYI(1, ("size of EA value too large"));
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if(ea_name == NULL) { if (ea_name == NULL) {
cFYI(1,("Null xattr names not supported")); cFYI(1, ("Null xattr names not supported"));
} else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) { } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto set_ea_exit; goto set_ea_exit;
if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) { if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
cFYI(1,("attempt to set cifs inode metadata")); cFYI(1, ("attempt to set cifs inode metadata"));
} }
ea_name += 5; /* skip past user. prefix */ ea_name += 5; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
(__u16)value_size, cifs_sb->local_nls, (__u16)value_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto set_ea_exit; goto set_ea_exit;
ea_name += 4; /* skip past os2. prefix */ ea_name += 4; /* skip past os2. prefix */
rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
(__u16)value_size, cifs_sb->local_nls, (__u16)value_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} else { } else {
int temp; int temp;
temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS, temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
strlen(POSIX_ACL_XATTR_ACCESS)); strlen(POSIX_ACL_XATTR_ACCESS));
if (temp == 0) { if (temp == 0) {
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
if(sb->s_flags & MS_POSIXACL) if (sb->s_flags & MS_POSIXACL)
rc = CIFSSMBSetPosixACL(xid, pTcon,full_path, rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
ea_value, (const int)value_size, ea_value, (const int)value_size,
ACL_TYPE_ACCESS,cifs_sb->local_nls, ACL_TYPE_ACCESS, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1,("set POSIX ACL rc %d",rc)); cFYI(1, ("set POSIX ACL rc %d", rc));
#else #else
cFYI(1,("set POSIX ACL not supported")); cFYI(1, ("set POSIX ACL not supported"));
#endif #endif
} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
if(sb->s_flags & MS_POSIXACL) if (sb->s_flags & MS_POSIXACL)
rc = CIFSSMBSetPosixACL(xid, pTcon,full_path, rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
ea_value, (const int)value_size, ea_value, (const int)value_size,
ACL_TYPE_DEFAULT, cifs_sb->local_nls, ACL_TYPE_DEFAULT, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1,("set POSIX default ACL rc %d",rc)); cFYI(1, ("set POSIX default ACL rc %d", rc));
#else #else
cFYI(1,("set default POSIX ACL not supported")); cFYI(1, ("set default POSIX ACL not supported"));
#endif #endif
} else { } else {
cFYI(1,("illegal xattr request %s (only user namespace supported)",ea_name)); cFYI(1, ("illegal xattr request %s (only user namespace"
" supported)", ea_name));
/* BB what if no namespace prefix? */ /* BB what if no namespace prefix? */
/* Should we just pass them to server, except for /* Should we just pass them to server, except for
system and perhaps security prefixes? */ system and perhaps security prefixes? */
...@@ -198,23 +202,23 @@ set_ea_exit: ...@@ -198,23 +202,23 @@ set_ea_exit:
return rc; return rc;
} }
ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
void * ea_value, size_t buf_size) void *ea_value, size_t buf_size)
{ {
ssize_t rc = -EOPNOTSUPP; ssize_t rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR #ifdef CONFIG_CIFS_XATTR
int xid; int xid;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct super_block * sb; struct super_block *sb;
char * full_path; char *full_path;
if(direntry == NULL) if (direntry == NULL)
return -EIO; return -EIO;
if(direntry->d_inode == NULL) if (direntry->d_inode == NULL)
return -EIO; return -EIO;
sb = direntry->d_inode->i_sb; sb = direntry->d_inode->i_sb;
if(sb == NULL) if (sb == NULL)
return -EIO; return -EIO;
xid = GetXid(); xid = GetXid();
...@@ -223,38 +227,38 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, ...@@ -223,38 +227,38 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if(full_path == NULL) { if (full_path == NULL) {
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
/* return dos attributes as pseudo xattr */ /* return dos attributes as pseudo xattr */
/* return alt name if available as pseudo attr */ /* return alt name if available as pseudo attr */
if(ea_name == NULL) { if (ea_name == NULL) {
cFYI(1,("Null xattr names not supported")); cFYI(1, ("Null xattr names not supported"));
} else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) { } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto get_ea_exit; goto get_ea_exit;
if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) { if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
cFYI(1,("attempt to query cifs inode metadata")); cFYI(1, ("attempt to query cifs inode metadata"));
/* revalidate/getattr then populate from inode */ /* revalidate/getattr then populate from inode */
} /* BB add else when above is implemented */ } /* BB add else when above is implemented */
ea_name += 5; /* skip past user. prefix */ ea_name += 5; /* skip past user. prefix */
rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value,
buf_size, cifs_sb->local_nls, buf_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto get_ea_exit; goto get_ea_exit;
ea_name += 4; /* skip past os2. prefix */ ea_name += 4; /* skip past os2. prefix */
rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value,
buf_size, cifs_sb->local_nls, buf_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS, } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
if(sb->s_flags & MS_POSIXACL) if (sb->s_flags & MS_POSIXACL)
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
ea_value, buf_size, ACL_TYPE_ACCESS, ea_value, buf_size, ACL_TYPE_ACCESS,
cifs_sb->local_nls, cifs_sb->local_nls,
...@@ -275,30 +279,31 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, ...@@ -275,30 +279,31 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
CIFSSMBClose(xid, pTcon, fid); CIFSSMBClose(xid, pTcon, fid);
} }
} */ /* BB enable after fixing up return data */ } */ /* BB enable after fixing up return data */
#else #else
cFYI(1,("query POSIX ACL not supported yet")); cFYI(1, ("query POSIX ACL not supported yet"));
#endif /* CONFIG_CIFS_POSIX */ #endif /* CONFIG_CIFS_POSIX */
} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT, } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
if(sb->s_flags & MS_POSIXACL) if (sb->s_flags & MS_POSIXACL)
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
ea_value, buf_size, ACL_TYPE_DEFAULT, ea_value, buf_size, ACL_TYPE_DEFAULT,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
#else #else
cFYI(1,("query POSIX default ACL not supported yet")); cFYI(1, ("query POSIX default ACL not supported yet"));
#endif #endif
} else if(strncmp(ea_name, } else if (strncmp(ea_name,
CIFS_XATTR_TRUSTED_PREFIX,XATTR_TRUSTED_PREFIX_LEN) == 0) { CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
cFYI(1,("Trusted xattr namespace not supported yet")); cFYI(1, ("Trusted xattr namespace not supported yet"));
} else if(strncmp(ea_name, } else if (strncmp(ea_name,
CIFS_XATTR_SECURITY_PREFIX,XATTR_SECURITY_PREFIX_LEN) == 0) { CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
cFYI(1,("Security xattr namespace not supported yet")); cFYI(1, ("Security xattr namespace not supported yet"));
} else { } else {
cFYI(1,("illegal xattr name request %s (only user namespace supported)",ea_name)); cFYI(1,
("illegal xattr request %s (only user namespace supported)",
ea_name));
} }
/* We could add an additional check for streams ie /* We could add an additional check for streams ie
...@@ -306,7 +311,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, ...@@ -306,7 +311,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
search server for EAs or streams to search server for EAs or streams to
returns as xattrs */ returns as xattrs */
if(rc == -EINVAL) if (rc == -EINVAL)
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
get_ea_exit: get_ea_exit:
...@@ -316,34 +321,34 @@ get_ea_exit: ...@@ -316,34 +321,34 @@ get_ea_exit:
return rc; return rc;
} }
ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
{ {
ssize_t rc = -EOPNOTSUPP; ssize_t rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR #ifdef CONFIG_CIFS_XATTR
int xid; int xid;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct super_block * sb; struct super_block *sb;
char * full_path; char *full_path;
if(direntry == NULL) if (direntry == NULL)
return -EIO; return -EIO;
if(direntry->d_inode == NULL) if (direntry->d_inode == NULL)
return -EIO; return -EIO;
sb = direntry->d_inode->i_sb; sb = direntry->d_inode->i_sb;
if(sb == NULL) if (sb == NULL)
return -EIO; return -EIO;
cifs_sb = CIFS_SB(sb); cifs_sb = CIFS_SB(sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
return -EOPNOTSUPP; return -EOPNOTSUPP;
xid = GetXid(); xid = GetXid();
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if(full_path == NULL) { if (full_path == NULL) {
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
...@@ -353,7 +358,7 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) ...@@ -353,7 +358,7 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
/* if proc/fs/cifs/streamstoxattr is set then /* if proc/fs/cifs/streamstoxattr is set then
search server for EAs or streams to search server for EAs or streams to
returns as xattrs */ returns as xattrs */
rc = CIFSSMBQAllEAs(xid,pTcon,full_path,data,buf_size, rc = CIFSSMBQAllEAs(xid, pTcon, full_path, data, buf_size,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
......
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