Commit 4be77aab authored by Linus Torvalds's avatar Linus Torvalds

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

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents e8734933 65933b2c
...@@ -1569,20 +1569,30 @@ config CIFS ...@@ -1569,20 +1569,30 @@ config CIFS
This is the client VFS module for the Common Internet File System This is the client VFS module for the Common Internet File System
(CIFS) protocol which is the successor to the Server Message Block (CIFS) protocol which is the successor to the Server Message Block
(SMB) protocol, the native file sharing mechanism for most early (SMB) protocol, the native file sharing mechanism for most early
PC operating systems. CIFS is fully supported by current network PC operating systems. The CIFS protocol is fully supported by
file servers such as Windows 2000 (including Windows NT version 4 file servers such as Windows 2000 (including Windows 2003, NT 4
and Windows XP) as well by Samba (which provides excellent CIFS and Windows XP) as well by Samba (which provides excellent CIFS
server support for Linux and many other operating systems). For server support for Linux and many other operating systems). Currently
production systems the smbfs module may be used instead of this you must use the smbfs client filesystem to access older SMB servers
cifs module since smbfs is currently more stable and provides such as Windows 9x and OS/2.
support for older servers. The intent of this module is to provide the
most advanced network file system function for CIFS compliant servers, The intent of the cifs module is to provide an advanced
network file system client for mounting to CIFS compliant servers,
including support for dfs (hierarchical name space), secure per-user including support for dfs (hierarchical name space), secure per-user
session establishment, safe distributed caching (oplock), optional session establishment, safe distributed caching (oplock), optional
packet signing, Unicode and other internationalization improvements, and packet signing, Unicode and other internationalization improvements,
optional Winbind (nsswitch) integration. This module is in an early and optional Winbind (nsswitch) integration. You do not need to enable
development stage, so unless you are specifically interested in this cifs if running only a (Samba) server. It is possible to enable both
filesystem, just say N. smbfs and cifs (e.g. if you are using CIFS for accessing Windows 2003
and Samba 3 servers, and smbfs for accessing old servers). If you need
to mount to Samba or Windows 2003 servers from this machine, say Y.
config CIFS_STATS
bool "CIFS statistics"
depends on CIFS
help
Enabling this option will cause statistics for each server share
mounted by the cifs client to be displayed in /proc/fs/cifs/DebugData
config NCP_FS config NCP_FS
tristate "NCP file system support (to mount NetWare volumes)" tristate "NCP file system support (to mount NetWare volumes)"
......
Version 1.16
------------
Fix incorrect file size in file handle based setattr on big endian hardware.
Fix oops in build_path_from_dentry when out of memory. Add checks for invalid
and closing file structs in writepage/partialpagewrite. Add statistics
for each mounted share (new menuconfig option). Fix endianness problem in
volume information displayed in /proc/fs/cifs/DebugData (only affects
affects big endian architectures). Prevent renames while constructing
path names for open, mkdir and rmdir.
Version 1.15 Version 1.15
------------ ------------
Change to mempools for alloc smb request buffers and multiplex structs Change to mempools for alloc smb request buffers and multiplex structs
......
...@@ -268,6 +268,8 @@ Misc /proc/fs/cifs Flags and Debug Info ...@@ -268,6 +268,8 @@ Misc /proc/fs/cifs Flags and Debug Info
======================================= =======================================
Informational pseudo-files: Informational pseudo-files:
DebugData Displays information about active CIFS sessions DebugData Displays information about active CIFS sessions
as well as per share statistics (if CONFIG_CIFS_STATS
is enabled in the kernel configuration).
SimultaneousOps Counter which holds maximum number of SimultaneousOps Counter which holds maximum number of
simultaneous outstanding SMB/CIFS requests. simultaneous outstanding SMB/CIFS requests.
Stats Lists summary resource usage information Stats Lists summary resource usage information
...@@ -324,13 +326,25 @@ and for more extensive tracing including the start of smb requests and responses ...@@ -324,13 +326,25 @@ and for more extensive tracing including the start of smb requests and responses
Three other experimental features are under development and to test Three other experimental features are under development and to test
require enabling an ifdef (e.g. by adding "#define CIFS_FCNTL" in cifsglob.h) require enabling an ifdef (e.g. by adding "#define CIFS_FCNTL" in cifsglob.h)
CIFS_QUOTA CONFIG_CIFS_QUOTA
CIFS_XATTR CONFIG_CIFS_XATTR
CIFS_FCNTL (fcntl needed for support of directory change notification) 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
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.).
Also recorded is the total bytes read and bytes written to the server for
that share. Note that due to client caching effects this can be less than the
number of bytes read and written by the application running on the client.
The statistics for the number of total SMBs and oplock breaks are different in
that they represent all for that share, not just those for which the server
returned success.
Also note that "cat /proc/fs/cifs/DebugData" will display some information about Also note that "cat /proc/fs/cifs/DebugData" will display information about
the active sessions and the shares that are mounted. Note: NTLMv2 enablement the active sessions and the shares that are mounted. Note: NTLMv2 enablement
will not work since they its implementation is not quite complete yet. will not work since they its implementation is not quite complete yet.
Do not alter these configuration values unless you are doing specific testing. Do not alter these configuration values unless you are doing specific testing.
......
version 1.14 May 14, 2004 version 1.16 May 27, 2004
A Partial List of Known Problems and Missing Features A Partial List of Missing Features
===================================================== ==================================
Contributions are welcome. There are plenty of opportunities Contributions are welcome. There are plenty of opportunities
for visible, important contributions to this module. Here for visible, important contributions to this module. Here
...@@ -54,7 +54,8 @@ than resending (helps reduce server resource utilization and avoid ...@@ -54,7 +54,8 @@ than resending (helps reduce server resource utilization and avoid
spurious oplock breaks). spurious oplock breaks).
p) Improve performance of readpages by sending more than one read p) Improve performance of readpages by sending more than one read
at a time when 8 pages or more are requested. at a time when 8 pages or more are requested. Evaluate whether
reads larger than 16K would be helpful.
q) For support of Windows9x/98 we need to retry failed mounts q) For support of Windows9x/98 we need to retry failed mounts
to *SMBSERVER (default server name) with the uppercase hostname to *SMBSERVER (default server name) with the uppercase hostname
...@@ -66,8 +67,10 @@ to Windows servers) ...@@ -66,8 +67,10 @@ to Windows servers)
s) Finish fcntl D_NOTIFY support so kde and gnome file list windows s) Finish fcntl D_NOTIFY support so kde and gnome file list windows
will autorefresh will autorefresh
t) Add GUI tool to configure /proc/fs/cifs settings and for display of
the CIFS statistics
KNOWN BUGS (updated May 14, 2004) KNOWN BUGS (updated May 27, 2004)
==================================== ====================================
1) existing symbolic links (Windows reparse points) are recognized but 1) existing symbolic links (Windows reparse points) are recognized but
can not be created remotely. They are implemented for Samba and those that can not be created remotely. They are implemented for Samba and those that
...@@ -88,9 +91,19 @@ than to Windows. ...@@ -88,9 +91,19 @@ than to Windows.
page writes begin in the middle of a page (pages can get zeroed). page writes begin in the middle of a page (pages can get zeroed).
6) Write caching done incorrectly when files are only opened 6) Write caching done incorrectly when files are only opened
with write permission by the application. with write permission by the application.
7) Rename of files that are hardlinked does not work correctly e.g.
ln source target
mv source target
This should be no op since files are linked but in cifs it causes
the source file to go away. This may require implementation of
the cifs POSIX extensions (Unix Extensions version 2) for
it to be done correctly since Samba is failing the rename,
(rather than ignoring it) so the client not knowing they
are linked proceeds to delete the target and then retry the
move which succeeds this time (but the source is gone).
Misc testing to do Misc testing to do
================= ==================
1) check out max path names and max path name components against various server 1) check out max path names and max path name components against various server
types. Return max path name in stat -f information types. Return max path name in stat -f information
...@@ -102,5 +115,6 @@ there are some easy changes that can be done to parallelize sequential writes, ...@@ -102,5 +115,6 @@ there are some easy changes that can be done to parallelize sequential writes,
and when signing is disabled to request larger read sizes (larger than and when signing is disabled to request larger read sizes (larger than
negotiated size) and send larger write sizes to modern servers. negotiated size) and send larger write sizes to modern servers.
4) More exhaustively test the recently added NT4 support 4) More exhaustively test the recently added NT4 support against various
NT4 service pack levels.
...@@ -74,7 +74,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -74,7 +74,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
"---------------------------------------------------\n"); "---------------------------------------------------\n");
buf += length; buf += length;
length = sprintf(buf, "Servers: \n"); length = sprintf(buf, "Servers:\n");
buf += length; buf += length;
i = 0; i = 0;
...@@ -84,13 +84,15 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -84,13 +84,15 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
length = length =
sprintf(buf, sprintf(buf,
"\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\tTCP session status: %d", "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\tTCP status: %d",
i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse),
ses->serverOS, ses->serverNOS, ses->capabilities,ses->status,ses->server->tcpStatus); ses->serverOS, ses->serverNOS, ses->capabilities,ses->status,ses->server->tcpStatus);
buf += length; buf += length;
if(ses->server) { if(ses->server) {
buf += sprintf(buf, "\n\tLocal Users To Same Server: %d SecMode: 0x%x", buf += sprintf(buf, "\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d",
atomic_read(&ses->server->socketUseCount),ses->server->secMode); atomic_read(&ses->server->socketUseCount),
ses->server->secMode,
atomic_read(&ses->server->inFlight));
/* length = sprintf(buf, "\nMIDs: \n"); /* length = sprintf(buf, "\nMIDs: \n");
buf += length; buf += length;
...@@ -113,7 +115,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -113,7 +115,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
sprintf(buf, "\n"); sprintf(buf, "\n");
buf++; buf++;
length = sprintf(buf, "\nShares: \n"); length = sprintf(buf, "\nShares:\n");
buf += length; buf += length;
i = 0; i = 0;
...@@ -123,7 +125,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -123,7 +125,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
length = length =
sprintf(buf, sprintf(buf,
"\n%d) %s Uses: %d on FS: %s with characteristics: 0x%x Attributes: 0x%x\n\tPathComponentMax: %d Status: %d", "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d",
i, tcon->treeName, i, tcon->treeName,
atomic_read(&tcon->useCount), atomic_read(&tcon->useCount),
tcon->nativeFileSystem, tcon->nativeFileSystem,
...@@ -142,6 +144,28 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -142,6 +144,28 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
buf += length; buf += length;
if(tcon->tidStatus == CifsNeedReconnect) if(tcon->tidStatus == CifsNeedReconnect)
buf += sprintf(buf, "\tDISCONNECTED "); buf += sprintf(buf, "\tDISCONNECTED ");
#ifdef CONFIG_CIFS_STATS
length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d",
atomic_read(&tcon->num_smbs_sent),
atomic_read(&tcon->num_oplock_brks));
buf += length;
length = sprintf(buf,"\nReads: %d Bytes %lld",
atomic_read(&tcon->num_reads),
(long long)(tcon->bytes_read));
buf += length;
length = sprintf(buf,"\nWrites: %d Bytes: %lld",
atomic_read(&tcon->num_writes),
(long long)(tcon->bytes_written));
buf += length;
length = sprintf(buf,
"\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d",
atomic_read(&tcon->num_opens),
atomic_read(&tcon->num_deletes),
atomic_read(&tcon->num_mkdirs),
atomic_read(&tcon->num_rmdirs));
buf += length;
#endif
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
......
...@@ -63,18 +63,4 @@ extern int cifsERROR; ...@@ -63,18 +63,4 @@ extern int cifsERROR;
#define cifserror(format,arg...) #define cifserror(format,arg...)
#endif /* _CIFS_DEBUG */ #endif /* _CIFS_DEBUG */
/*
* statistics
* ----------
*/
#ifdef _CIFS_STATISTICS
#define INCREMENT(x) ((x)++)
#define DECREMENT(x) ((x)--)
#define HIGHWATERMARK(x,y) x = MAX((x), (y))
#else
#define INCREMENT(x)
#define DECREMENT(x)
#define HIGHWATERMARK(x,y)
#endif /* _CIFS_STATISTICS */
#endif /* _H_CIFS_DEBUG */ #endif /* _H_CIFS_DEBUG */
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
/* BB when mempool_resize is added back in, we will resize pool on new mount */ /* BB when mempool_resize is added back in, we will resize pool on new mount */
#define CIFS_MIN_RCV_POOL 11 /* enough for progress to five servers */ #define CIFS_MIN_RCV_POOL 11 /* enough for progress to five servers */
#ifdef CIFS_QUOTA #ifdef CONFIG_CIFS_QUOTA
static struct quotactl_ops cifs_quotactl_ops; static struct quotactl_ops cifs_quotactl_ops;
#endif #endif
...@@ -103,7 +103,7 @@ cifs_read_super(struct super_block *sb, void *data, ...@@ -103,7 +103,7 @@ cifs_read_super(struct super_block *sb, void *data,
sb->s_op = &cifs_super_ops; sb->s_op = &cifs_super_ops;
/* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) /* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
#ifdef CIFS_QUOTA #ifdef CONFIG_CIFS_QUOTA
sb->s_qcop = &cifs_quotactl_ops; sb->s_qcop = &cifs_quotactl_ops;
#endif #endif
sb->s_blocksize = CIFS_MAX_MSGSIZE; sb->s_blocksize = CIFS_MAX_MSGSIZE;
...@@ -276,7 +276,7 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) ...@@ -276,7 +276,7 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
return 0; return 0;
} }
#ifdef 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)
{ {
...@@ -509,7 +509,7 @@ struct inode_operations cifs_file_inode_ops = { ...@@ -509,7 +509,7 @@ struct inode_operations cifs_file_inode_ops = {
.getattr = cifs_getattr, /* do we need this anymore? */ .getattr = cifs_getattr, /* do we need this anymore? */
.rename = cifs_rename, .rename = cifs_rename,
.permission = cifs_permission, .permission = cifs_permission,
#ifdef CIFS_XATTR #ifdef CONFIG_CIFS_XATTR
.setxattr = cifs_setxattr, .setxattr = cifs_setxattr,
.getxattr = cifs_getxattr, .getxattr = cifs_getxattr,
.listxattr = cifs_listxattr, .listxattr = cifs_listxattr,
...@@ -524,7 +524,7 @@ struct inode_operations cifs_symlink_inode_ops = { ...@@ -524,7 +524,7 @@ struct inode_operations cifs_symlink_inode_ops = {
/* BB add the following two eventually */ /* BB add the following two eventually */
/* revalidate: cifs_revalidate, /* revalidate: cifs_revalidate,
setattr: cifs_notify_change, *//* BB do we need notify change */ setattr: cifs_notify_change, *//* BB do we need notify change */
#ifdef CIFS_XATTR #ifdef CONFIG_CIFS_XATTR
.setxattr = cifs_setxattr, .setxattr = cifs_setxattr,
.getxattr = cifs_getxattr, .getxattr = cifs_getxattr,
.listxattr = cifs_listxattr, .listxattr = cifs_listxattr,
...@@ -542,7 +542,7 @@ struct file_operations cifs_file_ops = { ...@@ -542,7 +542,7 @@ struct file_operations cifs_file_ops = {
.flush = cifs_flush, .flush = cifs_flush,
.mmap = cifs_file_mmap, .mmap = cifs_file_mmap,
.sendfile = generic_file_sendfile, .sendfile = generic_file_sendfile,
#ifdef CIFS_FCNTL #ifdef CONFIG_CIFS_FCNTL
.fcntl = cifs_fcntl, .fcntl = cifs_fcntl,
#endif #endif
}; };
...@@ -551,7 +551,7 @@ struct file_operations cifs_dir_ops = { ...@@ -551,7 +551,7 @@ struct file_operations cifs_dir_ops = {
.readdir = cifs_readdir, .readdir = cifs_readdir,
.release = cifs_closedir, .release = cifs_closedir,
.read = generic_read_dir, .read = generic_read_dir,
#ifdef CIFS_FCNTL #ifdef CONFIG_CIFS_FCNTL
.fcntl = cifs_fcntl, .fcntl = cifs_fcntl,
#endif #endif
}; };
......
...@@ -93,5 +93,5 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *, ...@@ -93,5 +93,5 @@ 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);
#define CIFS_VERSION "1.15" #define CIFS_VERSION "1.16"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -34,9 +34,14 @@ ...@@ -34,9 +34,14 @@
/* /*
* MAX_REQ is the maximum number of requests that WE will send * MAX_REQ is the maximum number of requests that WE will send
* on one NetBIOS handle concurently. * on one socket concurently. It also matches the most common
* value of max multiplex returned by servers. We may
* eventually want to use the negotiated value (in case
* future servers can handle more) when we are more confident that
* we will not have problems oveloading the socket with pending
* write data.
*/ */
#define MAX_REQ (10) #define CIFS_MAX_REQ 50
#define SERVER_NAME_LENGTH 15 #define SERVER_NAME_LENGTH 15
#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) #define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
...@@ -110,7 +115,8 @@ struct TCP_Server_Info { ...@@ -110,7 +115,8 @@ struct TCP_Server_Info {
struct sockaddr_in sockAddr; struct sockaddr_in sockAddr;
struct sockaddr_in6 sockAddr6; struct sockaddr_in6 sockAddr6;
} addr; } addr;
wait_queue_head_t response_q; wait_queue_head_t response_q;
wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
struct list_head pending_mid_q; struct list_head pending_mid_q;
void *Server_NlsInfo; /* BB - placeholder for future NLS info */ void *Server_NlsInfo; /* BB - placeholder for future NLS info */
unsigned short server_codepage; /* codepage for the server */ unsigned short server_codepage; /* codepage for the server */
...@@ -119,7 +125,8 @@ struct TCP_Server_Info { ...@@ -119,7 +125,8 @@ struct TCP_Server_Info {
char versionMajor; char versionMajor;
char versionMinor; char versionMinor;
int svlocal:1; /* local server or remote */ int svlocal:1; /* local server or remote */
atomic_t socketUseCount; /* indicates if the server has any open cifs sessions */ atomic_t socketUseCount; /* number of open cifs sessions on socket */
atomic_t inFlight; /* number of requests on the wire to server */
enum statusEnum tcpStatus; /* what we think the status is */ enum statusEnum tcpStatus; /* what we think the status is */
struct semaphore tcpSem; struct semaphore tcpSem;
struct task_struct *tsk; struct task_struct *tsk;
...@@ -163,7 +170,7 @@ struct cifsSesInfo { ...@@ -163,7 +170,7 @@ struct cifsSesInfo {
struct semaphore sesSem; struct semaphore sesSem;
struct cifsUidInfo *uidInfo; /* pointer to user info */ struct cifsUidInfo *uidInfo; /* pointer to user info */
struct TCP_Server_Info *server; /* pointer to server info */ struct TCP_Server_Info *server; /* pointer to server info */
atomic_t inUse; /* # of CURRENT users of this ses */ atomic_t inUse; /* # of mounts (tree connections) on this ses */
enum statusEnum status; enum statusEnum status;
__u32 sequence_number; /* needed for CIFS PDU signature */ __u32 sequence_number; /* needed for CIFS PDU signature */
__u16 ipc_tid; /* special tid for connection to IPC share */ __u16 ipc_tid; /* special tid for connection to IPC share */
...@@ -195,6 +202,19 @@ struct cifsTconInfo { ...@@ -195,6 +202,19 @@ struct cifsTconInfo {
__u16 Flags; /* optional support bits */ __u16 Flags; /* optional support bits */
enum statusEnum tidStatus; enum statusEnum tidStatus;
atomic_t useCount; /* how many mounts (explicit or implicit) to this share */ atomic_t useCount; /* how many mounts (explicit or implicit) to this share */
#ifdef CONFIG_CIFS_STATS
atomic_t num_smbs_sent;
atomic_t num_writes;
atomic_t num_reads;
atomic_t num_oplock_brks;
atomic_t num_opens;
atomic_t num_deletes;
atomic_t num_mkdirs;
atomic_t num_rmdirs;
__u64 bytes_read;
__u64 bytes_written;
spinlock_t stat_lock;
#endif
FILE_SYSTEM_DEVICE_INFO fsDevInfo; FILE_SYSTEM_DEVICE_INFO fsDevInfo;
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */
FILE_SYSTEM_UNIX_INFO fsUnixInfo; FILE_SYSTEM_UNIX_INFO fsUnixInfo;
...@@ -294,13 +314,6 @@ struct oplock_q_entry { ...@@ -294,13 +314,6 @@ struct oplock_q_entry {
#define MID_RESPONSE_RECEIVED 4 #define MID_RESPONSE_RECEIVED 4
#define MID_RETRY_NEEDED 8 /* session closed while this request out */ #define MID_RETRY_NEEDED 8 /* session closed while this request out */
struct servers_not_supported { /* @z4a */
struct servers_not_supported *next1; /* @z4a */
char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* @z4a */
/* Server Names in SMB protocol are 15 chars + X'20' */
/* in 16th byte... @z4a */
};
/* /*
***************************************************************** *****************************************************************
* All constants go here * All constants go here
...@@ -398,4 +411,3 @@ GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ ...@@ -398,4 +411,3 @@ GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */
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 linuxExtEnabled; /* enable Linux/Unix CIFS extensions */ GLOBAL_EXTERN unsigned int linuxExtEnabled; /* enable Linux/Unix CIFS extensions */
...@@ -1687,6 +1687,83 @@ struct data_blob { ...@@ -1687,6 +1687,83 @@ struct data_blob {
void (*free) (struct data_blob * data_blob); void (*free) (struct data_blob * data_blob);
}; };
#ifdef CONFIG_CIFS_POSIX
/*
For better POSIX semantics from Linux client, (even better
than the existing CIFS Unix Extensions) we need updated PDUs for:
1) PosixCreateX - to set and return the mode, inode#, device info and
perhaps add a CreateDevice - to create Pipes and other special .inodes
Also note POSIX open flags
2) Close - to return the last write time to do cache across close more safely
3) PosixQFSInfo - to return statfs info
4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes)
5) Mkdir - set mode
And under consideration:
6) FindClose2 (return nanosecond timestamp ??)
7) Use nanosecond timestamps throughout all time fields if
corresponding attribute flag is set
8) sendfile - handle based copy
9) Direct i/o
10) "POSIX ACL" support
11) Misc fcntls?
what about fixing 64 bit alignment
There are also various legacy SMB/CIFS requests used as is
From existing Lanman and NTLM dialects:
--------------------------------------
NEGOTIATE
SESSION_SETUP_ANDX (BB which?)
TREE_CONNECT_ANDX (BB which wct?)
TREE_DISCONNECT (BB add volume timestamp on response)
LOGOFF_ANDX
DELETE (note delete open file behavior)
DELETE_DIRECTORY
READ_AND_X
WRITE_AND_X
LOCKING_AND_X (note posix lock semantics)
RENAME (note rename across dirs and open file rename posix behaviors)
NT_RENAME (for hardlinks) Is this good enough for all features?
FIND_CLOSE2
TRANSACTION2 (18 cases)
SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2
(BB verify that never need to set allocation size)
SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?)
COPY (note support for copy across directories) - FUTURE, OPTIONAL
setting/getting OS/2 EAs - FUTURE (BB can this handle
setting Linux xattrs perfectly) - OPTIONAL
dnotify - FUTURE, OPTIONAL
quota - FUTURE, OPTIONAL
Note that various requests implemented for NT interop such as
NT_TRANSACT (IOCTL) QueryReparseInfo
are unneeded to servers compliant with the CIFS POSIX extensions
From CIFS Unix Extensions:
-------------------------
T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks
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_BASIC) - BB check for missing inode fields
Actually need QUERY_FILE_UNIX_INFO since has inode num
BB what about a) blksize/blkbits/blocks
b) i_version
c) i_rdev
d) notify mask?
e) generation
f) size_seqcount
T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
*/
#endif
#pragma pack() /* resume default structure packing */ #pragma pack() /* resume default structure packing */
#endif /* _CIFSPDU_H */ #endif /* _CIFSPDU_H */
...@@ -37,13 +37,24 @@ ...@@ -37,13 +37,24 @@
#include "cifs_unicode.h" #include "cifs_unicode.h"
#include "cifs_debug.h" #include "cifs_debug.h"
#ifdef CONFIG_CIFS_POSIX
static struct { static struct {
int index; int index;
char *name; char *name;
} protocols[] = { } protocols[] = {
{CIFS_PROT, "\2NT LM 0.12"}, {CIFS_PROT, "\2NT LM 0.12"},
{CIFS_PROT, "\2POSIX 2"},
{BAD_PROT, "\2"} {BAD_PROT, "\2"}
}; };
#else
static struct {
int index;
char *name;
} protocols[] = {
{CIFS_PROT, "\2NT LM 0.12"},
{BAD_PROT, "\2"}
};
#endif
/* Mark as invalid, all open files on tree connections since they /* Mark as invalid, all open files on tree connections since they
...@@ -144,6 +155,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, ...@@ -144,6 +155,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
*request_buf = cifs_buf_get(); *request_buf = cifs_buf_get();
if (*request_buf == 0) { if (*request_buf == 0) {
/* BB should we add a retry in here if not a writepage? */
return -ENOMEM; return -ENOMEM;
} }
/* Although the original thought was we needed the response buf for */ /* Although the original thought was we needed the response buf for */
...@@ -154,6 +166,12 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, ...@@ -154,6 +166,12 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
wct /*wct */ ); wct /*wct */ );
#ifdef CONFIG_CIFS_STATS
if(tcon != NULL) {
atomic_inc(&tcon->num_smbs_sent);
}
#endif
return rc; return rc;
} }
...@@ -418,7 +436,13 @@ CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, ...@@ -418,7 +436,13 @@ CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
(struct smb_hdr *) pSMBr, &bytes_returned, 0); (struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) { if (rc) {
cFYI(1, ("Error in RMFile = %d", rc)); cFYI(1, ("Error in RMFile = %d", rc));
} }
#ifdef CONFIG_CIFS_STATS
else {
atomic_inc(&tcon->num_deletes);
}
#endif
if (pSMB) if (pSMB)
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
if (rc == -EAGAIN) if (rc == -EAGAIN)
...@@ -465,6 +489,12 @@ CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, ...@@ -465,6 +489,12 @@ CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
if (rc) { if (rc) {
cFYI(1, ("Error in RMDir = %d", rc)); cFYI(1, ("Error in RMDir = %d", rc));
} }
#ifdef CONFIG_CIFS_STATS
else {
atomic_inc(&tcon->num_rmdirs);
}
#endif
if (pSMB) if (pSMB)
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
if (rc == -EAGAIN) if (rc == -EAGAIN)
...@@ -510,6 +540,11 @@ CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, ...@@ -510,6 +540,11 @@ CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
if (rc) { if (rc) {
cFYI(1, ("Error in Mkdir = %d", rc)); cFYI(1, ("Error in Mkdir = %d", rc));
} }
#ifdef CONFIG_CIFS_STATS
else {
atomic_inc(&tcon->num_mkdirs);
}
#endif
if (pSMB) if (pSMB)
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
if (rc == -EAGAIN) if (rc == -EAGAIN)
...@@ -606,6 +641,10 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -606,6 +641,10 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
pfile_info->EndOfFile = pSMBr->EndOfFile; pfile_info->EndOfFile = pSMBr->EndOfFile;
pfile_info->NumberOfLinks = cpu_to_le32(1); pfile_info->NumberOfLinks = cpu_to_le32(1);
} }
#ifdef CONFIG_CIFS_STATS
atomic_inc(&tcon->num_opens);
#endif
} }
if (pSMB) if (pSMB)
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
...@@ -728,7 +767,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, ...@@ -728,7 +767,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, long_op); (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
if (rc) { if (rc) {
cERROR(1, ("Send error in write = %d", rc)); cFYI(1, ("Send error in write = %d", rc));
*nbytes = 0; *nbytes = 0;
} else } else
*nbytes = le16_to_cpu(pSMBr->Count); *nbytes = le16_to_cpu(pSMBr->Count);
...@@ -792,7 +831,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, ...@@ -792,7 +831,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
(struct smb_hdr *) pSMBr, &bytes_returned, timeout); (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
if (rc) { if (rc) {
cERROR(1, ("Send error in Lock = %d", rc)); cFYI(1, ("Send error in Lock = %d", rc));
} }
if (pSMB) if (pSMB)
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
...@@ -987,60 +1026,59 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, ...@@ -987,60 +1026,59 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
int int
CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
const __u16 target_tid, const char *toName, const int flags, const __u16 target_tid, const char *toName, const int flags,
const struct nls_table *nls_codepage) const struct nls_table *nls_codepage)
{ {
int rc = 0; int rc = 0;
COPY_REQ *pSMB = NULL; COPY_REQ *pSMB = NULL;
COPY_RSP *pSMBr = NULL; COPY_RSP *pSMBr = NULL;
int bytes_returned; int bytes_returned;
int name_len, name_len2; int name_len, name_len2;
cFYI(1, ("In CIFSSMBCopy")); cFYI(1, ("In CIFSSMBCopy"));
copyRetry: copyRetry:
rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB, rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
(void **) &pSMBr); (void **) &pSMBr);
if (rc) if (rc)
return rc; return rc;
pSMB->BufferFormat = 0x04; pSMB->BufferFormat = 0x04;
pSMB->Tid2 = target_tid; pSMB->Tid2 = target_tid;
if(flags & COPY_TREE) if(flags & COPY_TREE)
pSMB->Flags |= COPY_TREE; pSMB->Flags |= COPY_TREE;
pSMB->Flags = cpu_to_le16(pSMB->Flags); pSMB->Flags = cpu_to_le16(pSMB->Flags);
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName,
cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530 fromName,
/* find define for this maxpathcomponent */ 530 /* find define for this maxpathcomponent */,
, nls_codepage); nls_codepage);
name_len++; /* trailing null */ name_len++; /* trailing null */
name_len *= 2; name_len *= 2;
pSMB->OldFileName[name_len] = 0x04; /* pad */ pSMB->OldFileName[name_len] = 0x04; /* pad */
/* protocol requires ASCII signature byte on Unicode string */ /* protocol requires ASCII signature byte on Unicode string */
pSMB->OldFileName[name_len + 1] = 0x00; pSMB->OldFileName[name_len + 1] = 0x00;
name_len2 = name_len2 = cifs_strtoUCS((wchar_t *) & pSMB->
cifs_strtoUCS((wchar_t *) & pSMB-> OldFileName[name_len + 2], toName, 530,
OldFileName[name_len + 2], toName, 530, nls_codepage);
nls_codepage); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */
name_len2 *= 2; /* convert to bytes */ } else { /* BB improve the check for buffer overruns BB */
} else { /* BB improve the check for buffer overruns BB */ name_len = strnlen(fromName, 530);
name_len = strnlen(fromName, 530); name_len++; /* trailing null */
name_len++; /* trailing null */ strncpy(pSMB->OldFileName, fromName, name_len);
strncpy(pSMB->OldFileName, fromName, name_len); name_len2 = strnlen(toName, 530);
name_len2 = strnlen(toName, 530); name_len2++; /* trailing null */
name_len2++; /* trailing null */ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); name_len2++; /* trailing null */
name_len2++; /* trailing null */ name_len2++; /* signature byte */
name_len2++; /* signature byte */ }
}
pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2; pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2;
pSMB->hdr.smb_buf_length += pSMB->ByteCount; pSMB->hdr.smb_buf_length += pSMB->ByteCount;
pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0); (struct smb_hdr *) pSMBr, &bytes_returned, 0);
...@@ -2281,6 +2319,11 @@ CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon, ...@@ -2281,6 +2319,11 @@ CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon,
(FILE_SYSTEM_ATTRIBUTE_INFO (FILE_SYSTEM_ATTRIBUTE_INFO
*) (((char *) &pSMBr->hdr.Protocol) + *) (((char *) &pSMBr->hdr.Protocol) +
pSMBr->DataOffset); pSMBr->DataOffset);
response_data->Attributes = le32_to_cpu(response_data->Attributes);
response_data->MaxPathNameComponentLength =
le32_to_cpu(response_data->MaxPathNameComponentLength);
response_data->FileSystemNameLen =
le32_to_cpu(response_data->FileSystemNameLen);
memcpy(&tcon->fsAttrInfo, response_data, memcpy(&tcon->fsAttrInfo, response_data,
sizeof (FILE_SYSTEM_ATTRIBUTE_INFO)); sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
} }
...@@ -2350,6 +2393,10 @@ CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon, ...@@ -2350,6 +2393,10 @@ CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon,
(FILE_SYSTEM_DEVICE_INFO (FILE_SYSTEM_DEVICE_INFO
*) (((char *) &pSMBr->hdr.Protocol) + *) (((char *) &pSMBr->hdr.Protocol) +
pSMBr->DataOffset); pSMBr->DataOffset);
response_data->DeviceType =
le32_to_cpu(response_data->DeviceType);
response_data->DeviceCharacteristics =
le32_to_cpu(response_data->DeviceCharacteristics);
memcpy(&tcon->fsDevInfo, response_data, memcpy(&tcon->fsDevInfo, response_data,
sizeof (FILE_SYSTEM_DEVICE_INFO)); sizeof (FILE_SYSTEM_DEVICE_INFO));
} }
...@@ -2360,7 +2407,6 @@ CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon, ...@@ -2360,7 +2407,6 @@ CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon,
if (rc == -EAGAIN) if (rc == -EAGAIN)
goto QFSDeviceRetry; goto QFSDeviceRetry;
return rc; return rc;
} }
...@@ -2418,6 +2464,12 @@ CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon, ...@@ -2418,6 +2464,12 @@ CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon,
(FILE_SYSTEM_UNIX_INFO (FILE_SYSTEM_UNIX_INFO
*) (((char *) &pSMBr->hdr.Protocol) + *) (((char *) &pSMBr->hdr.Protocol) +
pSMBr->DataOffset); pSMBr->DataOffset);
response_data->MajorVersionNumber =
le16_to_cpu(response_data->MajorVersionNumber);
response_data->MinorVersionNumber =
le16_to_cpu(response_data->MinorVersionNumber);
response_data->Capability =
le64_to_cpu(response_data->Capability);
memcpy(&tcon->fsUnixInfo, response_data, memcpy(&tcon->fsUnixInfo, response_data,
sizeof (FILE_SYSTEM_UNIX_INFO)); sizeof (FILE_SYSTEM_UNIX_INFO));
} }
...@@ -2581,7 +2633,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, ...@@ -2581,7 +2633,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
(struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
pSMB->DataOffset); pSMB->DataOffset);
pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */
parm_data->FileSize = size; parm_data->FileSize = cpu_to_le64(size);
pSMB->Fid = fid; pSMB->Fid = fid;
if(SetAllocation) { if(SetAllocation) {
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
......
...@@ -165,6 +165,7 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -165,6 +165,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
} else { } else {
atomic_inc(&tcpSesReconnectCount); atomic_inc(&tcpSesReconnectCount);
server->tcpStatus = CifsGood; server->tcpStatus = CifsGood;
atomic_set(&server->inFlight,0);
wake_up(&server->response_q); wake_up(&server->response_q);
} }
} }
...@@ -390,8 +391,14 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -390,8 +391,14 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
} }
} }
server->tcpStatus = CifsExiting; server->tcpStatus = CifsExiting;
atomic_set(&server->inFlight, 0);
/* Although there should not be any requests blocked on
this queue it can not hurt to be paranoid and try to wake up requests
that may haven been blocked when more than 50 at time were on the wire
to the same server - they now will see the session is in exit state
and get out of SendReceive. */
wake_up_all(&server->request_q);
server->tsk = NULL; server->tsk = NULL;
if(server->ssocket) { if(server->ssocket) {
sock_release(csocket); sock_release(csocket);
...@@ -1211,11 +1218,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1211,11 +1218,13 @@ 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, sizeof (struct sockaddr_in));
/* BB Add code for ipv6 case too */ atomic_set(&srvTcp->inFlight,0);
/* BB Add code for ipv6 case too */
srvTcp->ssocket = csocket; srvTcp->ssocket = csocket;
srvTcp->protocolType = IPV4; srvTcp->protocolType = IPV4;
init_waitqueue_head(&srvTcp->response_q); init_waitqueue_head(&srvTcp->response_q);
init_waitqueue_head(&srvTcp->request_q);
INIT_LIST_HEAD(&srvTcp->pending_mid_q); INIT_LIST_HEAD(&srvTcp->pending_mid_q);
srvTcp->tcpStatus = CifsNew; srvTcp->tcpStatus = CifsNew;
init_MUTEX(&srvTcp->tcpSem); init_MUTEX(&srvTcp->tcpSem);
...@@ -2752,6 +2761,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) ...@@ -2752,6 +2761,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
FreeXid(xid); FreeXid(xid);
return 0; return 0;
} }
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 4); /* give captive thread time to exit */ schedule_timeout(HZ / 4); /* give captive thread time to exit */
if((ses->server) && (ses->server->ssocket)) { if((ses->server) && (ses->server->ssocket)) {
......
...@@ -38,7 +38,7 @@ renew_parental_timestamps(struct dentry *direntry) ...@@ -38,7 +38,7 @@ renew_parental_timestamps(struct dentry *direntry)
do { do {
direntry->d_time = jiffies; direntry->d_time = jiffies;
direntry = direntry->d_parent; direntry = direntry->d_parent;
} while (!IS_ROOT(direntry)); /* BB for DFS case should stop at the root of share which could be lower than root of this mount due to implicit dfs connections */ } while (!IS_ROOT(direntry));
} }
/* Note: caller must free return buffer */ /* Note: caller must free return buffer */
...@@ -49,14 +49,26 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -49,14 +49,26 @@ build_path_from_dentry(struct dentry *direntry)
int namelen = 0; int namelen = 0;
char *full_path; char *full_path;
if(direntry == NULL)
return NULL; /* not much we can do if dentry is freed and
we need to reopen the file after it was closed implicitly
when the server crashed */
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) {
cERROR(1,("corrupt dentry"));
return NULL;
}
} }
namelen += 1; /* allow for trailing null */
full_path = kmalloc(namelen, GFP_KERNEL); full_path = kmalloc(namelen+1, GFP_KERNEL);
namelen--; if(full_path == NULL)
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);) {
namelen -= 1 + temp->d_name.len; namelen -= 1 + temp->d_name.len;
if (namelen < 0) { if (namelen < 0) {
...@@ -68,11 +80,23 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -68,11 +80,23 @@ build_path_from_dentry(struct dentry *direntry)
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) {
cERROR(1,("corrupt dentry"));
kfree(full_path);
return NULL;
}
} }
if (namelen != 0) if (namelen != 0) {
cERROR(1, cERROR(1,
("We did not end path lookup where we expected namelen is %d", ("We did not end path lookup where we expected namelen is %d",
namelen)); namelen));
/* presumably this is only possible if we were racing with a rename
of one of the parent directories (we can not lock the dentries
above us to prevent this, but retrying should be harmless) */
kfree(full_path);
namelen = 0;
goto cifs_bp_rename_retry;
}
return full_path; return full_path;
} }
...@@ -141,11 +165,15 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -141,11 +165,15 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
down(&direntry->d_sb->s_vfs_rename_sem);
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
up(&direntry->d_sb->s_vfs_rename_sem);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
if(nd) { if(nd) {
cFYI(1,("In create for inode %p dentry->inode %p nd flags = 0x%x for %s",inode, direntry->d_inode, nd->flags,full_path));
if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY) if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY)
desiredAccess = GENERIC_READ; desiredAccess = GENERIC_READ;
else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY)
...@@ -173,6 +201,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -173,6 +201,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
oplock = REQ_OPLOCK; oplock = REQ_OPLOCK;
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
if(buf == NULL) {
kfree(full_path);
FreeXid(xid);
return -ENOMEM;
}
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, desiredAccess, CREATE_NOT_DIR,
&fileHandle, &oplock, buf, cifs_sb->local_nls); &fileHandle, &oplock, buf, cifs_sb->local_nls);
...@@ -272,9 +306,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev ...@@ -272,9 +306,13 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
down(&direntry->d_sb->s_vfs_rename_sem);
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
up(&direntry->d_sb->s_vfs_rename_sem);
if (pTcon->ses->capabilities & CAP_UNIX) { if(full_path == NULL)
rc = -ENOMEM;
if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) {
rc = CIFSSMBUnixSetPerms(xid, pTcon, rc = CIFSSMBUnixSetPerms(xid, pTcon,
full_path, mode, current->euid, current->egid, full_path, mode, current->euid, current->egid,
device_number, cifs_sb->local_nls); device_number, cifs_sb->local_nls);
...@@ -298,7 +336,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev ...@@ -298,7 +336,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
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)
{ {
int rc, xid; int xid;
int rc = 0; /* to get around spurious gcc warning, set to zero here */
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode *newInode = NULL; struct inode *newInode = NULL;
...@@ -320,7 +359,15 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name ...@@ -320,7 +359,15 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
cifs_sb = CIFS_SB(parent_dir_inode->i_sb); cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
/* can not grab the rename sem here since it would
deadlock in the cases (beginning of sys_rename itself)
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) {
FreeXid(xid);
return ERR_PTR(-ENOMEM);
}
if (direntry->d_inode != NULL) { if (direntry->d_inode != NULL) {
cFYI(1, (" non-NULL inode in lookup")); cFYI(1, (" non-NULL inode in lookup"));
} else { } else {
...@@ -347,10 +394,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name ...@@ -347,10 +394,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
rc = 0; rc = 0;
d_add(direntry, NULL); d_add(direntry, NULL);
} else { } else {
cERROR(1, cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc));
("Error 0x%x or (%d decimal) on cifs_get_inode_info in lookup", /* BB special case check for Access Denied - watch security
rc, rc)); exposure of returning dir info implicitly via different rc
/* BB special case check for Access Denied - watch security 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 */
} }
if (full_path) if (full_path)
......
...@@ -39,9 +39,18 @@ int cifs_directory_notify(unsigned long arg, struct file * file) ...@@ -39,9 +39,18 @@ int cifs_directory_notify(unsigned long arg, struct file * file)
xid = GetXid(); xid = GetXid();
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;
down(&file->f_dentry->d_sb->s_vfs_rename_sem);
full_path = build_path_from_dentry(file->f_dentry); full_path = build_path_from_dentry(file->f_dentry);
cFYI(1,("cifs dir notify on file %s",full_path)); up(&file->f_dentry->d_sb->s_vfs_rename_sem);
/* CIFSSMBNotify */
if(full_path == NULL) {
rc = -ENOMEM;
} else {
cFYI(1,("cifs dir notify on file %s",full_path));
/* CIFSSMBNotify(xid, pTcon, full_path, cifs_sb->local_nls);*/
}
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
......
...@@ -80,7 +80,13 @@ cifs_open(struct inode *inode, struct file *file) ...@@ -80,7 +80,13 @@ cifs_open(struct inode *inode, struct file *file)
} }
} }
down(&inode->i_sb->s_vfs_rename_sem);
full_path = build_path_from_dentry(file->f_dentry); full_path = build_path_from_dentry(file->f_dentry);
up(&inode->i_sb->s_vfs_rename_sem);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
if ((file->f_flags & O_ACCMODE) == O_RDONLY) if ((file->f_flags & O_ACCMODE) == O_RDONLY)
...@@ -150,8 +156,6 @@ cifs_open(struct inode *inode, struct file *file) ...@@ -150,8 +156,6 @@ cifs_open(struct inode *inode, struct file *file)
cFYI(1, ("cifs_open returned 0x%x ", rc)); cFYI(1, ("cifs_open returned 0x%x ", rc));
cFYI(1, ("oplock: %d ", oplock)); cFYI(1, ("oplock: %d ", oplock));
} else { } else {
if(file->private_data)
kfree(file->private_data);
file->private_data = file->private_data =
kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
if (file->private_data) { if (file->private_data) {
...@@ -281,11 +285,24 @@ static int cifs_reopen_file(struct inode *inode, struct file *file) ...@@ -281,11 +285,24 @@ static int cifs_reopen_file(struct inode *inode, struct file *file)
return 0; return 0;
} }
if(file->f_dentry == NULL) {
up(&pCifsFile->fh_sem);
cFYI(1,("failed file reopen, no valid name if dentry freed"));
FreeXid(xid);
return -EBADF;
}
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
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_dentry); full_path = build_path_from_dentry(file->f_dentry);
if(full_path == NULL) {
up(&pCifsFile->fh_sem);
FreeXid(xid);
return -ENOMEM;
}
cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
if ((file->f_flags & O_ACCMODE) == O_RDONLY) if ((file->f_flags & O_ACCMODE) == O_RDONLY)
...@@ -546,6 +563,9 @@ cifs_write(struct file * file, const char *write_data, ...@@ -546,6 +563,9 @@ 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)
return -EBADF;
xid = GetXid(); xid = GetXid();
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
...@@ -608,12 +628,21 @@ cifs_write(struct file * file, const char *write_data, ...@@ -608,12 +628,21 @@ cifs_write(struct file * file, const char *write_data,
long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */ long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
} }
#ifdef CONFIG_CIFS_STATS
if(total_written > 0) {
atomic_inc(&pTcon->num_writes);
spin_lock(&pTcon->stat_lock);
pTcon->bytes_written += total_written;
spin_unlock(&pTcon->stat_lock);
}
#endif
/* 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(file->f_dentry) {
if(file->f_dentry->d_inode) { if(file->f_dentry->d_inode) {
file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime = file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime =
CURRENT_TIME; CURRENT_TIME;
if (bytes_written > 0) { if (total_written > 0) {
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, *poffset); i_size_write(file->f_dentry->d_inode, *poffset);
} }
...@@ -634,26 +663,22 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) ...@@ -634,26 +663,22 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
int bytes_written = 0; int bytes_written = 0;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
struct inode *inode = page->mapping->host; struct inode *inode;
struct cifsInodeInfo *cifsInode; struct cifsInodeInfo *cifsInode;
struct cifsFileInfo *open_file = NULL; struct cifsFileInfo *open_file = NULL;
struct list_head *tmp; struct list_head *tmp;
struct list_head *tmp1; struct list_head *tmp1;
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
/* figure out which file struct to use
if (file->private_data == NULL) {
return -EBADF;
}
*/
if (!mapping) { if (!mapping) {
return -EFAULT; return -EFAULT;
} else if(!mapping->host) { } else if(!mapping->host) {
return -EFAULT; return -EFAULT;
} }
inode = page->mapping->host;
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
offset += (loff_t)from; offset += (loff_t)from;
write_data = kmap(page); write_data = kmap(page);
write_data += from; write_data += from;
...@@ -678,6 +703,8 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) ...@@ -678,6 +703,8 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
read_lock(&GlobalSMBSeslock); read_lock(&GlobalSMBSeslock);
list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {
open_file = list_entry(tmp,struct cifsFileInfo, flist); open_file = list_entry(tmp,struct cifsFileInfo, flist);
if(open_file->closePend)
continue;
/* We check if file is open for writing first */ /* We check if file is open for writing first */
if((open_file->pfile) && if((open_file->pfile) &&
((open_file->pfile->f_flags & O_RDWR) || ((open_file->pfile->f_flags & O_RDWR) ||
...@@ -691,7 +718,15 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) ...@@ -691,7 +718,15 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
if ((bytes_written > 0) && (offset)) { if ((bytes_written > 0) && (offset)) {
rc = 0; rc = 0;
} else if(bytes_written < 0) { } else if(bytes_written < 0) {
rc = bytes_written; if(rc == -EBADF) {
/* have seen a case in which
kernel seemed to have closed/freed a file
even with writes active so we might as well
see if there are other file structs to try
for the same inode before giving up */
continue;
} else
rc = bytes_written;
} }
break; /* now that we found a valid file handle break; /* now that we found a valid file handle
and tried to write to it we are done, no and tried to write to it we are done, no
...@@ -913,10 +948,15 @@ cifs_read(struct file * file, char *read_data, size_t read_size, ...@@ -913,10 +948,15 @@ cifs_read(struct file * file, char *read_data, size_t read_size,
return rc; return rc;
} }
} else { } else {
#ifdef CONFIG_CIFS_STATS
atomic_inc(&pTcon->num_reads);
spin_lock(&pTcon->stat_lock);
pTcon->bytes_read += total_read;
spin_unlock(&pTcon->stat_lock);
#endif
*poffset += bytes_read; *poffset += bytes_read;
} }
} }
FreeXid(xid); FreeXid(xid);
return total_read; return total_read;
} }
...@@ -1078,7 +1118,12 @@ cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -1078,7 +1118,12 @@ cifs_readpages(struct file *file, struct address_space *mapping,
le16_to_cpu(pSMBr->DataOffset), &lru_pvec); le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
i += bytes_read >> PAGE_CACHE_SHIFT; i += bytes_read >> PAGE_CACHE_SHIFT;
#ifdef CONFIG_CIFS_STATS
atomic_inc(&pTcon->num_reads);
spin_lock(&pTcon->stat_lock);
pTcon->bytes_read += bytes_read;
spin_unlock(&pTcon->stat_lock);
#endif
if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
cFYI(1,("Partial page %d of %d read to cache",i++,num_pages)); cFYI(1,("Partial page %d of %d read to cache",i++,num_pages));
......
...@@ -345,8 +345,15 @@ cifs_unlink(struct inode *inode, struct dentry *direntry) ...@@ -345,8 +345,15 @@ cifs_unlink(struct inode *inode, struct dentry *direntry)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
/* Unlink can be called from rename so we can not grab
the sem here since we deadlock otherwise */
/* down(&direntry->d_sb->s_vfs_rename_sem);*/
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
/* up(&direntry->d_sb->s_vfs_rename_sem);*/
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls); rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
if (!rc) { if (!rc) {
...@@ -427,7 +434,13 @@ cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -427,7 +434,13 @@ cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
down(&inode->i_sb->s_vfs_rename_sem);
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
up(&inode->i_sb->s_vfs_rename_sem);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
/* 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);
if (rc) { if (rc) {
...@@ -480,7 +493,13 @@ cifs_rmdir(struct inode *inode, struct dentry *direntry) ...@@ -480,7 +493,13 @@ cifs_rmdir(struct inode *inode, struct dentry *direntry)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
down(&inode->i_sb->s_vfs_rename_sem);
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
up(&inode->i_sb->s_vfs_rename_sem);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls); rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
...@@ -525,8 +544,14 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry, ...@@ -525,8 +544,14 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
different share. Might eventually add support for this */ different share. Might eventually add support for this */
} }
/* we already have the rename sem so we do not need
to grab it again here to protect the path integrity */
fromName = build_path_from_dentry(source_direntry); fromName = build_path_from_dentry(source_direntry);
toName = build_path_from_dentry(target_direntry); toName = build_path_from_dentry(target_direntry);
if((fromName == NULL) || (toName == NULL)) {
rc = -ENOMEM;
goto cifs_rename_exit;
}
rc = CIFSSMBRename(xid, pTcon, fromName, toName, rc = CIFSSMBRename(xid, pTcon, fromName, toName,
cifs_sb_source->local_nls); cifs_sb_source->local_nls);
...@@ -549,6 +574,8 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry, ...@@ -549,6 +574,8 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
CIFSSMBClose(xid, pTcon, netfid); CIFSSMBClose(xid, pTcon, netfid);
} }
} }
cifs_rename_exit:
if (fromName) if (fromName)
kfree(fromName); kfree(fromName);
if (toName) if (toName)
...@@ -586,7 +613,13 @@ cifs_revalidate(struct dentry *direntry) ...@@ -586,7 +613,13 @@ cifs_revalidate(struct dentry *direntry)
cifs_sb = CIFS_SB(direntry->d_sb); cifs_sb = CIFS_SB(direntry->d_sb);
/* can not safely grab the rename sem here if
rename calls revalidate since that would deadlock */
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
cFYI(1, cFYI(1,
("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld", ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
full_path, direntry->d_inode, full_path, direntry->d_inode,
...@@ -730,7 +763,13 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -730,7 +763,13 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
cifs_sb = CIFS_SB(direntry->d_inode->i_sb); cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
down(&direntry->d_sb->s_vfs_rename_sem);
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
up(&direntry->d_sb->s_vfs_rename_sem);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
cifsInode = CIFS_I(direntry->d_inode); cifsInode = CIFS_I(direntry->d_inode);
/* BB check if we need to refresh inode from server now ? BB */ /* BB check if we need to refresh inode from server now ? BB */
......
...@@ -44,10 +44,18 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, ...@@ -44,10 +44,18 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
cifs_sb_target = CIFS_SB(inode->i_sb); cifs_sb_target = CIFS_SB(inode->i_sb);
pTcon = cifs_sb_target->tcon; pTcon = cifs_sb_target->tcon;
/* No need to check for cross device links since server will do that - BB note DFS case in future though (when we may have to check) */ /* No need to check for cross device links since server will do that
BB note DFS case in future though (when we may have to check) */
down(&inode->i_sb->s_vfs_rename_sem);
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);
up(&inode->i_sb->s_vfs_rename_sem);
if((fromName == NULL) || (toName == NULL)) {
rc = -ENOMEM;
goto cifs_hl_exit;
}
if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX) if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
cifs_sb_target->local_nls); cifs_sb_target->local_nls);
...@@ -70,6 +78,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, ...@@ -70,6 +78,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
cifsInode = CIFS_I(old_file->d_inode); cifsInode = CIFS_I(old_file->d_inode);
cifsInode->time = 0; /* will force revalidate to go get info when needed */ cifsInode->time = 0; /* will force revalidate to go get info when needed */
cifs_hl_exit:
if (fromName) if (fromName)
kfree(fromName); kfree(fromName);
if (toName) if (toName)
...@@ -90,7 +99,15 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ...@@ -90,7 +99,15 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
xid = GetXid(); xid = GetXid();
down(&direntry->d_sb->s_vfs_rename_sem);
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
up(&direntry->d_sb->s_vfs_rename_sem);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
...@@ -149,7 +166,15 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) ...@@ -149,7 +166,15 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
down(&inode->i_sb->s_vfs_rename_sem);
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
up(&inode->i_sb->s_vfs_rename_sem);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
cFYI(1, ("Full path: %s ", full_path)); cFYI(1, ("Full path: %s ", full_path));
cFYI(1, ("symname is %s", symname)); cFYI(1, ("symname is %s", symname));
...@@ -204,7 +229,18 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ...@@ -204,7 +229,18 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
xid = GetXid(); xid = GetXid();
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
/* BB would it be safe against deadlock to grab this sem
even though rename itself grabs the sem and calls lookup? */
/* down(&inode->i_sb->s_vfs_rename_sem);*/
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
/* up(&inode->i_sb->s_vfs_rename_sem);*/
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
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));
......
...@@ -123,6 +123,9 @@ tconInfoAlloc(void) ...@@ -123,6 +123,9 @@ tconInfoAlloc(void)
ret_buf->tidStatus = CifsNew; ret_buf->tidStatus = CifsNew;
INIT_LIST_HEAD(&ret_buf->openFileList); INIT_LIST_HEAD(&ret_buf->openFileList);
init_MUTEX(&ret_buf->tconSem); init_MUTEX(&ret_buf->tconSem);
#ifdef CONFIG_CIFS_STATS
ret_buf->stat_lock = SPIN_LOCK_UNLOCKED;
#endif
write_unlock(&GlobalSMBSeslock); write_unlock(&GlobalSMBSeslock);
} }
return ret_buf; return ret_buf;
...@@ -392,6 +395,9 @@ is_valid_oplock_break(struct smb_hdr *buf) ...@@ -392,6 +395,9 @@ is_valid_oplock_break(struct smb_hdr *buf)
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->tid == buf->Tid) { if (tcon->tid == buf->Tid) {
#ifdef CONFIG_CIFS_STATS
atomic_inc(&tcon->num_oplock_brks);
#endif
list_for_each(tmp1,&tcon->openFileList){ list_for_each(tmp1,&tcon->openFileList){
netfile = list_entry(tmp1,struct cifsFileInfo,tlist); netfile = list_entry(tmp1,struct cifsFileInfo,tlist);
if(pSMB->Fid == netfile->netfid) { if(pSMB->Fid == netfile->netfid) {
......
...@@ -182,31 +182,60 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -182,31 +182,60 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
long timeout; long timeout;
struct mid_q_entry *midQ; struct mid_q_entry *midQ;
if ((ses == NULL) || (ses->server == NULL)) { if (ses == NULL) {
cERROR(1,("Null tcp session or smb session: %p",ses)); cERROR(1,("Null smb session"));
return -EIO;
}
if(ses->server == NULL) {
cERROR(1,("Null tcp session"));
return -EIO; return -EIO;
} }
/* 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 */
/* can not count locking commands against the total since
they are allowed to block on server */
if(long_op < 3) {
/* update # of requests on the wire to this server */
atomic_inc(&ses->server->inFlight);
}
if(atomic_read(&ses->server->inFlight) > CIFS_MAX_REQ) {
wait_event(ses->server->request_q,atomic_read(&ses->server->inFlight) <= CIFS_MAX_REQ);
}
/* 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) { if (ses->server->tcpStatus == CifsExiting) {
return -ENOENT; rc = -ENOENT;
goto out_unlock;
} 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; rc = -EAGAIN;
goto out_unlock;
} 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; rc = -EAGAIN;
goto out_unlock;
} /* else ok - we are setting up session */ } /* else ok - we are setting up session */
} }
/* 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);
midQ = AllocMidQEntry(in_buf, ses); midQ = AllocMidQEntry(in_buf, ses);
if (midQ == NULL) { if (midQ == NULL) {
up(&ses->server->tcpSem); up(&ses->server->tcpSem);
return -EIO; /* 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) { if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) {
...@@ -215,6 +244,11 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -215,6 +244,11 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
("Illegal length, greater than maximum frame, %d ", ("Illegal length, greater than maximum frame, %d ",
in_buf->smb_buf_length)); in_buf->smb_buf_length));
DeleteMidQEntry(midQ); 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; return -EIO;
} }
...@@ -285,10 +319,14 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -285,10 +319,14 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
DeleteMidQEntry(midQ); 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 rc; return rc;
} }
if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) { if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
cERROR(1, cERROR(1,
("Frame too large received. Length: %d Xid: %d", ("Frame too large received. Length: %d Xid: %d",
...@@ -338,8 +376,22 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -338,8 +376,22 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
} }
} }
cifs_no_response_exit: cifs_no_response_exit:
DeleteMidQEntry(midQ); /* BB what if process is killed? DeleteMidQEntry(midQ);
- BB add background daemon to clean up Mid entries from
killed processes & test killing process with active mid */ if(long_op < 3) {
atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
}
return rc;
out_unlock:
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; return rc;
} }
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