Commit f27e5a2c authored by Steve French's avatar Steve French

Merge bk://linux.bkbits.net/linux-2.5

into bkbits.net:/repos/c/cifs/linux-2.5cifs
parents 01eb4811 4096004b
......@@ -1718,12 +1718,22 @@ config CIFS_XATTR
config CIFS_POSIX
bool "CIFS POSIX Extensions (EXPERIMENTAL)"
depends on CIFS
depends on CIFS_XATTR
help
Enabling this option will cause the cifs client to attempt to
negotiate a newer dialect with servers, such as Samba 3.0.5
or later, that optionally can handle more POSIX like (rather
than Windows like) file behavior. If unsure, say N.
than Windows like) file behavior. It also enables
support for POSIX ACLs (getfacl and setfacl) to servers
(such as Samba 3.10 and later) which can negotiate
CIFS POSIX ACL support. If unsure, say N.
config CIFS_EXPERIMENTAL
bool "CIFS Experimental Features (EXPERIMENTAL)"
depends on CIFS
help
Enables cifs features under testing. These features
are highly experimental. If unsure, say N.
config NCP_FS
tristate "NCP file system support (to mount NetWare volumes)"
......
Version 1.26
------------
Add setfacl support to allow setting of ACLs remotely to Samba 3.10 and later
and other POSIX CIFS compliant servers. Fix error mapping for getfacl
to EOPNOTSUPP when server does not support posix acls on the wire. Fix
improperly zeroed buffer in CIFS Unix extensions set times call.
Version 1.25
------------
Fix internationlization problem in cifs readdir with filenames that map to
longer UTF8 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
non-consecutive entries). Do not do readdir when server negotiates
buffer size to small to fit filename. Add support for reading POSIX ACLs from
the server (add also acl and noacl mount options).
Version 1.24
------------
Optionally allow using server side inode numbers, rather than client generated
ones by specifying mount option "serverino" - this is required for some apps
to work which double check hardlinked files and have persistent inode numbers.
Version 1.23
------------
Multiple bigendian fixes. On little endian systems (for reconnect after
network failure) fix tcp session reconnect code so we do not try first
to reconnect on reverse of port 445. Treat reparse points (NTFS junctions)
as directories rather than symlinks because we can do follow link on them.
Version 1.22
------------
Add config option to enable XATTR (extended attribute) support, mapping
......
......@@ -3,4 +3,4 @@
#
obj-$(CONFIG_CIFS) += cifs.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
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
......@@ -115,11 +115,20 @@ cifs client, and that EA support is present in later versions of Samba (e.g.
3.0.6 and later (also EA support works in all versions of Windows, at least to
shares on NTFS filesystems). Extended Attribute (xattr) support is an optional
feature of most Linux filesystems which may require enabling via
make menuconfig
make menuconfig.
The CIFS client can get and set POSIX ACLs (getfacl, setfacl) to Samba servers
version 3.10 and later. Setting POSIX ACLs requires enabling both XATTR and
then POSIX support in the CIFS configuration options when building the cifs
module.
Some administrators may want to change Samba's smb.conf "map archive" and
"create mask" parameters from the default. Creating special devices (mknod)
remotely may require specifying a mkdev function to Samba if you are not using
"create mask" parameters from the default. Unless the create mask is changed
newly created files can end up with an unnecessarily restrictive default mode,
which may not be what you want, although if the CIFS Unix extensions are
enabled on the server and client, subsequent setattr calls (e.g. chmod) can
fix the mode. Note that creating special devices (mknod) remotely
may require specifying a mkdev function to Samba if you are not using
Samba 3.0.6 or later. For more information on these see the manual pages
("man smb.conf") on the Samba server system. Note that the cifs vfs,
unlike the smbfs vfs, does not read the smb.conf on the client system
......@@ -266,6 +275,10 @@ A partial list of the supported mount options follows:
If you do not trust the servers in your network (your mount
targets) it is recommended that you specify this option for
greater security.
exec Permit execution of binaries on the mount.
noexec Do not permit execution of binaries on the mount.
dev Recognize block devices on the remote mount.
nodev Do not recognize devices on the remote mount.
suid Allow remote files on this mountpoint with suid enabled to
be executed (default for mounts when executed as root,
nosuid is default for user mounts).
......@@ -292,6 +305,22 @@ A partial list of the supported mount options follows:
Note that this does not affect the normal ACL check on the
target machine done by the server software (of the server
ACL against the user name provided at mount time).
serverino Use servers inode numbers instead of generating automatically
incrementing inode numbers on the client. Although this will
make it easier to spot hardlinked files (as they will have
the same inode numbers) and inode numbers may be persistent,
note that the server does not guarantee that the inode numbers
are unique if multiple server side mounts are exported under a
single share (since inode numbers on the servers might not
be unique if multiple filesystems are mounted under the same
shared higher level directory). Note that this requires that
the server support the CIFS Unix Extensions as other servers
do not return a unique IndexNumber on SMB FindFirst (most
servers return zero as the IndexNumber). Parameter has no
effect to Windows servers and others which do not support the
CIFS Unix Extensions.
noserverino Client generates inode numbers (rather than using the actual one
from the server) by default.
setuids If the CIFS Unix extensions are negotiated with the server
the client will attempt to set the effective uid and gid of
the local process on newly created files, directories, and
......@@ -304,6 +333,23 @@ A partial list of the supported mount options follows:
the client) set the uid and gid is the default. This
parameter has no effect if the CIFS Unix Extensions are not
negotiated.
netbiosname When mounting to servers via port 139, specifies the RFC1001
source name to use to represent the client netbios machine
name when doing the RFC1001 netbios session initialize.
direct Do not do inode data caching on files opened on this mount.
This precludes mmaping files on this mount. In some cases
with fast networks and little or no caching benefits on the
client (e.g. when the application is doing large sequential
reads bigger than page size without rereading the same data)
this can provide better performance than the default
behavior which caches reads (reaadahead) and writes
(writebehind) through the local Linux client pagecache
if oplock (caching token) is granted and held. Note that
direct allows write operations larger than page size
to be sent to the server.
acl Allow setfacl and getfacl to manage posix ACLs if server
supports them. (default)
noacl Do not allow setfacl and getfacl calls on this mount
The mount.cifs mount helper also accepts a few mount options before -o
including:
......@@ -382,7 +428,7 @@ require enabling an ifdef (e.g. by adding "#define CIFS_FCNTL" in cifsglob.h)
CONFIG_CIFS_FCNTL (fcntl needed for support of directory change
notification and perhaps later for file leases)
Per share (per client mount) statistics are available in /proc/fs/cifs/DebugData
Per share (per client mount) statistics are available in /proc/fs/cifs/Stats
if the kernel was configured with cifs statistics enabled. The statistics
represent the number of successful (ie non-zero return code from the server)
SMB responses to some of the more common commands (open, delete, mkdir etc.).
......
......@@ -201,7 +201,14 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
sprintf(buf,"SMB Request/Response Buffer: %d\n",
bufAllocCount.counter);
length += item_length;
buf += item_length;
buf += item_length;
#ifdef CONFIG_CIFS_EXPERIMENTAL
item_length =
sprintf(buf,"SMB Small Req/Resp Buffer: %d\n",
smBufAllocCount.counter);
length += item_length;
buf += item_length;
#endif /* CIFS_EXPERIMENTAL */
item_length =
sprintf(buf,"Operations (MIDs): %d\n",
midCount.counter);
......@@ -337,7 +344,7 @@ cifs_proc_init(void)
if (pde)
pde->write_proc = oplockEnabled_write;
pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs,
pde = create_proc_read_entry("ReenableOldCifsReaddirCode", 0, proc_fs_cifs,
quotaEnabled_read, NULL);
if (pde)
pde->write_proc = quotaEnabled_write;
......@@ -396,7 +403,7 @@ cifs_proc_clean(void)
remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
remove_proc_entry("QuotaEnabled",proc_fs_cifs);
remove_proc_entry("ReenableOldCifsReaddirCode",proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
remove_proc_entry("cifs", proc_root_fs);
}
......@@ -485,7 +492,7 @@ quotaEnabled_read(char *page, char **start, off_t off,
{
int len;
len = sprintf(page, "%d\n", quotaEnabled);
len = sprintf(page, "%d\n", experimEnabled);
/* could also check if quotas are enabled in kernel
as a whole first */
len -= off;
......@@ -512,9 +519,9 @@ quotaEnabled_write(struct file *file, const char __user *buffer,
if (rc)
return rc;
if (c == '0' || c == 'n' || c == 'N')
quotaEnabled = 0;
experimEnabled = 0;
else if (c == '1' || c == 'y' || c == 'Y')
quotaEnabled = 1;
experimEnabled = 1;
return count;
}
......
/*
* fs/cifs/cifs_fs_sb.h
*
* Copyright (c) International Business Machines Corp., 2002
* Copyright (c) International Business Machines Corp., 2002,2004
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
......@@ -18,8 +18,10 @@
#ifndef _CIFS_FS_SB_H
#define _CIFS_FS_SB_H
#define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */
#define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */
#define CIFS_MOUNT_SET_UID 2 /* set current->euid in create etc. */
#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */
......
......@@ -50,7 +50,7 @@ int cifsFYI = 0;
int cifsERROR = 1;
int traceSMB = 0;
unsigned int oplockEnabled = 1;
unsigned int quotaEnabled = 0;
unsigned int experimEnabled = 0;
unsigned int linuxExtEnabled = 1;
unsigned int lookupCacheEnabled = 1;
unsigned int multiuser_mount = 0;
......@@ -207,6 +207,10 @@ static kmem_cache_t *cifs_inode_cachep;
static kmem_cache_t *cifs_req_cachep;
static kmem_cache_t *cifs_mid_cachep;
kmem_cache_t *cifs_oplock_cachep;
#ifdef CONFIG_CIFS_EXPERIMENTAL
static kmem_cache_t *cifs_sm_req_cachep;
mempool_t *cifs_sm_req_poolp;
#endif /* CIFS_EXPERIMENTAL */
mempool_t *cifs_req_poolp;
mempool_t *cifs_mid_poolp;
......@@ -431,6 +435,20 @@ cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size,
return -EIO;
cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset));
#ifdef CONFIG_CIFS_EXPERIMENTAL /* BB fixme - fix user char * to kernel char * mapping here BB */
/* check whether we can cache writes locally */
if(file->f_dentry->d_sb) {
struct cifs_sb_info *cifs_sb;
cifs_sb = CIFS_SB(file->f_dentry->d_sb);
if(cifs_sb != NULL) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
return cifs_read(file,read_data,
read_size,poffset);
}
}
#endif /* CIFS_EXPERIMENTAL */
if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) {
return generic_file_read(file,read_data,read_size,poffset);
} else {
......@@ -463,7 +481,19 @@ cifs_write_wrapper(struct file * file, const char __user *write_data,
cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset));
#ifdef CONFIG_CIFS_EXPERIMENTAL /* BB fixme - fix user char * to kernel char * mapping here BB */
/* check whether we can cache writes locally */
if(file->f_dentry->d_sb) {
struct cifs_sb_info *cifs_sb;
cifs_sb = CIFS_SB(file->f_dentry->d_sb);
if(cifs_sb != NULL) {
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
return cifs_write(file,write_data,
write_size,poffset);
}
}
}
#endif /* CIFS_EXPERIMENTAL */
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) {
......@@ -495,6 +525,12 @@ struct inode_operations cifs_dir_inode_ops = {
.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 = {
......@@ -598,6 +634,34 @@ cifs_init_request_bufs(void)
kmem_cache_destroy(cifs_req_cachep);
return -ENOMEM;
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
/* 120 bytes is enough for most SMB responses and handle
based requests (but not write response, nor is it
sufficient for path based requests). 112 bytes is 75 more than
sizeof(struct smb_hdr) but still (with slab hdr) just smaller than
128 byte cutoff which should make it easy to alloc off the slab
compared to 17K (5page) alloc of large cifs buffers and not
so large as to force a single page alloc for each slab entry */
cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq",
112, 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;
}
cifs_sm_req_poolp = mempool_create(64,
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;
}
#endif /* CIFS_EXPERIMENTAL */
return 0;
}
......@@ -609,6 +673,12 @@ cifs_destroy_request_bufs(void)
if (kmem_cache_destroy(cifs_req_cachep))
printk(KERN_WARNING
"cifs_destroy_request_cache: error not all structures were freed\n");
#ifdef CONFIG_CIFS_EXPERIMENTAL
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");
#endif /* CIFS_EXPERIMENTAL */
}
static int
......
......@@ -90,5 +90,5 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
size_t, int);
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
#define CIFS_VERSION "1.20"
#define CIFS_VERSION "1.26"
#endif /* _CIFSFS_H */
......@@ -240,6 +240,20 @@ struct cifsLockInfo {
/*
* One of these for each open instance of a file
*/
struct cifs_search_info {
loff_t index_of_last_entry;
__u16 entries_in_buffer;
__u16 info_level;
__u32 resume_key;
char * ntwrk_buf_start;
char * srch_entries_start;
char * presume_name;
unsigned int resume_name_len;
unsigned endOfSearch:1;
unsigned emptyDir:1;
unsigned unicode:1;
};
struct cifsFileInfo {
struct list_head tlist; /* pointer to next fid owned by tcon */
struct list_head flist; /* next fid (file instance) for this inode */
......@@ -250,14 +264,12 @@ struct cifsFileInfo {
/* lock scope id (0 if none) */
struct file * pfile; /* needed for writepage */
struct inode * pInode; /* needed for oplock break */
unsigned endOfSearch:1; /* we have reached end of search */
unsigned closePend:1; /* file is marked to close */
unsigned emptyDir:1;
unsigned invalidHandle:1; /* file closed via session abend */
struct semaphore fh_sem; /* prevents reopen race after dead ses*/
char * search_resume_name;
unsigned int resume_name_length;
__u32 resume_key;
char * search_resume_name; /* BB removeme BB */
unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
struct cifs_search_info srch_inf;
};
/*
......@@ -317,6 +329,8 @@ struct oplock_q_entry {
#define MID_REQUEST_SUBMITTED 2
#define MID_RESPONSE_RECEIVED 4
#define MID_RETRY_NEEDED 8 /* session closed while this request out */
#define MID_NO_RESP_NEEDED 0x10
#define MID_SMALL_BUFFER 0x20 /* 112 byte response buffer instead of 4K */
/*
*****************************************************************
......@@ -399,6 +413,9 @@ GLOBAL_EXTERN atomic_t tconInfoReconnectCount;
/* Various Debug counters to remove someday (BB) */
GLOBAL_EXTERN atomic_t bufAllocCount;
#ifdef CONFIG_CIFS_EXPERIMENTAL
GLOBAL_EXTERN atomic_t smBufAllocCount;
#endif /* CIFS_EXPERIMENTAL */
GLOBAL_EXTERN atomic_t midCount;
/* Misc globals */
......@@ -407,7 +424,7 @@ GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
have the uid/password or Kerberos credential
or equivalent for current user */
GLOBAL_EXTERN unsigned int oplockEnabled;
GLOBAL_EXTERN unsigned int quotaEnabled;
GLOBAL_EXTERN unsigned int experimEnabled;
GLOBAL_EXTERN unsigned int lookupCacheEnabled;
GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */
......
This diff is collapsed.
/*
* fs/cifs/cifsproto.h
*
* Copyright (c) International Business Machines Corp., 2002
* Copyright (c) International Business Machines Corp., 2002,2004
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
......@@ -32,6 +32,10 @@ struct statfs;
extern struct smb_hdr *cifs_buf_get(void);
extern void cifs_buf_release(void *);
#ifdef CONFIG_CIFS_EXPERIMENTAL
extern struct smb_hdr *cifs_small_buf_get(void);
extern void cifs_small_buf_release(void *);
#endif /* CIFS_EXPERIMENTAL */
extern int smb_send(struct socket *, struct smb_hdr *,
unsigned int /* length */ , struct sockaddr *);
extern unsigned int _GetXid(void);
......@@ -233,4 +237,12 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const char * ea_name,
const void * ea_value, const __u16 ea_value_len,
const struct nls_table *nls_codepage);
extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
char *acl_inf, const int buflen,const int acl_type,
const struct nls_table *nls_codepage);
extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
const unsigned char *fileName,
const char *local_acl, const int buflen, const int acl_type,
const struct nls_table *nls_codepage);
#endif /* _CIFSPROTO_H */
This diff is collapsed.
......@@ -69,6 +69,9 @@ struct smb_vol {
unsigned intr:1;
unsigned setuids:1;
unsigned noperm:1;
unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
unsigned direct_io:1;
unsigned int rsize;
unsigned int wsize;
unsigned int sockopt;
......@@ -335,7 +338,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
(checkSMBhdr
(smb_buffer, smb_buffer->Mid))) {
cERROR(1,
("Invalid size or format for SMB found with length %d and pdu_lenght %d",
("Invalid size or format for SMB found with length %d and pdu_length %d",
length, pdu_length));
cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
/* could we fix this network corruption by finding next
......@@ -505,7 +508,7 @@ cifs_kcalloc(size_t size, int type)
}
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 *data;
......@@ -692,7 +695,12 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
vol->file_mode =
simple_strtoul(value, &value, 0);
}
} else if (strnicmp(data, "dir_mode", 3) == 0) {
} else if (strnicmp(data, "dir_mode", 4) == 0) {
if (value && *value) {
vol->dir_mode =
simple_strtoul(value, &value, 0);
}
} else if (strnicmp(data, "dirmode", 4) == 0) {
if (value && *value) {
vol->dir_mode =
simple_strtoul(value, &value, 0);
......@@ -742,6 +750,8 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
/* ignore */
} else if (strnicmp(data, "version", 3) == 0) {
/* ignore */
} else if (strnicmp(data, "guest",5) == 0) {
/* ignore */
} else if (strnicmp(data, "rw", 2) == 0) {
vol->rw = TRUE;
} else if ((strnicmp(data, "suid", 4) == 0) ||
......@@ -780,6 +790,18 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
vol->intr = 0;
} else if (strnicmp(data, "intr", 4) == 0) {
vol->intr = 1;
} else if (strnicmp(data, "serverino",7) == 0) {
vol->server_ino = 1;
} else if (strnicmp(data, "noserverino",9) == 0) {
vol->server_ino = 0;
} else if (strnicmp(data, "acl",3) == 0) {
vol->no_psx_acl = 0;
} else if (strnicmp(data, "noacl",5) == 0) {
vol->no_psx_acl = 1;
} else if (strnicmp(data, "direct",6) == 0) {
vol->direct_io = 1;
} else if (strnicmp(data, "forcedirectio",13) == 0) {
vol->direct_io = 1;
} 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");
} else
......@@ -1393,6 +1415,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
if(volume_info.setuids)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
if(volume_info.server_ino)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
if(volume_info.direct_io) {
cERROR(1,("mounting share using direct i/o"));
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
}
tcon =
find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
......@@ -1482,8 +1510,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* do not care if following two calls succeed - informational only */
CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
if (tcon->ses->capabilities & CAP_UNIX)
CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls);
if (tcon->ses->capabilities & CAP_UNIX) {
if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) {
if(!volume_info.no_psx_acl) {
if(CIFS_UNIX_POSIX_ACL_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))
cFYI(1,("server negotiated posix acl support"));
sb->s_flags |= MS_POSIXACL;
}
}
}
}
/* volume_info.password is freed above when existing session found
......@@ -1552,14 +1588,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
capabilities |= CAP_DFS;
}
pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
/* pSMB->req_no_secext.CaseInsensitivePasswordLength =
CIFS_SESSION_KEY_SIZE; */
pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
pSMB->req_no_secext.CaseInsensitivePasswordLength =
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
pSMB->req_no_secext.CaseSensitivePasswordLength =
cpu_to_le16(CIFS_SESSION_KEY_SIZE);
bcc_ptr = pByteArea(smb_buffer);
/* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE; */
memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE;
memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
bcc_ptr += CIFS_SESSION_KEY_SIZE;
......
......@@ -399,9 +399,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
(" parent inode = 0x%p name is: %s and dentry = 0x%p",
parent_dir_inode, direntry->d_name.name, direntry));
if(nd) { /* BB removeme */
cFYI(1,("In lookup nd flags 0x%x open intent flags 0x%x",nd->flags,nd->intent.open.flags));
} /* BB removeme BB */
/* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */
/* check whether path exists */
......
......@@ -37,7 +37,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
struct cifsTconInfo *pTcon;
char *full_path = NULL;
__u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES;
__u16 netfid;
__u16 netfid;
xid = GetXid();
cifs_sb = CIFS_SB(file->f_dentry->d_sb);
......
This diff is collapsed.
......@@ -85,6 +85,13 @@ cifs_get_inode_info_unix(struct inode **pinode,
*pinode = new_inode(sb);
if(*pinode == NULL)
return -ENOMEM;
/* 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) {
(*pinode)->i_ino =
(unsigned long)findData.UniqueId;
} /* note ino incremented to unique num in new_inode */
insert_inode_hash(*pinode);
}
......@@ -244,6 +251,21 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
*pinode = new_inode(sb);
if(*pinode == NULL)
return -ENOMEM;
/* 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? */
/* We can not use the IndexNumber from either
Windows or Samba as it is frequently set to zero */
/* There may be higher info levels that work but
Are there Windows server or network appliances
for which IndexNumber field is not guaranteed unique? */
/* if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
(*pinode)->i_ino =
(unsigned long)pfindData->IndexNumber;
} */ /*NB: ino incremented to unique num in new_inode*/
insert_inode_hash(*pinode);
}
inode = *pinode;
......@@ -273,10 +295,10 @@ cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
/* new inode, can safely set these fields */
inode->i_mode = cifs_sb->mnt_file_mode;
if (attr & ATTR_REPARSE) {
/* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
inode->i_mode |= S_IFLNK;
} else if (attr & ATTR_DIRECTORY) {
/* if (attr & ATTR_REPARSE) */
/* We no longer handle these as symlinks because we could not */
/* follow them due to the absolute path with drive letter */
if (attr & ATTR_DIRECTORY) {
/* override default perms since we do not do byte range locking on dirs */
inode->i_mode = cifs_sb->mnt_dir_mode;
inode->i_mode |= S_IFDIR;
......
/*
* fs/cifs/misc.c
*
* Copyright (C) International Business Machines Corp., 2002,2003
* Copyright (C) International Business Machines Corp., 2002,2004
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
......@@ -29,6 +29,9 @@
#include "smberr.h"
#include "nterr.h"
#ifdef CONFIG_CIFS_EXPERIMENTAL
extern mempool_t *cifs_sm_req_poolp;
#endif /* CIFS_EXPERIMENTAL */
extern mempool_t *cifs_req_poolp;
extern struct task_struct * oplockThread;
......@@ -160,8 +163,10 @@ cifs_buf_get(void)
(struct smb_hdr *) mempool_alloc(cifs_req_poolp, SLAB_KERNEL | SLAB_NOFS);
/* clear the first few header bytes */
/* clear through bcc + 1, making an even 0x40 bytes */
if (ret_buf) {
memset(ret_buf, 0, sizeof (struct smb_hdr));
memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);
atomic_inc(&bufAllocCount);
}
......@@ -182,6 +187,44 @@ cifs_buf_release(void *buf_to_free)
return;
}
#ifdef CONFIG_CIFS_EXPERIMENTAL
struct smb_hdr *
cifs_small_buf_get(void)
{
struct smb_hdr *ret_buf = NULL;
/* We could use negotiated size instead of max_msgsize -
but it may be more efficient to always alloc same size
albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */
ret_buf =
(struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, SLAB_KERNEL | SLAB_NOFS);
/* clear the first few header bytes */
/* clear through bcc + 1, making an even 0x40 bytes */
if (ret_buf) {
memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);
atomic_inc(&smBufAllocCount);
}
return ret_buf;
}
void
cifs_small_buf_release(void *buf_to_free)
{
if (buf_to_free == NULL) {
cFYI(1, ("Null buffer passed to cifs_small_buf_release"));
return;
}
mempool_free(buf_to_free,cifs_sm_req_poolp);
atomic_dec(&smBufAllocCount);
return;
}
#endif /* CIFS_EXPERIMENTAL */
void
header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
const struct cifsTconInfo *treeCon, int word_count
......
......@@ -69,10 +69,12 @@ const struct smb_to_posix_error mapping_table_ERRDOS[] = {
{ERRinvparm, -EINVAL},
{ERRdiskfull, -ENOSPC},
{ERRinvname, -ENOENT},
{ERRinvlevel,-EOPNOTSUPP},
{ERRdirnotempty, -ENOTEMPTY},
{ERRnotlocked, -ENOLCK},
{ERRalreadyexists, -EEXIST},
{ERRmoredata, -EOVERFLOW},
{ERReasnotsupported,-EOPNOTSUPP},
{ErrQuota, -EDQUOT},
{ErrNotALink, -ENOLINK},
{ERRnetlogonNotStarted,-ENOPROTOOPT},
......@@ -287,7 +289,7 @@ static const struct {
ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT}, {
ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP}, {
ERRDOS, 87, NT_STATUS_SECTION_PROTECTION}, {
ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED}, {
ERRDOS, ERReasnotsupported, NT_STATUS_EAS_NOT_SUPPORTED}, {
ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, {
ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, {
ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, {
......
This diff is collapsed.
......@@ -69,6 +69,7 @@
#define ERRpipeclosing 232
#define ERRnotconnected 233
#define ERRmoredata 234
#define ERReasnotsupported 282
#define ErrQuota 0x200 /* The operation would cause a quota limit to be exceeded. */
#define ErrNotALink 0x201 /* A link operation was performed on a pathname that
was not a link. */
......
......@@ -176,6 +176,143 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
return rc;
}
#ifdef CIFS_EXPERIMENTAL
/* BB finish off this function, adding support for writing set of pages as iovec */
/* and also adding support for operations that need to parse the response smb */
int
CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op)
{
int rc = 0;
unsigned long timeout = 15 * HZ;
struct mid_q_entry *midQ = NULL;
if (ses == NULL) {
cERROR(1,("Null smb session"));
return -EIO;
}
if(ses->server == NULL) {
cERROR(1,("Null tcp session"));
return -EIO;
}
if(pbytes_returned == NULL)
return -EIO;
else
*pbytes_returned = 0;
/* Ensure that we do not send more than 50 overlapping requests
to the same server. We may make this configurable later or
use ses->maxReq */
if(long_op == -1) {
/* oplock breaks must not be held up */
atomic_inc(&ses->server->inFlight);
} else {
spin_lock(&GlobalMid_Lock);
while(1) {
if(atomic_read(&ses->server->inFlight) >= CIFS_MAX_REQ){
spin_unlock(&GlobalMid_Lock);
wait_event(ses->server->request_q,
atomic_read(&ses->server->inFlight)
< CIFS_MAX_REQ);
spin_lock(&GlobalMid_Lock);
} else {
if(ses->server->tcpStatus == CifsExiting) {
spin_unlock(&GlobalMid_Lock);
return -ENOENT;
}
/* can not count locking commands against total since
they are allowed to block on server */
if(long_op < 3) {
/* update # of requests on the wire to server */
atomic_inc(&ses->server->inFlight);
}
spin_unlock(&GlobalMid_Lock);
break;
}
}
}
/* make sure that we sign in the same order that we send on this socket
and avoid races inside tcp sendmsg code that could cause corruption
of smb data */
down(&ses->server->tcpSem);
if (ses->server->tcpStatus == CifsExiting) {
rc = -ENOENT;
goto cifs_out_label;
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
cFYI(1,("tcp session dead - return to caller to retry"));
rc = -EAGAIN;
goto cifs_out_label;
} else if (ses->status != CifsGood) {
/* check if SMB session is bad because we are setting it up */
if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
(in_buf->Command != SMB_COM_NEGOTIATE)) {
rc = -EAGAIN;
goto cifs_out_label;
} /* else ok - we are setting up session */
}
midQ = AllocMidQEntry(in_buf, ses);
if (midQ == NULL) {
up(&ses->server->tcpSem);
/* If not lock req, update # of requests on wire to server */
if(long_op < 3) {
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
}
return -ENOMEM;
}
if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) {
up(&ses->server->tcpSem);
cERROR(1,
("Illegal length, greater than maximum frame, %d ",
in_buf->smb_buf_length));
DeleteMidQEntry(midQ);
/* If not lock req, update # of requests on wire to server */
if(long_op < 3) {
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
}
return -EIO;
}
/* BB can we sign efficiently in this path? */
rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
midQ->midState = MID_REQUEST_SUBMITTED;
/* rc = smb_send2(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec,
(struct sockaddr *) &(ses->server->addr.sockAddr));*/
if(rc < 0) {
DeleteMidQEntry(midQ);
up(&ses->server->tcpSem);
/* If not lock req, update # of requests on wire to server */
if(long_op < 3) {
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
}
return rc;
} else
up(&ses->server->tcpSem);
cifs_out_label:
if(midQ)
DeleteMidQEntry(midQ);
if(long_op < 3) {
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
}
return rc;
}
#endif /* CIFS_EXPERIMENTAL */
int
SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
struct smb_hdr *in_buf, struct smb_hdr *out_buf,
......@@ -307,7 +444,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
/* if signal pending do not hold up user for full smb timeout
but we still give response a change to complete */
timeout = 2 * HZ;
}
/* No user interrupts in wait - wreaks havoc with performance */
......
......@@ -20,6 +20,7 @@
*/
#include <linux/fs.h>
#include <linux/posix_acl_xattr.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
......@@ -27,10 +28,10 @@
#include "cifs_debug.h"
#define MAX_EA_VALUE_SIZE 65535
#define CIFS_XATTR_DOS_ATTRIB "user.DOSATTRIB"
#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
#define CIFS_XATTR_USER_PREFIX "user."
#define CIFS_XATTR_SYSTEM_PREFIX "system."
#define CIFS_XATTR_OS2_PREFIX "OS2." /* BB should check for this someday */
#define CIFS_XATTR_OS2_PREFIX "os2." /* BB should check for this someday */
/* also note could add check for security prefix XATTR_SECURITY_PREFIX */
......@@ -128,16 +129,47 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
if(ea_name == NULL) {
cFYI(1,("Null xattr names not supported"));
} else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)) {
cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name));
} else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) {
if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) {
cFYI(1,("attempt to set cifs inode metadata"));
}
ea_name += 5; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
(__u16)value_size, cifs_sb->local_nls);
} else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
ea_name += 4; /* skip past os2. prefix */
rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
(__u16)value_size, cifs_sb->local_nls);
} else {
int temp;
temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,
strlen(POSIX_ACL_XATTR_ACCESS));
if (temp == 0) {
#ifdef CONFIG_CIFS_POSIX
rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value,
(const int)value_size, ACL_TYPE_ACCESS,
cifs_sb->local_nls);
cFYI(1,("set POSIX ACL rc %d",rc));
#else
cFYI(1,("set POSIX ACL not supported"));
#endif
} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
#ifdef CONFIG_CIFS_POSIX
rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value,
(const int)value_size, ACL_TYPE_DEFAULT,
cifs_sb->local_nls);
cFYI(1,("set POSIX default ACL rc %d",rc));
#else
cFYI(1,("set default POSIX ACL not supported"));
#endif
} else {
cFYI(1,("illegal xattr request %s (only user namespace supported)",ea_name));
/* BB what if no namespace prefix? */
/* Should we just pass them to server, except for
system and perhaps security prefixes? */
} else {
ea_name+=5; /* skip past user. prefix */
rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
(__u16)value_size, cifs_sb->local_nls);
}
}
if (full_path)
kfree(full_path);
FreeXid(xid);
......@@ -163,6 +195,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
sb = direntry->d_inode->i_sb;
if(sb == NULL)
return -EIO;
xid = GetXid();
cifs_sb = CIFS_SB(sb);
......@@ -177,19 +210,48 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
}
/* return dos attributes as pseudo xattr */
/* return alt name if available as pseudo attr */
if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)) {
cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name));
/* BB what if no namespace prefix? */
/* Should we just pass them to server, except for system? */
} else {
/* We could add a check here
if(ea_name == NULL) {
cFYI(1,("Null xattr names not supported"));
} else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) {
if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) {
cFYI(1,("attempt to query cifs inode metadata"));
/* revalidate/getattr then populate from inode */
} /* BB add else when above is implemented */
ea_name += 5; /* skip past user. prefix */
rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
buf_size, cifs_sb->local_nls);
} else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
ea_name += 4; /* skip past os2. prefix */
rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
buf_size, cifs_sb->local_nls);
} else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
#ifdef CONFIG_CIFS_POSIX
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
ea_value, buf_size, ACL_TYPE_ACCESS,
cifs_sb->local_nls);
#else
cFYI(1,("query POSIX ACL not supported yet"));
#endif /* CONFIG_CIFS_POSIX */
} else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
#ifdef CONFIG_CIFS_POSIX
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
ea_value, buf_size, ACL_TYPE_DEFAULT,
cifs_sb->local_nls);
#else
cFYI(1,("query POSIX default ACL not supported yet"));
#endif
} else {
cFYI(1,("illegal xattr name request %s (only user namespace supported)",ea_name));
}
/* We could add an additional check for streams ie
if proc/fs/cifs/streamstoxattr is set then
search server for EAs or streams to
returns as xattrs */
ea_name+=5; /* skip past user. */
rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
buf_size, cifs_sb->local_nls);
}
if(rc == -EINVAL)
rc = -EOPNOTSUPP;
if (full_path)
kfree(full_path);
FreeXid(xid);
......
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