]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
authorSteve French <sfrench@us.ibm.com>
Tue, 6 Sep 2005 22:47:31 +0000 (15:47 -0700)
committerSteve French <sfrench@us.ibm.com>
Tue, 6 Sep 2005 22:47:31 +0000 (15:47 -0700)
21 files changed:
fs/cifs/AUTHORS
fs/cifs/CHANGES
fs/cifs/README
fs/cifs/cifs_debug.c
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/fcntl.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/misc.c
fs/cifs/netmisc.c
fs/cifs/readdir.c
fs/cifs/transport.c

index 72fdc10dfdd7c94327ad87efff1dec2adbb67cbd..8848e4dfa026d1eb07be1784d4961a48d62c36ac 100644 (file)
@@ -32,6 +32,10 @@ Domen Puncer
 Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
 Vince Negri and Dave Stahl (for finding an important caching bug)
 Adrian Bunk (kcalloc cleanups)
+Miklos Szeredi 
+Kazeon team for various fixes especially for 2.4 version.
+Asser Ferno (Change Notify support)
+Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
 
 Test case and Bug Report contributors
 -------------------------------------
index 3196d4c4eed36fde53bc857563b2dff2d403abb9..6c73f020ef400bc8a2377fdd9eb51c0c2dc5d810 100644 (file)
@@ -1,8 +1,24 @@
+Version 1.36
+------------
+Add support for mounting to older pre-CIFS servers such as Windows9x and ME.
+For these older servers, add option for passing netbios name of server in
+on mount (servernetbiosname).  Add suspend support for power management, to
+avoid cifsd thread preventing software suspend from working.
+Add mount option for disabling the default behavior of sending byte range lock
+requests to the server (necessary for certain applications which break with
+mandatory lock behavior such as Evolution), and also mount option for
+requesting case insensitive matching for path based requests (requesting
+case sensitive is the default).
+
 Version 1.35
 ------------
 Add writepage performance improvements.  Fix path name conversions
 for long filenames on mounts which were done with "mapchars" mount option
-specified.
+specified.  Ensure multiplex ids do not collide.  Fix case in which 
+rmmod can oops if done soon after last unmount.  Fix truncated
+search (readdir) output when resume filename was a long filename.
+Fix filename conversion when mapchars mount option was specified and
+filename was a long filename.
 
 Version 1.34
 ------------
@@ -11,7 +27,7 @@ Do not oops if root user kills cifs oplock kernel thread or
 kills the cifsd thread (NB: killing the cifs kernel threads is not
 recommended, unmount and rmmod cifs will kill them when they are
 no longer needed).  Fix readdir to ASCII servers (ie older servers
-which do not support Unicode) and also require asterik.
+which do not support Unicode) and also require asterisk.
 Fix out of memory case in which data could be written one page
 off in the page cache.
 
@@ -101,7 +117,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call.
 
 Version 1.25
 ------------
-Fix internationlization problem in cifs readdir with filenames that map to 
+Fix internationalization problem in cifs readdir with filenames that map to 
 longer UTF8 strings than the string on the wire was in Unicode.  Add workaround
 for readdir to netapp servers. Fix search rewind (seek into readdir to return 
 non-consecutive entries).  Do not do readdir when server negotiates 
@@ -276,7 +292,7 @@ Fix caching problem when files opened by multiple clients in which
 page cache could contain stale data, and write through did
 not occur often enough while file was still open when read ahead
 (read oplock) not allowed.  Treat "sep=" when first mount option
-as an overrride of comma as the default separator between mount
+as an override of comma as the default separator between mount
 options. 
 
 Version 1.01
@@ -286,7 +302,7 @@ Allow passwords longer than 16 bytes. Allow null password string.
 Version 1.00
 ------------
 Gracefully clean up failed mounts when attempting to mount to servers such as
-Windows 98 that terminate tcp sessions during prototocol negotiation.  Handle
+Windows 98 that terminate tcp sessions during protocol negotiation.  Handle
 embedded commas in mount parsing of passwords.
 
 Version 0.99
@@ -295,7 +311,7 @@ Invalidate local inode cached pages on oplock break and when last file
 instance is closed so that the client does not continue using stale local
 copy rather than later modified server copy of file.  Do not reconnect
 when server drops the tcp session prematurely before negotiate
-protocol response.  Fix oops in roepen_file when dentry freed.  Allow
+protocol response.  Fix oops in reopen_file when dentry freed.  Allow
 the support for CIFS Unix Extensions to be disabled via proc interface.
 
 Version 0.98
@@ -637,7 +653,7 @@ versions of 2.4 kernel (now builds and works again on kernels at least as early
 Version 0.41
 ------------
 Various minor fixes for Connectathon Posix "basic" file i/o test suite.  Directory caching fixed so hardlinked
-files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked.
+files now return the correct number of links on fstat as they are repeatedly linked and unlinked.
 
 Version 0.40
 ------------
@@ -704,7 +720,7 @@ session)
 and cleaned them up and made them more consistent with other cifs functions. 
 
 7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways 
-(with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
+(with or without Unix extensions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
 nor is the symlink support using the Unix extensions
 
 8) Started adding the readlink and follow_link code 
index 34b0cf7111f384aff0ea2afc9504b95fd67cd564..3b610d08dc1e32353b600fc844c841a24b00905a 100644 (file)
@@ -407,6 +407,13 @@ A partial list of the supported mount options follows:
                This has no effect if the server does not support
                Unicode on the wire.
  nomapchars     Do not translate any of these seven characters (default).
+ nocase         Request case insensitive path name matching (case
+               sensitive is the default if the server suports it).
+ nobrl          Do not send byte range lock requests to the server.
+               This is necessary for certain applications that break
+               with cifs style mandatory byte range locks (and most
+               cifs servers do not yet support requesting advisory
+               byte range locks).
  remount        remount the share (often used to change from ro to rw mounts
                or vice versa)
                
index 4061e43471c1a1dc1822fcae3dca02c4406794f0..f4c6544468abecfe5648d680e2de62c69ee3b99b 100644 (file)
@@ -254,35 +254,51 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
                        buf += sprintf(buf, "\tDISCONNECTED ");
                        length += 14;
                }
-               item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d",
+               item_length = sprintf(buf, "\nSMBs: %d Oplock Breaks: %d",
                        atomic_read(&tcon->num_smbs_sent),
                        atomic_read(&tcon->num_oplock_brks));
                buf += item_length;
                length += item_length;
-               item_length = sprintf(buf,"\nReads: %d Bytes %lld",
+               item_length = sprintf(buf, "\nReads: %d Bytes %lld",
                        atomic_read(&tcon->num_reads),
                        (long long)(tcon->bytes_read));
                buf += item_length;
                length += item_length;
-               item_length = sprintf(buf,"\nWrites: %d Bytes: %lld",
+               item_length = sprintf(buf, "\nWrites: %d Bytes: %lld",
                        atomic_read(&tcon->num_writes),
                        (long long)(tcon->bytes_written));
+                buf += item_length;
+                length += item_length;
+                item_length = sprintf(buf, 
+                       "\nLocks: %d HardLinks: %d Symlinks: %d",
+                        atomic_read(&tcon->num_locks),
+                       atomic_read(&tcon->num_hardlinks),
+                       atomic_read(&tcon->num_symlinks));
+                buf += item_length;
+                length += item_length;
+
+               item_length = sprintf(buf, "\nOpens: %d Closes: %d Deletes: %d",
+                       atomic_read(&tcon->num_opens),
+                       atomic_read(&tcon->num_closes),
+                       atomic_read(&tcon->num_deletes));
                buf += item_length;
                length += item_length;
-               item_length = sprintf(buf,
-                       "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d",
-                       atomic_read(&tcon->num_opens),
-                       atomic_read(&tcon->num_deletes),
+               item_length = sprintf(buf, "\nMkdirs: %d Rmdirs: %d",
                        atomic_read(&tcon->num_mkdirs),
                        atomic_read(&tcon->num_rmdirs));
                buf += item_length;
                length += item_length;
-               item_length = sprintf(buf,
-                       "\nRenames: %d T2 Renames %d",
+               item_length = sprintf(buf, "\nRenames: %d T2 Renames %d",
                        atomic_read(&tcon->num_renames),
                        atomic_read(&tcon->num_t2renames));
                buf += item_length;
                length += item_length;
+               item_length = sprintf(buf, "\nFindFirst: %d FNext %d FClose %d",
+                       atomic_read(&tcon->num_ffirst),
+                       atomic_read(&tcon->num_fnext),
+                       atomic_read(&tcon->num_fclose));
+               buf += item_length;
+               length += item_length;
        }
        read_unlock(&GlobalSMBSeslock);
 
@@ -360,7 +376,7 @@ cifs_proc_init(void)
        if (pde)
                pde->write_proc = oplockEnabled_write;
 
-       pde = create_proc_read_entry("ReenableOldCifsReaddirCode", 0, proc_fs_cifs,
+       pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs,
                                quotaEnabled_read, NULL);
        if (pde)
                pde->write_proc = quotaEnabled_write;
@@ -419,7 +435,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("ReenableOldCifsReaddirCode",proc_fs_cifs);
+       remove_proc_entry("Experimental",proc_fs_cifs);
        remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
        remove_proc_entry("cifs", proc_root_fs);
 }
index ec00d61d53080b1b5e771ba3b0d0d2a83ce6e30a..f799f6f0e7296927af5bfc7203d2c5b489441de5 100644 (file)
@@ -24,6 +24,9 @@
 #define CIFS_MOUNT_DIRECT_IO    8 /* do not write nor read through page cache */
 #define CIFS_MOUNT_NO_XATTR  0x10 /* if set - disable xattr support */
 #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
+#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */
+#define CIFS_MOUNT_UNX_EMUL    0x80 /* Network compat with SFUnix emulation */
+#define CIFS_MOUNT_NO_BRL      0x100 /* No sending byte range locks to srv */
 
 struct cifs_sb_info {
        struct cifsTconInfo *tcon;      /* primary mount */
index 8cc23e7d0d5d34e69924e7752e3a816dd6297cfc..43fb2aafa528cee52e2b6feb826d32cf276c1a3e 100644 (file)
@@ -59,6 +59,8 @@ unsigned int ntlmv2_support = 0;
 unsigned int sign_CIFS_PDUs = 1;
 extern struct task_struct * oplockThread; /* remove sparse warning */
 struct task_struct * oplockThread = NULL;
+extern struct task_struct * dnotifyThread; /* remove sparse warning */
+struct task_struct * dnotifyThread = NULL;
 unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
 module_param(CIFSMaxBufSize, int, 0);
 MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
@@ -73,6 +75,7 @@ module_param(cifs_max_pending, int, 0);
 MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256");
 
 static DECLARE_COMPLETION(cifs_oplock_exited);
+static DECLARE_COMPLETION(cifs_dnotify_exited);
 
 extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
@@ -781,6 +784,8 @@ static int cifs_oplock_thread(void * dummyarg)
 
        oplockThread = current;
        do {
+               if(try_to_freeze()) 
+                       continue;
                set_current_state(TASK_INTERRUPTIBLE);
                
                schedule_timeout(1*HZ);  
@@ -834,8 +839,23 @@ static int cifs_oplock_thread(void * dummyarg)
                                spin_unlock(&GlobalMid_Lock);
                }
        } while(!signal_pending(current));
-       complete_and_exit (&cifs_oplock_exited, 0);
        oplockThread = NULL;
+       complete_and_exit (&cifs_oplock_exited, 0);
+}
+
+static int cifs_dnotify_thread(void * dummyarg)
+{
+       daemonize("cifsdnotifyd");
+       allow_signal(SIGTERM);
+
+       dnotifyThread = current;
+       do {
+               if(try_to_freeze())
+                       continue;
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule_timeout(39*HZ);
+       } while(!signal_pending(current));
+       complete_and_exit (&cifs_dnotify_exited, 0);
 }
 
 static int __init
@@ -884,10 +904,16 @@ init_cifs(void)
                                if (!rc) {                
                                        rc = (int)kernel_thread(cifs_oplock_thread, NULL, 
                                                CLONE_FS | CLONE_FILES | CLONE_VM);
-                                       if(rc > 0)
-                                               return 0;
-                                       else 
+                                       if(rc > 0) {
+                                               rc = (int)kernel_thread(cifs_dnotify_thread, NULL,
+                                                       CLONE_FS | CLONE_FILES | CLONE_VM);
+                                               if(rc > 0)
+                                                       return 0;
+                                               else
+                                                       cERROR(1,("error %d create dnotify thread", rc));
+                                       } else {
                                                cERROR(1,("error %d create oplock thread",rc));
+                                       }
                                }
                                cifs_destroy_request_bufs();
                        }
@@ -916,6 +942,10 @@ exit_cifs(void)
                send_sig(SIGTERM, oplockThread, 1);
                wait_for_completion(&cifs_oplock_exited);
        }
+       if(dnotifyThread) {
+               send_sig(SIGTERM, dnotifyThread, 1);
+               wait_for_completion(&cifs_dnotify_exited);
+       }
 }
 
 MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
index 1fd21f66f2435198e33eca7a2919ef42b08ef6ce..bb3404a99e5f9bef5759d3260f65eb471498ffaa 100644 (file)
@@ -81,6 +81,7 @@ extern int cifs_dir_notify(struct file *, unsigned long arg);
 
 /* Functions related to dir entries */
 extern struct dentry_operations cifs_dentry_ops;
+extern struct dentry_operations cifs_ci_dentry_ops;
 
 /* Functions related to symlinks */
 extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
@@ -96,5 +97,5 @@ extern ssize_t        cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
 extern int cifs_ioctl (struct inode * inode, struct file * filep,
                       unsigned int command, unsigned long arg);
-#define CIFS_VERSION   "1.35"
+#define CIFS_VERSION   "1.36"
 #endif                         /* _CIFSFS_H */
index 81babab265e1a31fcad6c97429fadc8d052890fd..a9c791edede5959c690b088b42e4741758b0894f 100644 (file)
@@ -110,8 +110,9 @@ enum protocolEnum {
  */
 
 struct TCP_Server_Info {
-       char server_Name[SERVER_NAME_LEN_WITH_NULL];    /* 15 chars + X'20'in 16th */
-       char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];        /* Unicode version of server_Name */
+       /* 15 character server name + 0x20 16th byte indicating type = srv */
+       char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
+       char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
        struct socket *ssocket;
        union {
                struct sockaddr_in sockAddr;
@@ -147,8 +148,10 @@ struct TCP_Server_Info {
        /* (returned on Negotiate */
        int capabilities; /* allow selective disabling of caps by smb sess */
        __u16 timeZone;
+       __u16 CurrentMid;         /* multiplex id - rotating counter */
        char cryptKey[CIFS_CRYPTO_KEY_SIZE];
-       char workstation_RFC1001_name[16]; /* 16th byte is always zero */
+       /* 16th byte of RFC1001 workstation name is always null */
+       char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
        __u32 sequence_number; /* needed for CIFS PDU signature */
        char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; 
 };
@@ -214,19 +217,41 @@ struct cifsTconInfo {
        atomic_t num_reads;
        atomic_t num_oplock_brks;
        atomic_t num_opens;
+       atomic_t num_closes;
        atomic_t num_deletes;
        atomic_t num_mkdirs;
        atomic_t num_rmdirs;
        atomic_t num_renames;
        atomic_t num_t2renames;
+       atomic_t num_ffirst;
+       atomic_t num_fnext;
+       atomic_t num_fclose;
+       atomic_t num_hardlinks;
+       atomic_t num_symlinks;
+       atomic_t num_locks;
+#ifdef CONFIG_CIFS_STATS2
+       unsigned long long time_writes;
+       unsigned long long time_reads;
+       unsigned long long time_opens;
+       unsigned long long time_deletes;
+       unsigned long long time_closes;
+       unsigned long long time_mkdirs;
+       unsigned long long time_rmdirs;
+       unsigned long long time_renames;
+       unsigned long long time_t2renames;
+       unsigned long long time_ffirst;
+       unsigned long long time_fnext;
+       unsigned long long time_fclose;
+#endif /* CONFIG_CIFS_STATS2 */
        __u64    bytes_read;
        __u64    bytes_written;
        spinlock_t stat_lock;
-#endif
+#endif /* CONFIG_CIFS_STATS */
        FILE_SYSTEM_DEVICE_INFO fsDevInfo;
        FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo;  /* ok if file system name truncated */
        FILE_SYSTEM_UNIX_INFO fsUnixInfo;
        unsigned retry:1;
+       unsigned nocase:1;
        /* BB add field for back pointer to sb struct? */
 };
 
@@ -306,6 +331,41 @@ CIFS_SB(struct super_block *sb)
        return sb->s_fs_info;
 }
 
+static inline const char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
+{
+       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+               return '/';
+       else
+               return '\\';
+}
+
+#ifdef CONFIG_CIFS_STATS
+#define cifs_stats_inc atomic_inc
+
+static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon,
+                                           unsigned int bytes)
+{
+       if (bytes) {
+               spin_lock(&tcon->stat_lock);
+               tcon->bytes_written += bytes;
+               spin_unlock(&tcon->stat_lock);
+       }
+}
+
+static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
+                                        unsigned int bytes)
+{
+       spin_lock(&tcon->stat_lock);
+       tcon->bytes_read += bytes;
+       spin_unlock(&tcon->stat_lock);
+}
+#else
+
+#define  cifs_stats_inc(field) do {} while(0)
+#define  cifs_stats_bytes_written(tcon, bytes) do {} while(0)
+#define  cifs_stats_bytes_read(tcon, bytes) do {} while(0)
+
+#endif
 
 /* one of these for every pending CIFS request to the server */
 struct mid_q_entry {
@@ -331,6 +391,20 @@ struct oplock_q_entry {
        __u16 netfid;
 };
 
+/* for pending dnotify requests */
+struct dir_notify_req {
+       struct list_head lhead;
+       __le16 Pid;
+       __le16 PidHigh;
+       __u16 Mid;
+       __u16 Tid;
+       __u16 Uid;
+       __u16 netfid;
+       __u32 filter; /* CompletionFilter (for multishot) */
+       int multishot;
+       struct file * pfile;
+};
+
 #define   MID_FREE 0
 #define   MID_REQUEST_ALLOCATED 1
 #define   MID_REQUEST_SUBMITTED 2
@@ -399,6 +473,9 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock;  /* protects list inserts on 3 above */
 
 GLOBAL_EXTERN struct list_head GlobalOplock_Q;
 
+GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */
+GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */
+
 /*
  * Global transaction id (XID) information
  */
index aede6a81316794a1a20de497c9684f96e20f6f0c..cf466595b0d400b459dc23f0c18433f00495669d 100644 (file)
 #define SMB_COM_CLOSE                 0x04 /* triv req/rsp, timestamp ignored */
 #define SMB_COM_DELETE                0x06 /* trivial response */
 #define SMB_COM_RENAME                0x07 /* trivial response */
+#define SMB_COM_QUERY_INFORMATION     0x08 /* aka getattr */
 #define SMB_COM_SETATTR               0x09 /* trivial response */
 #define SMB_COM_LOCKING_ANDX          0x24 /* trivial response */
 #define SMB_COM_COPY                  0x29 /* trivial rsp, fail filename ignrd*/
+#define SMB_COM_OPEN_ANDX             0x2D /* Legacy open for old servers */
 #define SMB_COM_READ_ANDX             0x2E
 #define SMB_COM_WRITE_ANDX            0x2F
 #define SMB_COM_TRANSACTION2          0x32
@@ -52,6 +54,7 @@
 #define SMB_COM_NT_TRANSACT           0xA0
 #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
 #define SMB_COM_NT_CREATE_ANDX        0xA2
+#define SMB_COM_NT_CANCEL             0xA4 /* no response */
 #define SMB_COM_NT_RENAME             0xA5 /* trivial response */
 
 /* Transact2 subcommand codes */
@@ -59,6 +62,7 @@
 #define TRANS2_FIND_FIRST             0x01
 #define TRANS2_FIND_NEXT              0x02
 #define TRANS2_QUERY_FS_INFORMATION   0x03
+#define TRANS2_SET_FS_INFORMATION     0x04
 #define TRANS2_QUERY_PATH_INFORMATION 0x05
 #define TRANS2_SET_PATH_INFORMATION   0x06
 #define TRANS2_QUERY_FILE_INFORMATION 0x07
 /* CreateOptions */
 #define CREATE_NOT_FILE                0x00000001      /* if set must not be file */
 #define CREATE_WRITE_THROUGH   0x00000002
-#define CREATE_NOT_DIR         0x00000040      /* if set must not be directory */
+#define CREATE_SEQUENTIAL       0x00000004
+#define CREATE_SYNC_ALERT       0x00000010
+#define CREATE_ASYNC_ALERT      0x00000020
+#define CREATE_NOT_DIR         0x00000040    /* if set must not be directory */
+#define CREATE_NO_EA_KNOWLEDGE  0x00000200
+#define CREATE_EIGHT_DOT_THREE  0x00000400
 #define CREATE_RANDOM_ACCESS   0x00000800
 #define CREATE_DELETE_ON_CLOSE 0x00001000
+#define CREATE_OPEN_BY_ID       0x00002000
 #define OPEN_REPARSE_POINT     0x00200000
+#define CREATE_OPTIONS_MASK     0x007FFFFF 
+#define CREATE_OPTION_SPECIAL   0x20000000   /* system. NB not sent over wire */
 
 /* ImpersonationLevel flags */
 #define SECURITY_ANONYMOUS      0
@@ -614,6 +626,7 @@ typedef struct smb_com_findclose_req {
 } FINDCLOSE_REQ;
 
 /* OpenFlags */
+#define REQ_MORE_INFO      0x00000001  /* legacy (OPEN_AND_X) only */
 #define REQ_OPLOCK         0x00000002
 #define REQ_BATCHOPLOCK    0x00000004
 #define REQ_OPENDIRONLY    0x00000008
@@ -669,6 +682,62 @@ typedef struct smb_com_open_rsp {
        __u16 ByteCount;        /* bct = 0 */
 } OPEN_RSP;
 
+/* format of legacy open request */
+typedef struct smb_com_openx_req {
+       struct smb_hdr  hdr;    /* wct = 15 */
+       __u8 AndXCommand;
+       __u8 AndXReserved;
+       __le16 AndXOffset;
+       __le16 OpenFlags;
+       __le16 Mode;
+       __le16 Sattr; /* search attributes */
+       __le16 FileAttributes;  /* dos attrs */
+       __le32 CreateTime; /* os2 format */
+       __le16 OpenFunction;
+       __le32 EndOfFile;
+       __le32 Timeout;
+       __le32 Reserved;
+       __u16  ByteCount;  /* file name follows */
+       char   fileName[1];
+} OPENX_REQ;
+
+typedef struct smb_com_openx_rsp {
+       struct smb_hdr  hdr;    /* wct = 15 */
+       __u8 AndXCommand;
+       __u8 AndXReserved;
+       __le16 AndXOffset;
+       __u16  Fid;
+       __le16 FileAttributes;
+       __le32 LastWriteTime; /* os2 format */
+       __le32 EndOfFile;
+       __le16 Access;
+       __le16 FileType;
+       __le16 IPCState;
+       __le16 Action;
+       __u32  FileId;
+       __u16  Reserved;
+       __u16  ByteCount;
+} OPENX_RSP; 
+
+/* Legacy write request for older servers */
+typedef struct smb_com_writex_req {
+        struct smb_hdr hdr;     /* wct = 12 */
+        __u8 AndXCommand;
+        __u8 AndXReserved;
+        __le16 AndXOffset;
+        __u16 Fid;
+        __le32 OffsetLow;
+        __u32 Reserved; /* Timeout */
+        __le16 WriteMode; /* 1 = write through */
+        __le16 Remaining;
+        __le16 Reserved2;
+        __le16 DataLengthLow;
+        __le16 DataOffset;
+        __le16 ByteCount;
+        __u8 Pad;               /* BB check for whether padded to DWORD boundary and optimum performance here */
+        char Data[0];
+} WRITEX_REQ;
+
 typedef struct smb_com_write_req {
        struct smb_hdr hdr;     /* wct = 14 */
        __u8 AndXCommand;
@@ -700,6 +769,21 @@ typedef struct smb_com_write_rsp {
        __u16 ByteCount;
 } WRITE_RSP;
 
+/* legacy read request for older servers */
+typedef struct smb_com_readx_req {
+        struct smb_hdr hdr;     /* wct = 10 */
+        __u8 AndXCommand;
+        __u8 AndXReserved;
+        __le16 AndXOffset;
+        __u16 Fid;
+        __le32 OffsetLow;
+        __le16 MaxCount;
+        __le16 MinCount;                /* obsolete */
+        __le32 Reserved;
+        __le16 Remaining;
+        __le16 ByteCount;
+} READX_REQ;
+
 typedef struct smb_com_read_req {
        struct smb_hdr hdr;     /* wct = 12 */
        __u8 AndXCommand;
@@ -876,6 +960,22 @@ typedef struct smb_com_create_directory_rsp {
        __u16 ByteCount;        /* bct = 0 */
 } CREATE_DIRECTORY_RSP;
 
+typedef struct smb_com_query_information_req {
+       struct smb_hdr hdr;     /* wct = 0 */
+       __le16 ByteCount;       /* 1 + namelen + 1 */
+       __u8 BufferFormat;      /* 4 = ASCII */
+       unsigned char FileName[1];
+} QUERY_INFORMATION_REQ;
+
+typedef struct smb_com_query_information_rsp {
+       struct smb_hdr hdr;     /* wct = 10 */
+       __le16 attr;
+       __le32  last_write_time;
+       __le32 size;
+       __u16  reserved[5];
+       __le16 ByteCount;       /* bcc = 0 */
+} QUERY_INFORMATION_RSP;
+
 typedef struct smb_com_setattr_req {
        struct smb_hdr hdr; /* wct = 8 */
        __le16 attr;
@@ -1411,6 +1511,43 @@ typedef struct smb_com_transaction_qfsi_rsp {
        __u8 Pad;               /* may be three bytes *//* followed by data area */
 } TRANSACTION2_QFSI_RSP;
 
+
+/* SETFSInfo Levels */
+#define SMB_SET_CIFS_UNIX_INFO    0x200
+typedef struct smb_com_transaction2_setfsi_req {
+       struct smb_hdr hdr;     /* wct = 15 */
+       __le16 TotalParameterCount;
+       __le16 TotalDataCount;
+       __le16 MaxParameterCount;
+       __le16 MaxDataCount;
+       __u8 MaxSetupCount;
+       __u8 Reserved;
+       __le16 Flags;
+       __le32 Timeout;
+       __u16 Reserved2;
+       __le16 ParameterCount;  /* 4 */
+       __le16 ParameterOffset;
+       __le16 DataCount;       /* 12 */
+       __le16 DataOffset;
+       __u8 SetupCount;        /* one */
+       __u8 Reserved3;
+       __le16 SubCommand;      /* TRANS2_SET_FS_INFORMATION */
+       __le16 ByteCount;
+       __u8 Pad;
+       __u16 FileNum;          /* Parameters start. */
+       __le16 InformationLevel;/* Parameters end. */
+       __le16 ClientUnixMajor; /* Data start. */
+       __le16 ClientUnixMinor;
+       __le64 ClientUnixCap;   /* Data end */
+} TRANSACTION2_SETFSI_REQ;
+
+typedef struct smb_com_transaction2_setfsi_rsp {
+       struct smb_hdr hdr;     /* wct = 10 */
+       struct trans2_resp t2;
+       __u16 ByteCount;
+} TRANSACTION2_SETFSI_RSP;
+
+
 typedef struct smb_com_transaction2_get_dfs_refer_req {
        struct smb_hdr hdr;     /* wct = 15 */
        __le16 TotalParameterCount;
@@ -1551,12 +1688,20 @@ typedef struct {
        __le16 MinorVersionNumber;
        __le64 Capability;
 } FILE_SYSTEM_UNIX_INFO;       /* Unix extensions info, level 0x200 */
+
+/* Version numbers for CIFS UNIX major and minor. */
+#define CIFS_UNIX_MAJOR_VERSION 1
+#define CIFS_UNIX_MINOR_VERSION 0
+
 /* Linux/Unix extensions capability flags */
 #define CIFS_UNIX_FCNTL_CAP             0x00000001 /* support for fcntl locks */
 #define CIFS_UNIX_POSIX_ACL_CAP         0x00000002 /* support getfacl/setfacl */
 #define CIFS_UNIX_XATTR_CAP             0x00000004 /* support new namespace   */
 #define CIFS_UNIX_EXTATTR_CAP           0x00000008 /* support chattr/chflag   */
+#define CIFS_UNIX_POSIX_PATHNAMES_CAP   0x00000010 /* Use POSIX pathnames on the wire. */
+
 #define CIFS_POSIX_EXTENSIONS           0x00000010 /* support for new QFSInfo */
+
 typedef struct {
        /* For undefined recommended transfer size return -1 in that field */
        __le32 OptimalTransferSize;  /* bsize on some os, iosize on other os */
@@ -1907,18 +2052,17 @@ struct data_blob {
        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
+       3) FindFirst return unique inode number - what about resume key, two 
+       forms short (matches readdir) and full (enough info to cache inodes)
+       4) Mkdir - set mode
        
        And under consideration: 
-       6) FindClose2 (return nanosecond timestamp ??)
-       7) Use nanosecond timestamps throughout all time fields if 
+       5) FindClose2 (return nanosecond timestamp ??)
+       6) 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?
+       7) sendfile - handle based copy
+       8) Direct i/o
+       9) Misc fcntls?
        
        what about fixing 64 bit alignment
        
@@ -1974,7 +2118,7 @@ struct data_blob {
        
  */
 
-/* xsymlink is a symlink format that can be used
+/* xsymlink is a symlink format (used by MacOS) that can be used
    to save symlink info in a regular file when 
    mounted to operating systems that do not
    support the cifs Unix extensions or EAs (for xattr
index ea239dea571e1f0a02374079ca0e918bf072cb01..6943f7c6de08468eb138ae41c833165ec8a67e69 100644 (file)
@@ -47,6 +47,10 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
                        struct smb_hdr * /* input */ ,
                        struct smb_hdr * /* out */ ,
                        int * /* bytes returned */ , const int long_op);
+extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
+                       struct smb_hdr * /* input */ , int hdr_len,
+                       const char * /* SMB data to send */ , int data_len,
+                       int * /* bytes returned */ , const int long_op);
 extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
 extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
 extern int is_valid_oplock_break(struct smb_hdr *smb);
@@ -57,9 +61,9 @@ extern int decode_negTokenInit(unsigned char *security_blob, int length,
 extern int cifs_inet_pton(int, char * source, void *dst);
 extern int map_smb_to_linux_error(struct smb_hdr *smb);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
-                       const struct cifsTconInfo *, int /* specifies length
-                           of fixed section (word count) in two byte units */
-                       );
+                           const struct cifsTconInfo *, int /* length of
+                           fixed section (word count) in two byte units */);
+extern __u16 GetNextMid(struct TCP_Server_Info *server);
 extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, 
                                                 struct cifsTconInfo *);
 extern void DeleteOplockQEntry(struct oplock_q_entry *);
@@ -89,7 +93,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 
 extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
             const char *searchName, const struct nls_table *nls_codepage,
-            __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map);
+            __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep);
 
 extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
             __u16 searchHandle, struct cifs_search_info * psrch_inf);
@@ -101,6 +105,10 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
                        const unsigned char *searchName,
                        FILE_ALL_INFO * findData,
                        const struct nls_table *nls_codepage, int remap);
+extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
+                        const unsigned char *searchName,
+                        FILE_ALL_INFO * findData,
+                        const struct nls_table *nls_codepage, int remap);
 
 extern int CIFSSMBUnixQPathInfo(const int xid,
                        struct cifsTconInfo *tcon,
@@ -125,6 +133,9 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
                        int remap);
 extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
                        struct kstatfs *FSData);
+extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
+                       __u64 cap);
+
 extern int CIFSSMBQFSAttributeInfo(const int xid,
                        struct cifsTconInfo *tcon);
 extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon);
@@ -207,6 +218,11 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
                        const int access_flags, const int omode,
                        __u16 * netfid, int *pOplock, FILE_ALL_INFO *,
                        const struct nls_table *nls_codepage, int remap);
+extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
+                       const char *fileName, const int disposition,
+                       const int access_flags, const int omode,
+                       __u16 * netfid, int *pOplock, FILE_ALL_INFO *,
+                       const struct nls_table *nls_codepage, int remap);
 extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
                        const int smb_file_id);
 
@@ -222,7 +238,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
                        const int netfid, const unsigned int count,
                        const __u64 offset, unsigned int *nbytes, 
-                       const char __user *buf,const int long_op);
+                       const char *buf,const int long_op);
 extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
                        const unsigned char *searchName, __u64 * inode_number,
                        const struct nls_table *nls_codepage, 
@@ -264,7 +280,8 @@ extern int CIFSSMBCopy(int xid,
                        int remap_special_chars);
 extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
                        const int notify_subdirs,const __u16 netfid,
-                       __u32 filter, const struct nls_table *nls_codepage);
+                       __u32 filter, struct file * file, int multishot, 
+                       const struct nls_table *nls_codepage);
 extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
                        const unsigned char *searchName, char * EAData,
                        size_t bufsize, const struct nls_table *nls_codepage,
index 0db0b313d7150f49795c0cc2a765d1abe298f0b0..b8830118f09a0f755e1d733553c06be842ac43b8 100644 (file)
@@ -166,11 +166,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 
        header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
 
-#ifdef CONFIG_CIFS_STATS
-        if(tcon != NULL) {
-                atomic_inc(&tcon->num_smbs_sent);
-        }
-#endif /* CONFIG_CIFS_STATS */
+        if(tcon != NULL)
+                cifs_stats_inc(&tcon->num_smbs_sent);
+
        return rc;
 }  
 
@@ -269,11 +267,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
        header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
                        wct /*wct */ );
 
-#ifdef CONFIG_CIFS_STATS
-        if(tcon != NULL) {
-                atomic_inc(&tcon->num_smbs_sent);
-        }
-#endif /* CONFIG_CIFS_STATS */
+        if(tcon != NULL)
+                cifs_stats_inc(&tcon->num_smbs_sent);
+
        return rc;
 }
 
@@ -330,7 +326,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                      (void **) &pSMB, (void **) &pSMBr);
        if (rc)
                return rc;
-
+       pSMB->hdr.Mid = GetNextMid(server);
        pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
        if (extended_security)
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
@@ -422,8 +418,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                }
                                
        }
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       
+       cifs_buf_release(pSMB);
        return rc;
 }
 
@@ -518,6 +514,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
        smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
        
        if(ses->server) {
+               pSMB->hdr.Mid = GetNextMid(ses->server);
+
                if(ses->server->secMode & 
                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
@@ -537,9 +535,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
                        rc = -ESHUTDOWN;
                }
        }
-       if (pSMB)
-               cifs_small_buf_release(pSMB);
        up(&ses->sesSem);
+       cifs_small_buf_release(pSMB);
 
        /* if session dead then we do not need to do ulogoff,
                since server closed smb session, no sense reporting 
@@ -583,14 +580,10 @@ DelFileRetry:
        pSMB->ByteCount = cpu_to_le16(name_len + 1);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&tcon->num_deletes);
        if (rc) {
                cFYI(1, ("Error in RMFile = %d", rc));
        } 
-#ifdef CONFIG_CIFS_STATS
-        else {
-               atomic_inc(&tcon->num_deletes);
-        }
-#endif
 
        cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
@@ -632,14 +625,10 @@ RmDirRetry:
        pSMB->ByteCount = cpu_to_le16(name_len + 1);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&tcon->num_rmdirs);
        if (rc) {
                cFYI(1, ("Error in RMDir = %d", rc));
        }
-#ifdef CONFIG_CIFS_STATS
-        else {
-               atomic_inc(&tcon->num_rmdirs);
-        }
-#endif
 
        cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
@@ -680,20 +669,157 @@ MkDirRetry:
        pSMB->ByteCount = cpu_to_le16(name_len + 1);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&tcon->num_mkdirs);
        if (rc) {
                cFYI(1, ("Error in Mkdir = %d", rc));
        }
-#ifdef CONFIG_CIFS_STATS
-        else {
-               atomic_inc(&tcon->num_mkdirs);
-        }
-#endif
+
        cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
                goto MkDirRetry;
        return rc;
 }
 
+static __u16 convert_disposition(int disposition)
+{
+       __u16 ofun = 0;
+
+       switch (disposition) {
+               case FILE_SUPERSEDE:
+                       ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
+                       break;
+               case FILE_OPEN:
+                       ofun = SMBOPEN_OAPPEND;
+                       break;
+               case FILE_CREATE:
+                       ofun = SMBOPEN_OCREATE;
+                       break;
+               case FILE_OPEN_IF:
+                       ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
+                       break;
+               case FILE_OVERWRITE:
+                       ofun = SMBOPEN_OTRUNC;
+                       break;
+               case FILE_OVERWRITE_IF:
+                       ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
+                       break;
+               default:
+                       cFYI(1,("unknown disposition %d",disposition));
+                       ofun =  SMBOPEN_OAPPEND; /* regular open */
+       }
+       return ofun;
+}
+
+int
+SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
+           const char *fileName, const int openDisposition,
+           const int access_flags, const int create_options, __u16 * netfid,
+            int *pOplock, FILE_ALL_INFO * pfile_info,
+           const struct nls_table *nls_codepage, int remap)
+{
+       int rc = -EACCES;
+       OPENX_REQ *pSMB = NULL;
+       OPENX_RSP *pSMBr = NULL;
+       int bytes_returned;
+       int name_len;
+       __u16 count;
+
+OldOpenRetry:
+       rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       pSMB->AndXCommand = 0xFF;       /* none */
+
+       if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+               count = 1;      /* account for one byte pad to word boundary */
+               name_len =
+                  cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
+                                   fileName, PATH_MAX, nls_codepage, remap);
+               name_len++;     /* trailing null */
+               name_len *= 2;
+       } else {                /* BB improve check for buffer overruns BB */
+               count = 0;      /* no pad */
+               name_len = strnlen(fileName, PATH_MAX);
+               name_len++;     /* trailing null */
+               strncpy(pSMB->fileName, fileName, name_len);
+       }
+       if (*pOplock & REQ_OPLOCK)
+               pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
+       else if (*pOplock & REQ_BATCHOPLOCK) {
+               pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
+       }
+       pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
+       /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
+       /* 0 = read
+          1 = write
+          2 = rw
+          3 = execute
+        */
+       pSMB->Mode = cpu_to_le16(2);
+       pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
+       /* set file as system file if special file such
+          as fifo and server expecting SFU style and
+          no Unix extensions */
+
+        if(create_options & CREATE_OPTION_SPECIAL)
+                pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
+        else
+                pSMB->FileAttributes = cpu_to_le16(ATTR_NORMAL);
+
+       /* if ((omode & S_IWUGO) == 0)
+               pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
+       /*  Above line causes problems due to vfs splitting create into two
+           pieces - need to set mode after file created not while it is
+           being created */
+
+       /* BB FIXME BB */
+/*     pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
+       /* BB FIXME END BB */
+       pSMB->OpenFunction = convert_disposition(openDisposition);
+       count += name_len;
+       pSMB->hdr.smb_buf_length += count;
+
+       pSMB->ByteCount = cpu_to_le16(count);
+       /* long_op set to 1 to allow for oplock break timeouts */
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 1);
+       cifs_stats_inc(&tcon->num_opens);
+       if (rc) {
+               cFYI(1, ("Error in Open = %d", rc));
+       } else {
+       /* BB verify if wct == 15 */
+
+/*             *pOplock = pSMBr->OplockLevel; */  /* BB take from action field BB */
+
+               *netfid = pSMBr->Fid;   /* cifs fid stays in le */
+               /* Let caller know file was created so we can set the mode. */
+               /* Do we care about the CreateAction in any other cases? */
+       /* BB FIXME BB */
+/*             if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
+                       *pOplock |= CIFS_CREATE_ACTION; */
+       /* BB FIXME END */
+
+               if(pfile_info) {
+                       pfile_info->CreationTime = 0; /* BB convert CreateTime*/
+                       pfile_info->LastAccessTime = 0; /* BB fixme */
+                       pfile_info->LastWriteTime = 0; /* BB fixme */
+                       pfile_info->ChangeTime = 0;  /* BB fixme */
+                       pfile_info->Attributes = pSMBr->FileAttributes; 
+                       /* the file_info buf is endian converted by caller */
+                       pfile_info->AllocationSize = pSMBr->EndOfFile;
+                       pfile_info->EndOfFile = pSMBr->EndOfFile;
+                       pfile_info->NumberOfLinks = cpu_to_le32(1);
+               }
+       }
+
+       cifs_buf_release(pSMB);
+       if (rc == -EAGAIN)
+               goto OldOpenRetry;
+       return rc;
+}
+
 int
 CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
            const char *fileName, const int openDisposition,
@@ -738,7 +864,13 @@ openRetry:
        }
        pSMB->DesiredAccess = cpu_to_le32(access_flags);
        pSMB->AllocationSize = 0;
-       pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
+       /* set file as system file if special file such
+          as fifo and server expecting SFU style and
+          no Unix extensions */
+       if(create_options & CREATE_OPTION_SPECIAL)
+               pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
+       else
+               pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
        /* XP does not handle ATTR_POSIX_SEMANTICS */
        /* but it helps speed up case sensitive checks for other
        servers such as Samba */
@@ -752,7 +884,7 @@ openRetry:
                being created */
        pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
        pSMB->CreateDisposition = cpu_to_le32(openDisposition);
-       pSMB->CreateOptions = cpu_to_le32(create_options);
+       pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
        /* BB Expirement with various impersonation levels and verify */
        pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
        pSMB->SecurityFlags =
@@ -765,6 +897,7 @@ openRetry:
        /* long_op set to 1 to allow for oplock break timeouts */
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 1);
+       cifs_stats_inc(&tcon->num_opens);
        if (rc) {
                cFYI(1, ("Error in Open = %d", rc));
        } else {
@@ -782,11 +915,8 @@ openRetry:
                    pfile_info->EndOfFile = pSMBr->EndOfFile;
                    pfile_info->NumberOfLinks = cpu_to_le32(1);
                }
-
-#ifdef CONFIG_CIFS_STATS
-               atomic_inc(&tcon->num_opens);
-#endif
        }
+
        cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
                goto openRetry;
@@ -807,11 +937,16 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
        READ_RSP *pSMBr = NULL;
        char *pReadData = NULL;
        int bytes_returned;
+       int wct;
 
        cFYI(1,("Reading %d bytes on fid %d",count,netfid));
+       if(tcon->ses->capabilities & CAP_LARGE_FILES)
+               wct = 12;
+       else
+               wct = 10; /* old style read */
 
        *nbytes = 0;
-       rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
+       rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
                      (void **) &pSMBr);
        if (rc)
                return rc;
@@ -823,14 +958,26 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
-       pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+       if(wct == 12)
+               pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
+        else if((lseek >> 32) > 0) /* can not handle this big offset for old */
+                return -EIO;
+
        pSMB->Remaining = 0;
        pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
        pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
-       pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
-
+       if(wct == 12)
+               pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
+       else {
+               /* old style read */
+               struct smb_com_readx_req * pSMBW = 
+                       (struct smb_com_readx_req *)pSMB;
+               pSMBW->ByteCount = 0;   
+       }
+       
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&tcon->num_reads);
        if (rc) {
                cERROR(1, ("Send error in read = %d", rc));
        } else {
@@ -876,12 +1023,20 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        int rc = -EACCES;
        WRITE_REQ *pSMB = NULL;
        WRITE_RSP *pSMBr = NULL;
-       int bytes_returned;
+       int bytes_returned, wct;
        __u32 bytes_sent;
        __u16 byte_count;
 
        /* cFYI(1,("write at %lld %d bytes",offset,count));*/
-       rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
+       if(tcon->ses == NULL)
+               return -ECONNABORTED;
+
+       if(tcon->ses->capabilities & CAP_LARGE_FILES)
+               wct = 14;
+       else
+               wct = 12;
+
+       rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
                      (void **) &pSMBr);
        if (rc)
                return rc;
@@ -892,7 +1047,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
-       pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+       if(wct == 14) 
+               pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
+       else if((offset >> 32) > 0) /* can not handle this big offset for old */
+               return -EIO;
+       
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
        pSMB->Remaining = 0;
@@ -929,10 +1088,18 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
        pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
        pSMB->hdr.smb_buf_length += bytes_sent+1;
-       pSMB->ByteCount = cpu_to_le16(byte_count);
+
+       if(wct == 14)
+               pSMB->ByteCount = cpu_to_le16(byte_count);
+       else { /* old style write has byte count 4 bytes earlier */
+               struct smb_com_writex_req * pSMBW = 
+                       (struct smb_com_writex_req *)pSMB;
+               pSMBW->ByteCount = cpu_to_le16(byte_count);
+       }
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
+       cifs_stats_inc(&tcon->num_writes);
        if (rc) {
                cFYI(1, ("Send error in write = %d", rc));
                *nbytes = 0;
@@ -951,56 +1118,70 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 }
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
+int
+CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
             const int netfid, const unsigned int count,
-            const __u64 offset, unsigned int *nbytes, const char __user *buf,
+            const __u64 offset, unsigned int *nbytes, const char *buf,
             const int long_op)
 {
        int rc = -EACCES;
        WRITE_REQ *pSMB = NULL;
-       WRITE_RSP *pSMBr = NULL;
-       /*int bytes_returned;*/
-       unsigned bytes_sent;
+       int bytes_returned;
+       int smb_hdr_len;
+       __u32 bytes_sent;
        __u16 byte_count;
 
+       cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
        rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
-    
        if (rc)
                return rc;
-       
-       pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
-
        /* tcon and ses pointer are checked in smb_init */
        if (tcon->ses->server == NULL)
                return -ECONNABORTED;
 
-       pSMB->AndXCommand = 0xFF; /* none */
+       pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = netfid;
        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
        pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
        pSMB->Reserved = 0xFFFFFFFF;
        pSMB->WriteMode = 0;
        pSMB->Remaining = 0;
-       bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
+
+       /* Can increase buffer size if buffer is big enough in some cases - ie 
+       can send more if LARGE_WRITE_X capability returned by the server and if
+       our buffer is big enough or if we convert to iovecs on socket writes
+       and eliminate the copy to the CIFS buffer */
+       if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
+               bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
+       } else {
+               bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
+                        & ~0xFF;
+       }
+
        if (bytes_sent > count)
                bytes_sent = count;
-       pSMB->DataLengthHigh = 0;
        pSMB->DataOffset =
            cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
 
-       byte_count = bytes_sent + 1 /* pad */ ;
-       pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
-       pSMB->DataLengthHigh = 0;
-       pSMB->hdr.smb_buf_length += byte_count;
+       byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
+       pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
+       pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
+       smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
+       pSMB->hdr.smb_buf_length += bytes_sent+1;
        pSMB->ByteCount = cpu_to_le16(byte_count);
 
-/*     rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB,
-                        (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */  /* BB fixme BB */
+       rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
+                         buf, bytes_sent, &bytes_returned, long_op);
+       cifs_stats_inc(&tcon->num_writes);
        if (rc) {
-               cFYI(1, ("Send error in write2 (large write) = %d", rc));
+               cFYI(1, ("Send error in write = %d", rc));
                *nbytes = 0;
-       } else
-               *nbytes = le16_to_cpu(pSMBr->Count);
+       } else {
+               WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
+               *nbytes = le16_to_cpu(pSMBr->CountHigh);
+               *nbytes = (*nbytes) << 16;
+               *nbytes += le16_to_cpu(pSMBr->Count);
+       }
 
        cifs_small_buf_release(pSMB);
 
@@ -1009,6 +1190,8 @@ int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 
        return rc;
 }
+
+
 #endif /* CIFS_EXPERIMENTAL */
 
 int
@@ -1065,7 +1248,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
-
+       cifs_stats_inc(&tcon->num_locks);
        if (rc) {
                cFYI(1, ("Send error in Lock = %d", rc));
        }
@@ -1099,6 +1282,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
        pSMB->ByteCount = 0;
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&tcon->num_closes);
        if (rc) {
                if(rc!=-EINTR) {
                        /* EINTR is expected when user ctl-c to kill app */
@@ -1171,16 +1355,11 @@ renameRetry:
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&tcon->num_renames);
        if (rc) {
                cFYI(1, ("Send error in rename = %d", rc));
        } 
 
-#ifdef CONFIG_CIFS_STATS
-         else {
-               atomic_inc(&tcon->num_renames);
-       }
-#endif
-
        cifs_buf_release(pSMB);
 
        if (rc == -EAGAIN)
@@ -1255,14 +1434,11 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&pTcon->num_t2renames);
        if (rc) {
                cFYI(1,("Send error in Rename (by file handle) = %d", rc));
        }
-#ifdef CONFIG_CIFS_STATS
-         else {
-               atomic_inc(&pTcon->num_t2renames);
-       }
-#endif
+
        cifs_buf_release(pSMB);
 
        /* Note: On -EAGAIN error only caller can retry on handle based calls
@@ -1416,6 +1592,7 @@ createSymLinkRetry:
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&tcon->num_symlinks);
        if (rc) {
                cFYI(1,
                     ("Send error in SetPathInfo (create symlink) = %d",
@@ -1505,6 +1682,7 @@ createHardLinkRetry:
        pSMB->ByteCount = cpu_to_le16(byte_count);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&tcon->num_hardlinks);
        if (rc) {
                cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
        }
@@ -1575,6 +1753,7 @@ winCreateHardLinkRetry:
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&tcon->num_hardlinks);
        if (rc) {
                cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
        }
@@ -1775,8 +1954,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
                }
        }
 qreparse_out:
-       if (pSMB)
-               cifs_buf_release(pSMB);
+       cifs_buf_release(pSMB);
 
        /* Note: On -EAGAIN error only caller can retry on handle based calls
                since file handle passed in no longer valid */
@@ -2165,6 +2343,65 @@ GetExtAttrOut:
 
 #endif /* CONFIG_POSIX */
 
+/* Legacy Query Path Information call for lookup to old servers such
+   as Win9x/WinME */
+int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
+                 const unsigned char *searchName,
+                 FILE_ALL_INFO * pFinfo,
+                 const struct nls_table *nls_codepage, int remap)
+{
+       QUERY_INFORMATION_REQ * pSMB;
+       QUERY_INFORMATION_RSP * pSMBr;
+       int rc = 0;
+       int bytes_returned;
+       int name_len;
+
+       cFYI(1, ("In SMBQPath path %s", searchName)); 
+QInfRetry:
+       rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
+                      (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+               name_len =
+                    cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+                                     PATH_MAX, nls_codepage, remap);
+               name_len++;     /* trailing null */
+               name_len *= 2;
+       } else {               
+               name_len = strnlen(searchName, PATH_MAX);
+               name_len++;     /* trailing null */
+               strncpy(pSMB->FileName, searchName, name_len);
+       }
+       pSMB->BufferFormat = 0x04;
+       name_len++; /* account for buffer type byte */  
+       pSMB->hdr.smb_buf_length += (__u16) name_len;
+       pSMB->ByteCount = cpu_to_le16(name_len);
+
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc) {
+               cFYI(1, ("Send error in QueryInfo = %d", rc));
+       } else if (pFinfo) {            /* decode response */
+               memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
+               pFinfo->AllocationSize = (__le64) pSMBr->size;
+               pFinfo->EndOfFile = (__le64) pSMBr->size;
+               pFinfo->Attributes = (__le32) pSMBr->attr;
+       } else
+               rc = -EIO; /* bad buffer passed in */
+
+       cifs_buf_release(pSMB);
+
+       if (rc == -EAGAIN)
+               goto QInfRetry;
+
+       return rc;
+}
+
+
+
+
 int
 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
                 const unsigned char *searchName,
@@ -2396,7 +2633,7 @@ findUniqueRetry:
        if (rc) {
                cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
        } else {                /* decode response */
-
+               cifs_stats_inc(&tcon->num_ffirst);
                /* BB fill in */
        }
 
@@ -2414,7 +2651,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
              const char *searchName, 
              const struct nls_table *nls_codepage,
              __u16 *   pnetfid,
-             struct cifs_search_info * psrch_inf, int remap)
+             struct cifs_search_info * psrch_inf, int remap, const char dirsep)
 {
 /* level 257 SMB_ */
        TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -2441,7 +2678,7 @@ findFirstRetry:
                it got remapped to 0xF03A as if it were part of the
                directory name instead of a wildcard */
                name_len *= 2;
-               pSMB->FileName[name_len] = '\\';
+               pSMB->FileName[name_len] = dirsep;
                pSMB->FileName[name_len+1] = 0;
                pSMB->FileName[name_len+2] = '*';
                pSMB->FileName[name_len+3] = 0;
@@ -2455,7 +2692,7 @@ findFirstRetry:
                if(name_len > buffersize-header)
                        free buffer exit; BB */
                strncpy(pSMB->FileName, searchName, name_len);
-               pSMB->FileName[name_len] = '\\';
+               pSMB->FileName[name_len] = dirsep;
                pSMB->FileName[name_len+1] = '*';
                pSMB->FileName[name_len+2] = 0;
                name_len += 3;
@@ -2496,6 +2733,7 @@ findFirstRetry:
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       cifs_stats_inc(&tcon->num_ffirst);
 
        if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
                /* BB Add code to handle unsupported level rc */
@@ -2617,7 +2855,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                                                                                               
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
-                                                                                              
+       cifs_stats_inc(&tcon->num_fnext);
        if (rc) {
                if (rc == -EBADF) {
                        psrch_inf->endOfSearch = TRUE;
@@ -2694,6 +2932,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
        if (rc) {
                cERROR(1, ("Send error in FindClose = %d", rc));
        }
+       cifs_stats_inc(&tcon->num_fclose);
        cifs_small_buf_release(pSMB);
 
        /* Since session is dead, search handle closed on server already */
@@ -2827,7 +3066,10 @@ getDFSRetry:
                      (void **) &pSMBr);
        if (rc)
                return rc;
-
+       
+       /* server pointer checked in called function, 
+       but should never be null here anyway */
+       pSMB->hdr.Mid = GetNextMid(ses->server);
        pSMB->hdr.Tid = ses->ipc_tid;
        pSMB->hdr.Uid = ses->Suid;
        if (ses->capabilities & CAP_STATUS32) {
@@ -3257,6 +3499,77 @@ QFSUnixRetry:
        return rc;
 }
 
+int
+CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
+{
+/* level 0x200  SMB_SET_CIFS_UNIX_INFO */
+       TRANSACTION2_SETFSI_REQ *pSMB = NULL;
+       TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
+       int rc = 0;
+       int bytes_returned = 0;
+       __u16 params, param_offset, offset, byte_count;
+
+       cFYI(1, ("In SETFSUnixInfo"));
+SETFSUnixRetry:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       params = 4;     /* 2 bytes zero followed by info level. */
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
+       offset = param_offset + params;
+
+       pSMB->MaxParameterCount = cpu_to_le16(4);
+       pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
+       byte_count = 1 /* pad */ + params + 12;
+
+       pSMB->DataCount = cpu_to_le16(12);
+       pSMB->ParameterCount = cpu_to_le16(params);
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->ParameterOffset = cpu_to_le16(param_offset);
+       pSMB->DataOffset = cpu_to_le16(offset);
+
+       /* Params. */
+       pSMB->FileNum = 0;
+       pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
+
+       /* Data. */
+       pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
+       pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
+       pSMB->ClientUnixCap = cpu_to_le64(cap);
+
+       pSMB->hdr.smb_buf_length += byte_count;
+       pSMB->ByteCount = cpu_to_le16(byte_count);
+
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc) {
+               cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
+       } else {                /* decode response */
+               rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+               if (rc) {
+                       rc = -EIO;      /* bad smb */
+               }
+       }
+       cifs_buf_release(pSMB);
+
+       if (rc == -EAGAIN)
+               goto SETFSUnixRetry;
+
+       return rc;
+}
+
+
 
 int
 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
@@ -3839,12 +4152,14 @@ setPermsRetry:
 }
 
 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
-                       const int notify_subdirs, const __u16 netfid,
-                       __u32 filter, const struct nls_table *nls_codepage)
+                 const int notify_subdirs, const __u16 netfid,
+                 __u32 filter, struct file * pfile, int multishot, 
+                 const struct nls_table *nls_codepage)
 {
        int rc = 0;
        struct smb_com_transaction_change_notify_req * pSMB = NULL;
        struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
+       struct dir_notify_req *dnotify_req;
        int bytes_returned;
 
        cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
@@ -3877,6 +4192,22 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
                        (struct smb_hdr *) pSMBr, &bytes_returned, -1);
        if (rc) {
                cFYI(1, ("Error in Notify = %d", rc));
+       } else {
+               /* Add file to outstanding requests */
+               dnotify_req = (struct dir_notify_req *) kmalloc(
+                                               sizeof(struct dir_notify_req), GFP_KERNEL);
+               dnotify_req->Pid = pSMB->hdr.Pid;
+               dnotify_req->PidHigh = pSMB->hdr.PidHigh;
+               dnotify_req->Mid = pSMB->hdr.Mid;
+               dnotify_req->Tid = pSMB->hdr.Tid;
+               dnotify_req->Uid = pSMB->hdr.Uid;
+               dnotify_req->netfid = netfid;
+               dnotify_req->pfile = pfile;
+               dnotify_req->filter = filter;
+               dnotify_req->multishot = multishot;
+               spin_lock(&GlobalMid_Lock);
+               list_add_tail(&dnotify_req->lhead, &GlobalDnotifyReqList);
+               spin_unlock(&GlobalMid_Lock);
        }
        cifs_buf_release(pSMB);
        return rc;      
index e568cc47a7f93005518d1470696f89ee1444a1ae..196976049c00e12dce6dda11b8915be2450beaa6 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/utsname.h>
 #include <linux/mempool.h>
 #include <linux/delay.h>
+#include <linux/completion.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include "cifspdu.h"
@@ -44,6 +45,8 @@
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
 
+static DECLARE_COMPLETION(cifsd_complete);
+
 extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
                       unsigned char *p24);
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
@@ -60,6 +63,7 @@ struct smb_vol {
        char *in6_addr;  /* ipv6 address as human readable form of in6_addr */
        char *iocharset;  /* local code page for mapping to and from Unicode */
        char source_rfc1001_name[16]; /* netbios name of client */
+       char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
        uid_t linux_uid;
        gid_t linux_gid;
        mode_t file_mode;
@@ -74,6 +78,10 @@ struct smb_vol {
        unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
        unsigned direct_io:1;
        unsigned remap:1;   /* set to remap seven reserved chars in filenames */
+       unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */
+       unsigned sfu_emul:1;
+       unsigned nocase;     /* request case insensitive filenames */
+       unsigned nobrl;      /* disable sending byte range locks to srv */
        unsigned int rsize;
        unsigned int wsize;
        unsigned int sockopt;
@@ -82,7 +90,8 @@ struct smb_vol {
 
 static int ipv4_connect(struct sockaddr_in *psin_server, 
                        struct socket **csocket,
-                       char * netb_name);
+                       char * netb_name,
+                       char * server_netb_name);
 static int ipv6_connect(struct sockaddr_in6 *psin_server, 
                        struct socket **csocket);
 
@@ -175,7 +184,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
                } else {
                        rc = ipv4_connect(&server->addr.sockAddr, 
                                        &server->ssocket,
-                                       server->workstation_RFC1001_name);
+                                       server->workstation_RFC1001_name,
+                                       server->server_RFC1001_name);
                }
                if(rc) {
                        msleep(3000);
@@ -337,6 +347,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        atomic_inc(&tcpSesAllocCount);
        length = tcpSesAllocCount.counter;
        write_unlock(&GlobalSMBSeslock);
+       complete(&cifsd_complete);
        if(length  > 1) {
                mempool_resize(cifs_req_poolp,
                        length + cifs_min_rcv,
@@ -344,6 +355,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        }
 
        while (server->tcpStatus != CifsExiting) {
+               if(try_to_freeze())
+                       continue;
                if (bigbuf == NULL) {
                        bigbuf = cifs_buf_get();
                        if(bigbuf == NULL) {
@@ -674,7 +687,7 @@ multi_t2_fnd:
                msleep(125);
        }
 
-       if (list_empty(&server->pending_mid_q)) {
+       if (!list_empty(&server->pending_mid_q)) {
                /* mpx threads have not exited yet give them 
                at least the smb send timeout time for long ops */
                /* due to delays on oplock break requests, we need
@@ -711,7 +724,7 @@ multi_t2_fnd:
                        GFP_KERNEL);
        }
        
-       msleep(250);
+       complete_and_exit(&cifsd_complete, 0);
        return 0;
 }
 
@@ -735,7 +748,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        toupper(system_utsname.nodename[i]);
        }
        vol->source_rfc1001_name[15] = 0;
-
+       /* null target name indicates to use *SMBSERVR default called name
+          if we end up sending RFC1001 session initialize */
+       vol->target_rfc1001_name[0] = 0;
        vol->linux_uid = current->uid;  /* current->euid instead? */
        vol->linux_gid = current->gid;
        vol->dir_mode = S_IRWXUGO;
@@ -745,6 +760,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
        /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
        vol->rw = TRUE;
 
+       /* default is always to request posix paths. */
+       vol->posix_paths = 1;
+
        if (!options)
                return 1;
 
@@ -985,7 +1003,31 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                /* The string has 16th byte zero still from
                                set at top of the function  */
                                if((i==15) && (value[i] != 0))
-                                       printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
+                                       printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
+                       }
+               } else if (strnicmp(data, "servern", 7) == 0) {
+                       /* servernetbiosname specified override *SMBSERVER */
+                       if (!value || !*value || (*value == ' ')) {
+                               cFYI(1,("empty server netbiosname specified"));
+                       } else {
+                               /* last byte, type, is 0x20 for servr type */
+                               memset(vol->target_rfc1001_name,0x20,16);
+
+                               for(i=0;i<15;i++) {
+                               /* BB are there cases in which a comma can be
+                                  valid in this workstation netbios name (and need
+                                  special handling)? */
+
+                               /* user or mount helper must uppercase netbiosname */
+                                       if (value[i]==0)
+                                               break;
+                                       else
+                                               vol->target_rfc1001_name[i] = value[i];
+                               }
+                               /* The string has 16th byte zero still from
+                                  set at top of the function  */
+                               if((i==15) && (value[i] != 0))
+                                       printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
                        }
                } else if (strnicmp(data, "credentials", 4) == 0) {
                        /* ignore */
@@ -1023,6 +1065,27 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        vol->remap = 1;
                } else if (strnicmp(data, "nomapchars", 10) == 0) {
                        vol->remap = 0;
+                } else if (strnicmp(data, "sfu", 3) == 0) {
+                        vol->sfu_emul = 1;
+                } else if (strnicmp(data, "nosfu", 5) == 0) {
+                        vol->sfu_emul = 0;
+               } else if (strnicmp(data, "posixpaths", 10) == 0) {
+                       vol->posix_paths = 1;
+               } else if (strnicmp(data, "noposixpaths", 12) == 0) {
+                       vol->posix_paths = 0;
+                } else if ((strnicmp(data, "nocase", 6) == 0) ||
+                          (strnicmp(data, "ignorecase", 10)  == 0)) {
+                        vol->nocase = 1;
+               } else if (strnicmp(data, "brl", 3) == 0) {
+                       vol->nobrl =  0;
+               } else if ((strnicmp(data, "nobrl", 5) == 0) || 
+                          (strnicmp(data, "nolock", 6) == 0)) {
+                       vol->nobrl =  1;
+                       /* turn off mandatory locking in mode
+                       if remote locking is turned off since the
+                       local vfs will do advisory */
+                       if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
+                               vol->file_mode = S_IALLUGO;
                } else if (strnicmp(data, "setuids", 7) == 0) {
                        vol->setuids = 1;
                } else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -1242,7 +1305,7 @@ static void rfc1002mangle(char * target,char * source, unsigned int length)
 
 static int
 ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, 
-                        char * netbios_name)
+            char * netbios_name, char * target_name)
 {
        int rc = 0;
        int connected = 0;
@@ -1320,8 +1383,14 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
                ses_init_buf = kcalloc(1, sizeof(struct rfc1002_session_packet), GFP_KERNEL);
                if(ses_init_buf) {
                        ses_init_buf->trailer.session_req.called_len = 32;
-                       rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
-                               DEFAULT_CIFS_CALLED_NAME,16);
+                       if(target_name && (target_name[0] != 0)) {
+                               rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
+                                       target_name, 16);
+                       } else {
+                               rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
+                                       DEFAULT_CIFS_CALLED_NAME,16);
+                       }
+
                        ses_init_buf->trailer.session_req.calling_len = 32;
                        /* calling name ends in null (byte 16) from old smb
                        convention. */
@@ -1554,7 +1623,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        sin_server.sin_port = htons(volume_info.port);
                else
                        sin_server.sin_port = 0;
-               rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
+               rc = ipv4_connect(&sin_server,&csocket,
+                                 volume_info.source_rfc1001_name,
+                                 volume_info.target_rfc1001_name);
                if (rc < 0) {
                        cERROR(1,
                               ("Error connecting to IPv4 socket. Aborting operation"));
@@ -1604,9 +1675,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                        kfree(volume_info.password);
                                FreeXid(xid);
                                return rc;
-                       } else
-                               rc = 0;
+                       }
+                       wait_for_completion(&cifsd_complete);
+                       rc = 0;
                        memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
+                       memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
                        srvTcp->sequence_number = 0;
                }
        }
@@ -1660,8 +1733,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                else
                        cifs_sb->wsize = CIFSMaxBufSize; /* default */
                if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
-                       cifs_sb->rsize = PAGE_CACHE_SIZE;
-                       cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
+                       cifs_sb->rsize = PAGE_CACHE_SIZE; 
+                       /* Windows ME does this */
+                       cFYI(1,("Attempt to set readsize for mount to less than one page (4096)"));
                }
                cifs_sb->mnt_uid = volume_info.linux_uid;
                cifs_sb->mnt_gid = volume_info.linux_gid;
@@ -1679,8 +1753,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
                if(volume_info.no_xattr)
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
+               if(volume_info.sfu_emul)
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
+               if(volume_info.nobrl)
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
+
                if(volume_info.direct_io) {
-                       cERROR(1,("mounting share using direct i/o"));
+                       cFYI(1,("mounting share using direct i/o"));
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
                }
 
@@ -1694,6 +1773,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                           to the same server share the last value passed in 
                           for the retry flag is used */
                        tcon->retry = volume_info.retry;
+                       tcon->nocase = volume_info.nocase;
                } else {
                        tcon = tconInfoAlloc();
                        if (tcon == NULL)
@@ -1722,6 +1802,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                if (!rc) {
                                        atomic_inc(&pSesInfo->inUse);
                                        tcon->retry = volume_info.retry;
+                                       tcon->nocase = volume_info.nocase;
                                }
                        }
                }
@@ -1743,8 +1824,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        spin_lock(&GlobalMid_Lock);
                        srvTcp->tcpStatus = CifsExiting;
                        spin_unlock(&GlobalMid_Lock);
-                       if(srvTcp->tsk)
+                       if(srvTcp->tsk) {
                                send_sig(SIGKILL,srvTcp->tsk,1);
+                               wait_for_completion(&cifsd_complete);
+                       }
                }
                 /* If find_unc succeeded then rc == 0 so we can not end */
                if (tcon)  /* up accidently freeing someone elses tcon struct */
@@ -1757,8 +1840,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                        temp_rc = CIFSSMBLogoff(xid, pSesInfo);
                                        /* if the socketUseCount is now zero */
                                        if((temp_rc == -ESHUTDOWN) &&
-                                          (pSesInfo->server->tsk))
+                                          (pSesInfo->server->tsk)) {
                                                send_sig(SIGKILL,pSesInfo->server->tsk,1);
+                                               wait_for_completion(&cifsd_complete);
+                                       }
                                } else
                                        cFYI(1, ("No session or bad tcon"));
                                sesInfoFree(pSesInfo);
@@ -1781,6 +1866,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                                                cFYI(1,("server negotiated posix acl support"));
                                                sb->s_flags |= MS_POSIXACL;
                                }
+
+                               /* Try and negotiate POSIX pathnames if we can. */
+                               if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
+                                   le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+                                       if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP))  {
+                                               cFYI(1,("negotiated posix pathnames support"));
+                                               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
+                                       } else {
+                                               cFYI(1,("posix pathnames support requested but not supported"));
+                                       }
+                               }
                        }
                }
        }
@@ -1830,6 +1926,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
                        NULL /* no tCon exists yet */ , 13 /* wct */ );
 
+       smb_buffer->Mid = GetNextMid(ses->server);
        pSMB->req_no_secext.AndXCommand = 0xFF;
        pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
        pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
@@ -2105,6 +2202,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        /* send SMBsessionSetup here */
        header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
                        NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+       smb_buffer->Mid = GetNextMid(ses->server);
        pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
        pSMB->req.AndXCommand = 0xFF;
        pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
@@ -2371,6 +2470,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        /* send SMBsessionSetup here */
        header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
                        NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+       smb_buffer->Mid = GetNextMid(ses->server);
        pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
        pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
 
@@ -2713,6 +2814,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        /* send SMBsessionSetup here */
        header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
                        NULL /* no tCon exists yet */ , 12 /* wct */ );
+
+       smb_buffer->Mid = GetNextMid(ses->server);
        pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
        pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
        pSMB->req.AndXCommand = 0xFF;
@@ -3084,6 +3187,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 
        header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
                        NULL /*no tid */ , 4 /*wct */ );
+
+       smb_buffer->Mid = GetNextMid(ses->server);
        smb_buffer->Uid = ses->Suid;
        pSMB = (TCONX_REQ *) smb_buffer;
        pSMBr = (TCONX_RSP *) smb_buffer_response;
@@ -3205,8 +3310,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
                                return 0;
                        } else if (rc == -ESHUTDOWN) {
                                cFYI(1,("Waking up socket by sending it signal"));
-                               if(cifsd_task)
+                               if(cifsd_task) {
                                        send_sig(SIGKILL,cifsd_task,1);
+                                       wait_for_completion(&cifsd_complete);
+                               }
                                rc = 0;
                        } /* else - we have an smb session
                                left on this socket do not kill cifsd */
index 3f3538d4a1fad105c0a776ef5f6d6e18fef0ff6c..cf90c9ad2c870f1dd1b02fce8fcee2da74a717c0 100644 (file)
@@ -48,6 +48,7 @@ build_path_from_dentry(struct dentry *direntry)
        struct dentry *temp;
        int namelen = 0;
        char *full_path;
+       char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
 
        if(direntry == NULL)
                return NULL;  /* not much we can do if dentry is freed and
@@ -74,7 +75,7 @@ cifs_bp_rename_retry:
                if (namelen < 0) {
                        break;
                } else {
-                       full_path[namelen] = '\\';
+                       full_path[namelen] = dirsep;
                        strncpy(full_path + namelen + 1, temp->d_name.name,
                                temp->d_name.len);
                        cFYI(0, (" name: %s ", full_path + namelen));
@@ -184,6 +185,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                         desiredAccess, CREATE_NOT_DIR,
                         &fileHandle, &oplock, buf, cifs_sb->local_nls,
                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if(rc == -EIO) {
+               /* old server, retry the open legacy style */
+               rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
+                       desiredAccess, CREATE_NOT_DIR,
+                       &fileHandle, &oplock, buf, cifs_sb->local_nls,
+                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       } 
        if (rc) {
                cFYI(1, ("cifs_create returned 0x%x ", rc));
        } else {
@@ -209,7 +217,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                        }
                else {
-                       /* BB implement via Windows security descriptors */
+                       /* BB implement mode setting via Windows security descriptors */
                        /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
                        /* could set r/o dos attribute if mode & 0222 == 0 */
                }
@@ -226,10 +234,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                }
 
                if (rc != 0) {
-                       cFYI(1,("Create worked but get_inode_info failed with rc = %d",
+                       cFYI(1,
+                            ("Create worked but get_inode_info failed rc = %d",
                              rc));
                } else {
-                       direntry->d_op = &cifs_dentry_ops;
+                       if (pTcon->nocase)
+                               direntry->d_op = &cifs_ci_dentry_ops;
+                       else
+                               direntry->d_op = &cifs_dentry_ops;
                        d_instantiate(direntry, newinode);
                }
                if((nd->flags & LOOKUP_OPEN) == FALSE) {
@@ -303,8 +315,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
        up(&direntry->d_sb->s_vfs_rename_sem);
        if(full_path == NULL)
                rc = -ENOMEM;
-       
-       if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) {
+       else if (pTcon->ses->capabilities & CAP_UNIX) {
                if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
                        rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
                                mode,(__u64)current->euid,(__u64)current->egid,
@@ -322,10 +333,49 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
                if(!rc) {
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
                                                inode->i_sb,xid);
-                       direntry->d_op = &cifs_dentry_ops;
+                       if (pTcon->nocase)
+                               direntry->d_op = &cifs_ci_dentry_ops;
+                       else
+                               direntry->d_op = &cifs_dentry_ops;
                        if(rc == 0)
                                d_instantiate(direntry, newinode);
                }
+       } else {
+               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+                       int oplock = 0;
+                       u16 fileHandle;
+                       FILE_ALL_INFO * buf;
+
+                       cFYI(1,("sfu compat create special file"));
+
+                       buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
+                       if(buf == NULL) {
+                               kfree(full_path);
+                               FreeXid(xid);
+                               return -ENOMEM;
+                       }
+
+                       rc = CIFSSMBOpen(xid, pTcon, full_path,
+                                        FILE_CREATE, /* fail if exists */
+                                        GENERIC_WRITE /* BB would 
+                                         WRITE_OWNER | WRITE_DAC be better? */,
+                                        /* Create a file and set the
+                                           file attribute to SYSTEM */
+                                        CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
+                                        &fileHandle, &oplock, buf,
+                                        cifs_sb->local_nls,
+                                        cifs_sb->mnt_cifs_flags & 
+                                           CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+                       if(!rc) {
+                               /* BB Do not bother to decode buf since no
+                                  local inode yet to put timestamps in */
+                               CIFSSMBClose(xid, pTcon, fileHandle);
+                               d_drop(direntry);
+                       }
+                       kfree(buf);
+                       /* add code here to set EAs */
+               }
        }
 
        kfree(full_path);
@@ -382,7 +432,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
                                         parent_dir_inode->i_sb,xid);
 
        if ((rc == 0) && (newInode != NULL)) {
-               direntry->d_op = &cifs_dentry_ops;
+               if (pTcon->nocase)
+                       direntry->d_op = &cifs_ci_dentry_ops;
+               else
+                       direntry->d_op = &cifs_dentry_ops;
                d_add(direntry, newInode);
 
                /* since paths are not looked up by component - the parent directories are presumed to be good here */
@@ -441,3 +494,42 @@ struct dentry_operations cifs_dentry_ops = {
 /* d_delete:       cifs_d_delete,       *//* not needed except for debugging */
        /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */
 };
+
+static int cifs_ci_hash(struct dentry *dentry, struct qstr *q)
+{
+       struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
+       unsigned long hash;
+       int i;
+
+       hash = init_name_hash();
+       for (i = 0; i < q->len; i++)
+               hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
+                                        hash);
+       q->hash = end_name_hash(hash);
+
+       return 0;
+}
+
+static int cifs_ci_compare(struct dentry *dentry, struct qstr *a,
+                          struct qstr *b)
+{
+       struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls;
+
+       if ((a->len == b->len) &&
+           (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) {
+               /*
+                * To preserve case, don't let an existing negative dentry's
+                * case take precedence.  If a is not a negative dentry, this
+                * should have no side effects
+                */
+               memcpy((unsigned char *)a->name, b->name, a->len);
+               return 0;
+       }
+       return 1;
+}
+
+struct dentry_operations cifs_ci_dentry_ops = {
+       .d_revalidate = cifs_d_revalidate,
+       .d_hash = cifs_ci_hash,
+       .d_compare = cifs_ci_compare,
+};
index 7d2a9202c39a3291969307c1c57bdc18237fca57..d527e2c76073e6c16fdd6192c2bb948c77b268e0 100644 (file)
@@ -100,8 +100,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
                } else {
                        filter = convert_to_cifs_notify_flags(arg);
                        if(filter != 0) {
-                               rc = CIFSSMBNotify(xid, pTcon, 0 /* no subdirs */, netfid, 
-                                       filter, cifs_sb->local_nls);
+                               rc = CIFSSMBNotify(xid, pTcon, 
+                                       0 /* no subdirs */, netfid,
+                                       filter, file, arg & DN_MULTISHOT,
+                                       cifs_sb->local_nls);
                        } else {
                                rc = -EINVAL;
                        }
@@ -109,7 +111,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
                        it would close automatically but may be a way
                        to do it easily when inode freed or when
                        notify info is cleared/changed */
-            cERROR(1,("notify rc %d",rc));
+                       cFYI(1,("notify rc %d",rc));
                }
        }
        
index 3497125189dfde1a8b19506216954495fd061c7b..5ecda554f9130f9c386cdbff1e5c6ca9f0808015 100644 (file)
@@ -256,6 +256,13 @@ int cifs_open(struct inode *inode, struct file *file)
                         CREATE_NOT_DIR, &netfid, &oplock, buf,
                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
                                 & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (rc == -EIO) {
+               /* Old server, try legacy style OpenX */
+               rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
+                       desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
+                       cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+                               & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       }
        if (rc) {
                cFYI(1, ("cifs_open returned 0x%x ", rc));
                goto out;
@@ -744,14 +751,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
                                    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         
+       cifs_stats_bytes_written(pTcon, total_written);
 
        /* since the write may have blocked check these pointers again */
        if (file->f_dentry) {
@@ -791,9 +791,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 
        pTcon = cifs_sb->tcon;
 
-       /* cFYI(1,
-          (" write %d bytes to offset %lld of %s", write_size,
-          *poffset, file->f_dentry->d_name.name)); */
+       cFYI(1,(" write %d bytes to offset %lld of %s", write_size,
+          *poffset, file->f_dentry->d_name.name)); /* BB removeme BB */
 
        if (file->private_data == NULL)
                return -EBADF;
@@ -846,7 +845,20 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
                                if (rc != 0)
                                        break;
                        }
-
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+                       /* BB FIXME We can not sign across two buffers yet */
+                       if((experimEnabled) && ((pTcon->ses->server->secMode & 
+                        (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) {
+                               rc = CIFSSMBWrite2(xid, pTcon,
+                                               open_file->netfid,
+                                               min_t(const int, cifs_sb->wsize,
+                                                   write_size - total_written),
+                                               *poffset, &bytes_written,
+                                               write_data + total_written, 
+                                               long_op);
+                       } else
+                       /* BB FIXME fixup indentation of line below */
+#endif                 
                        rc = CIFSSMBWrite(xid, pTcon,
                                 open_file->netfid,
                                 min_t(const int, cifs_sb->wsize, 
@@ -867,14 +879,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
                                    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         
+       cifs_stats_bytes_written(pTcon, total_written);
 
        /* since the write may have blocked check these pointers again */
        if (file->f_dentry) {
@@ -1207,12 +1212,10 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
                                if (rc != 0)
                                        break;
                        }
-
                        rc = CIFSSMBRead(xid, pTcon,
-                                open_file->netfid,
-                                current_read_size, *poffset,
-                                &bytes_read, &smb_read_data);
-
+                                       open_file->netfid,
+                                       current_read_size, *poffset,
+                                       &bytes_read, &smb_read_data);
                        pSMBr = (struct smb_com_read_rsp *)smb_read_data;
                        if (copy_to_user(current_offset, 
                                         smb_read_data + 4 /* RFC1001 hdr */
@@ -1235,12 +1238,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
                                return rc;
                        }
                } 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
+                       cifs_stats_bytes_read(pTcon, bytes_read);
                        *poffset += bytes_read;
                }
        }
@@ -1289,11 +1287,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
                                if (rc != 0)
                                        break;
                        }
-
                        rc = CIFSSMBRead(xid, pTcon,
-                                open_file->netfid,
-                                current_read_size, *poffset,
-                                &bytes_read, &current_offset);
+                                       open_file->netfid,
+                                       current_read_size, *poffset,
+                                       &bytes_read, &current_offset);
                }
                if (rc || (bytes_read == 0)) {
                        if (total_read) {
@@ -1303,12 +1300,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
                                return rc;
                        }
                } 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
+                       cifs_stats_bytes_read(pTcon, total_read);
                        *poffset += bytes_read;
                }
        }
@@ -1452,10 +1444,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                        }
 
                        rc = CIFSSMBRead(xid, pTcon,
-                               open_file->netfid,
-                               read_size, offset,
-                               &bytes_read, &smb_read_data);
-                       /* BB need to check return code here */
+                                       open_file->netfid,
+                                       read_size, offset,
+                                       &bytes_read, &smb_read_data);
+
+                       /* BB more RC checks ? */
                        if (rc== -EAGAIN) {
                                if (smb_read_data) {
                                        cifs_buf_release(smb_read_data);
@@ -1480,12 +1473,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                                le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
 
                        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
+                       cifs_stats_bytes_read(pTcon, bytes_read);
                        if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
                                i++; /* account for partial page */
 
index 8d336a90025584a6fb524001ef71c123b6d881ec..0fbe02ebc0335498bdc648287358e900662a8a87 100644 (file)
@@ -166,7 +166,13 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                                inode->i_fop = &cifs_file_direct_ops;
                        else
                                inode->i_fop = &cifs_file_ops;
+                       if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+                               inode->i_fop->lock = NULL;
                        inode->i_data.a_ops = &cifs_addr_ops;
+                       /* check if server can support readpages */
+                       if(pTcon->ses->server->maxBuf < 
+                           4096 + MAX_CIFS_HDR_SIZE)
+                               inode->i_data.a_ops->readpages = NULL;
                } else if (S_ISDIR(inode->i_mode)) {
                        cFYI(1, (" Directory inode"));
                        inode->i_op = &cifs_dir_inode_ops;
@@ -213,8 +219,18 @@ int cifs_get_inode_info(struct inode **pinode,
                pfindData = (FILE_ALL_INFO *)buf;
                /* could do find first instead but this returns more info */
                rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
-                             cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 
+                             cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
+               /* BB optimize code so we do not make the above call
+               when server claims no NT SMB support and the above call
+               failed at least once - set flag in tcon or mount */
+               if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
+                       rc = SMBQueryInformation(xid, pTcon, search_path,
+                                       pfindData, cifs_sb->local_nls, 
+                                       cifs_sb->mnt_cifs_flags &
+                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
+               }
+               
        }
        /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
        if (rc) {
@@ -320,6 +336,16 @@ int cifs_get_inode_info(struct inode **pinode,
                   on dirs */
                        inode->i_mode = cifs_sb->mnt_dir_mode;
                        inode->i_mode |= S_IFDIR;
+               } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
+                          (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
+                          /* No need to le64 convert size of zero */
+                          (pfindData->EndOfFile == 0)) {
+                       inode->i_mode = cifs_sb->mnt_file_mode;
+                       inode->i_mode |= S_IFIFO;
+/* BB Finish for SFU style symlinks and devies */
+/*             } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
+                          (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */
+
                } else {
                        inode->i_mode |= S_IFREG;
                        /* treat the dos attribute of read-only as read-only
@@ -359,7 +385,12 @@ int cifs_get_inode_info(struct inode **pinode,
                                inode->i_fop = &cifs_file_direct_ops;
                        else
                                inode->i_fop = &cifs_file_ops;
+                       if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+                               inode->i_fop->lock = NULL;
                        inode->i_data.a_ops = &cifs_addr_ops;
+                       if(pTcon->ses->server->maxBuf < 
+                            4096 + MAX_CIFS_HDR_SIZE)
+                               inode->i_data.a_ops->readpages = NULL;
                } else if (S_ISDIR(inode->i_mode)) {
                        cFYI(1, (" Directory inode "));
                        inode->i_op = &cifs_dir_inode_ops;
@@ -577,7 +608,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                        rc = cifs_get_inode_info(&newinode, full_path, NULL,
                                                 inode->i_sb,xid);
 
-               direntry->d_op = &cifs_dentry_ops;
+               if (pTcon->nocase)
+                       direntry->d_op = &cifs_ci_dentry_ops;
+               else
+                       direntry->d_op = &cifs_dentry_ops;
                d_instantiate(direntry, newinode);
                if (direntry->d_inode)
                        direntry->d_inode->i_nlink = 2;
index ab925ef4f863c9696b9ed0a1832e9d3d6a0c0d07..b43e071fe1106446fc2e48fc05299a7b8fabce4a 100644 (file)
@@ -198,7 +198,10 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
                             ("Create symlink worked but get_inode_info failed with rc = %d ",
                              rc));
                } else {
-                       direntry->d_op = &cifs_dentry_ops;
+                       if (pTcon->nocase)
+                               direntry->d_op = &cifs_ci_dentry_ops;
+                       else
+                               direntry->d_op = &cifs_dentry_ops;
                        d_instantiate(direntry, newinode);
                }
        }
index 20ae4153f791673d4137bf885db2b8b92cda8852..fafbdbfa63a1382d0c98e2208bf27e1559692fa1 100644 (file)
@@ -34,8 +34,6 @@ extern mempool_t *cifs_sm_req_poolp;
 extern mempool_t *cifs_req_poolp;
 extern struct task_struct * oplockThread;
 
-static __u16 GlobalMid;                /* multiplex id - rotating counter */
-
 /* The xid serves as a useful identifier for each incoming vfs request, 
    in a similar way to the mid which is useful to track each sent smb, 
    and CurrentXid can also provide a running counter (although it 
@@ -51,6 +49,8 @@ _GetXid(void)
        GlobalTotalActiveXid++;
        if (GlobalTotalActiveXid > GlobalMaxActiveXid)
                GlobalMaxActiveXid = GlobalTotalActiveXid;      /* keep high water mark for number of simultaneous vfs ops in our filesystem */
+       if(GlobalTotalActiveXid > 65000)
+               cFYI(1,("warning: more than 65000 requests active"));
        xid = GlobalCurrentXid++;
        spin_unlock(&GlobalMid_Lock);
        return xid;
@@ -218,6 +218,76 @@ cifs_small_buf_release(void *buf_to_free)
        return;
 }
 
+/* 
+       Find a free multiplex id (SMB mid). Otherwise there could be
+       mid collisions which might cause problems, demultiplexing the
+       wrong response to this request. Multiplex ids could collide if
+       one of a series requests takes much longer than the others, or
+       if a very large number of long lived requests (byte range
+       locks or FindNotify requests) are pending.  No more than
+       64K-1 requests can be outstanding at one time.  If no 
+       mids are available, return zero.  A future optimization
+       could make the combination of mids and uid the key we use
+       to demultiplex on (rather than mid alone).  
+       In addition to the above check, the cifs demultiplex
+       code already used the command code as a secondary
+       check of the frame and if signing is negotiated the
+       response would be discarded if the mid were the same
+       but the signature was wrong.  Since the mid is not put in the
+       pending queue until later (when it is about to be dispatched)
+       we do have to limit the number of outstanding requests 
+       to somewhat less than 64K-1 although it is hard to imagine
+       so many threads being in the vfs at one time.
+*/
+__u16 GetNextMid(struct TCP_Server_Info *server)
+{
+       __u16 mid = 0;
+       __u16 last_mid;
+       int   collision;  
+
+       if(server == NULL)
+               return mid;
+
+       spin_lock(&GlobalMid_Lock);
+       last_mid = server->CurrentMid; /* we do not want to loop forever */
+       server->CurrentMid++;
+       /* This nested loop looks more expensive than it is.
+       In practice the list of pending requests is short, 
+       fewer than 50, and the mids are likely to be unique
+       on the first pass through the loop unless some request
+       takes longer than the 64 thousand requests before it
+       (and it would also have to have been a request that
+        did not time out) */
+       while(server->CurrentMid != last_mid) {
+               struct list_head *tmp;
+               struct mid_q_entry *mid_entry;
+
+               collision = 0;
+               if(server->CurrentMid == 0)
+                       server->CurrentMid++;
+
+               list_for_each(tmp, &server->pending_mid_q) {
+                       mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+
+                       if ((mid_entry->mid == server->CurrentMid) &&
+                           (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
+                               /* This mid is in use, try a different one */
+                               collision = 1;
+                               break;
+                       }
+               }
+               if(collision == 0) {
+                       mid = server->CurrentMid;
+                       break;
+               }
+               server->CurrentMid++;
+       }
+       spin_unlock(&GlobalMid_Lock);
+       return mid;
+}
+
+/* NB: MID can not be set if treeCon not passed in, in that
+   case it is responsbility of caller to set the mid */
 void
 header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                const struct cifsTconInfo *treeCon, int word_count
@@ -233,7 +303,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
            (2 * word_count) + sizeof (struct smb_hdr) -
            4 /*  RFC 1001 length field does not count */  +
            2 /* for bcc field itself */ ;
-       /* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */
+       /* Note that this is the only network field that has to be converted
+          to big endian and it is done just before we send it */
 
        buffer->Protocol[0] = 0xFF;
        buffer->Protocol[1] = 'S';
@@ -245,8 +316,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
        buffer->Pid = cpu_to_le16((__u16)current->tgid);
        buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
        spin_lock(&GlobalMid_Lock);
-       GlobalMid++;
-       buffer->Mid = GlobalMid;
        spin_unlock(&GlobalMid_Lock);
        if (treeCon) {
                buffer->Tid = treeCon->tid;
@@ -256,8 +325,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                        if (treeCon->ses->capabilities & CAP_STATUS32) {
                                buffer->Flags2 |= SMBFLG2_ERR_STATUS;
                        }
-
-                       buffer->Uid = treeCon->ses->Suid;       /* always in LE format */
+                       /* Uid is not converted */
+                       buffer->Uid = treeCon->ses->Suid;
+                       buffer->Mid = GetNextMid(treeCon->ses->server);
                        if(multiuser_mount != 0) {
                /* For the multiuser case, there are few obvious technically  */
                /* possible mechanisms to match the local linux user (uid)    */
@@ -305,6 +375,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                }
                if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
                        buffer->Flags2 |= SMBFLG2_DFS;
+               if (treeCon->nocase)
+                       buffer->Flags  |= SMBFLG_CASELESS;
                if((treeCon->ses) && (treeCon->ses->server))
                        if(treeCon->ses->server->secMode & 
                          (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
@@ -448,9 +520,7 @@ is_valid_oplock_break(struct smb_hdr *buf)
        list_for_each(tmp, &GlobalTreeConnectionList) {
                tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
                if (tcon->tid == buf->Tid) {
-#ifdef CONFIG_CIFS_STATS
-                       atomic_inc(&tcon->num_oplock_brks);
-#endif
+                       cifs_stats_inc(&tcon->num_oplock_brks);
                        list_for_each(tmp1,&tcon->openFileList){
                                netfile = list_entry(tmp1,struct cifsFileInfo,
                                                     tlist);
index a92af41d44119a2c464f3b905b181f4445c9f1db..873b812c0f408e450421fcba274a6cbbc19854b9 100644 (file)
@@ -133,7 +133,6 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
 int
 cifs_inet_pton(int address_family, char *cp,void *dst)
 {
-       struct in_addr address;
        int value;
        int digit;
        int i;
@@ -190,8 +189,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst)
        if (value > addr_class_max[end - bytes])
                return 0;
 
-       address.s_addr = *((__be32 *) bytes) | htonl(value);
-       *((__be32 *)dst) = address.s_addr;
+       *((__be32 *)dst) = *((__be32 *) bytes) | htonl(value);
        return 1; /* success */
 }
 
index 22557716f9afb48c032d9c7759706183f01b6a9f..a1e8dc901de46d161dc8865732c0ba31593fcb5d 100644 (file)
@@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
                }
 
                *ptmp_inode = new_inode(file->f_dentry->d_sb);
-               tmp_dentry->d_op = &cifs_dentry_ops;
+               if (pTcon->nocase)
+                       tmp_dentry->d_op = &cifs_ci_dentry_ops;
+               else
+                       tmp_dentry->d_op = &cifs_dentry_ops;
                if(*ptmp_inode == NULL)
                        return rc;
                rc = 1;
@@ -148,6 +151,13 @@ static void fill_in_inode(struct inode *tmp_inode,
                        tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
                }
                tmp_inode->i_mode |= S_IFDIR;
+       } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && 
+                  (attr & ATTR_SYSTEM) && (end_of_file == 0)) {
+               *pobject_type = DT_FIFO;
+               tmp_inode->i_mode |= S_IFIFO;
+/* BB Finish for SFU style symlinks and devies */
+/*     } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
+               (attr & ATTR_SYSTEM) && ) { */
 /* we no longer mark these because we could not follow them */
 /*        } else if (attr & ATTR_REPARSE) {
                 *pobject_type = DT_LNK;
@@ -187,11 +197,17 @@ static void fill_in_inode(struct inode *tmp_inode,
                        tmp_inode->i_fop = &cifs_file_direct_ops;
                else
                        tmp_inode->i_fop = &cifs_file_ops;
+               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+                       tmp_inode->i_fop->lock = NULL;
                tmp_inode->i_data.a_ops = &cifs_addr_ops;
-
+               if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+                  (cifs_sb->tcon->ses->server->maxBuf <
+                       4096 + MAX_CIFS_HDR_SIZE))
+                       tmp_inode->i_data.a_ops->readpages = NULL;
                if(isNewInode)
-                       return; /* No sense invalidating pages for new inode since we
-                                          have not started caching readahead file data yet */
+                       return; /* No sense invalidating pages for new inode
+                                  since have not started caching readahead file
+                                  data yet */
 
                if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
                        (local_size == tmp_inode->i_size)) {
@@ -290,7 +306,13 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
                        tmp_inode->i_fop = &cifs_file_direct_ops;
                else
                        tmp_inode->i_fop = &cifs_file_ops;
+               if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+                       tmp_inode->i_fop->lock = NULL;
                tmp_inode->i_data.a_ops = &cifs_addr_ops;
+               if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+                  (cifs_sb->tcon->ses->server->maxBuf < 
+                       4096 + MAX_CIFS_HDR_SIZE))
+                       tmp_inode->i_data.a_ops->readpages = NULL;
 
                if(isNewInode)
                        return; /* No sense invalidating pages for new inode since we
@@ -374,7 +396,7 @@ ffirst_retry:
 
        rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
                &cifsFile->netfid, &cifsFile->srch_inf,
-               cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+               cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
        if(rc == 0)
                cifsFile->invalidHandle = FALSE;
        if((rc == -EOPNOTSUPP) && 
@@ -536,7 +558,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
        while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && 
              (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
                cFYI(1,("calling findnext2"));
-               rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf);
+               rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, 
+                                 &cifsFile->srch_inf);
                if(rc)
                        return -ENOENT;
        }
@@ -548,14 +571,13 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
                char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + 
                        smbCalcSize((struct smb_hdr *)
                                cifsFile->srch_inf.ntwrk_buf_start);
-/*     dump_cifs_file_struct(file,"found entry in fce "); */
                first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
                                        - cifsFile->srch_inf.entries_in_buffer;
                pos_in_buf = index_to_find - first_entry_in_buffer;
                cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); 
                current_entry = cifsFile->srch_inf.srch_entries_start;
                for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
-                       /* go entry to next entry figuring out which we need to start with */
+                       /* go entry by entry figuring out which is first */
                        /* if( . or ..)
                                skip */
                        rc = cifs_entry_is_dot(current_entry,cifsFile);
@@ -586,7 +608,6 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
                *num_to_ret = 0;
        } else
                *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
-/*     dump_cifs_file_struct(file, "end fce ");*/
 
        return rc;
 }
@@ -721,7 +742,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
                              (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc);
        }
        
-       rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type);
+       rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
+                    tmp_inode->i_ino,obj_type);
        if(rc) {
                cFYI(1,("filldir rc = %d",rc));
        }
@@ -805,14 +827,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                FreeXid(xid);
                return -EIO;
        }
-/*     dump_cifs_file_struct(file, "Begin rdir "); */
 
        cifs_sb = CIFS_SB(file->f_dentry->d_sb);
        pTcon = cifs_sb->tcon;
        if(pTcon == NULL)
                return -EINVAL;
 
-/*     cFYI(1,("readdir2 pos: %lld",file->f_pos)); */
 
        switch ((int) file->f_pos) {
        case 0:
@@ -866,7 +886,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                cifsFile->search_resume_name = NULL; */
 
                /* BB account for . and .. in f_pos as special case */
-               /* dump_cifs_file_struct(file, "rdir after default ");*/
 
                rc = find_cifs_entry(xid,pTcon, file,
                                &current_entry,&num_to_fill);
@@ -906,14 +925,14 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                                cifs_save_resume_key(current_entry,cifsFile);
                                break;
                        } else 
-                               current_entry = nxt_dir_entry(current_entry,end_of_smb);
+                               current_entry = nxt_dir_entry(current_entry,
+                                                             end_of_smb);
                }
                kfree(tmp_buf);
                break;
        } /* end switch */
 
 rddir2_exit:
-       /* dump_cifs_file_struct(file, "end rdir ");  */
        FreeXid(xid);
        return rc;
 }
index 0046c219833d6cfbef77e85addc663e1be71e290..96f89eb6604025fc7c417649a4d629fc1fde6390 100644 (file)
@@ -49,7 +49,8 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
                return NULL;
        }
        
-       temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS);
+       temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
+                                                   SLAB_KERNEL | SLAB_NOFS);
        if (temp == NULL)
                return temp;
        else {
@@ -179,27 +180,24 @@ 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
-smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
-        unsigned int smb_buf_length, struct kvec * write_vector 
-         /* page list */, struct sockaddr *sin)
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+static int
+smb_send2(struct socket *ssocket, struct smb_hdr *smb_buffer,
+        unsigned int smb_hdr_length, const char * data, unsigned int datalen,
+        struct sockaddr *sin)
 {
        int rc = 0;
        int i = 0;
        struct msghdr smb_msg;
-       number_of_pages += 1; /* account for SMB header */
-       struct kvec * piov  = kmalloc(number_of_pages * sizeof(struct kvec));
-       unsigned len = smb_buf_length + 4;
-
+       struct kvec iov[2];
+       unsigned len = smb_hdr_length + 4;
+       
        if(ssocket == NULL)
                return -ENOTSOCK; /* BB eventually add reconnect code here */
-       iov.iov_base = smb_buffer;
-       iov.iov_len = len;
-
+       iov[0].iov_base = smb_buffer;
+       iov[0].iov_len = len;
+       iov[1].iov_base = data;
+       iov[1].iov_len = datalen;
        smb_msg.msg_name = sin;
        smb_msg.msg_namelen = sizeof (struct sockaddr);
        smb_msg.msg_control = NULL;
@@ -212,12 +210,12 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
           Flags2 is converted in SendReceive */
 
        smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
-       cFYI(1, ("Sending smb of length %d ", smb_buf_length));
+       cFYI(1, ("Sending smb:  hdrlen %d datalen %d",
+                smb_hdr_length,datalen));
        dump_smb(smb_buffer, len);
 
-       while (len > 0) {
-               rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, 
-                                   len);
+       while (len + datalen > 0) {
+               rc = kernel_sendmsg(ssocket, &smb_msg, iov, 2, len);
                if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
                        i++;
                        if(i > 60) {
@@ -232,9 +230,23 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
                }
                if (rc < 0) 
                        break;
-               iov.iov_base += rc;
-               iov.iov_len -= rc;
-               len -= rc;
+               if(iov[0].iov_len > 0) {
+                       if(rc >= len) {
+                               iov[0].iov_len = 0;
+                               rc -= len;
+                               len = 0;
+                       } else {  /* some of hdr was not sent */
+                               len -= rc;
+                               iov[0].iov_len -= rc;
+                               iov[0].iov_base += rc;
+                               continue;
+                       }
+               }
+               if((iov[0].iov_len == 0) && (rc > 0)){
+                       iov[1].iov_base += rc;
+                       iov[1].iov_len -= rc;
+                       datalen -= rc;
+               }
        }
 
        if (rc < 0) {
@@ -246,14 +258,15 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
        return rc;
 }
 
-
 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)
+SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 
+            struct smb_hdr *in_buf, int hdrlen, const char * data,
+            int datalen, int *pbytes_returned, const int long_op)
 {
        int rc = 0;
-       unsigned long timeout = 15 * HZ;
-       struct mid_q_entry *midQ = NULL;
+       unsigned int receive_len;
+       unsigned long timeout;
+       struct mid_q_entry *midQ;
 
        if (ses == NULL) {
                cERROR(1,("Null smb session"));
@@ -263,14 +276,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
                cERROR(1,("Null tcp session"));
                return -EIO;
        }
-       if(pbytes_returned == NULL)
-               return -EIO;
-       else
-               *pbytes_returned = 0;
 
-  
-
-       if(ses->server->tcpStatus == CIFS_EXITING)
+       if(ses->server->tcpStatus == CifsExiting)
                return -ENOENT;
 
        /* Ensure that we do not send more than 50 overlapping requests 
@@ -282,7 +289,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
        } else {
                spin_lock(&GlobalMid_Lock); 
                while(1) {        
-                       if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){
+                       if(atomic_read(&ses->server->inFlight) >= 
+                                       cifs_max_pending){
                                spin_unlock(&GlobalMid_Lock);
                                wait_event(ses->server->request_q,
                                        atomic_read(&ses->server->inFlight)
@@ -314,17 +322,17 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
 
        if (ses->server->tcpStatus == CifsExiting) {
                rc = -ENOENT;
-               goto cifs_out_label;
+               goto out_unlock2;
        } else if (ses->server->tcpStatus == CifsNeedReconnect) {
                cFYI(1,("tcp session dead - return to caller to retry"));
                rc = -EAGAIN;
-               goto cifs_out_label;
+               goto out_unlock2;
        } 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;
+                       goto out_unlock2;
                } /* else ok - we are setting up session */
        }
        midQ = AllocMidQEntry(in_buf, ses);
@@ -352,13 +360,12 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
                return -EIO;
        }
 
-       /* BB can we sign efficiently in this path? */
-       rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
+/* BB FIXME */
+/*     rc = cifs_sign_smb2(in_buf, data, ses->server, &midQ->sequence_number); */
 
        midQ->midState = MID_REQUEST_SUBMITTED;
-/*     rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
-                      piovec, 
-                      (struct sockaddr *) &(ses->server->addr.sockAddr));*/
+       rc = smb_send2(ses->server->ssocket, in_buf, hdrlen, data, datalen,
+                     (struct sockaddr *) &(ses->server->addr.sockAddr));
        if(rc < 0) {
                DeleteMidQEntry(midQ);
                up(&ses->server->tcpSem);
@@ -370,19 +377,137 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
                return rc;
        } else
                up(&ses->server->tcpSem);
-cifs_out_label:
-       if(midQ)
-               DeleteMidQEntry(midQ);
-                                                                                                                           
+       if (long_op == -1)
+               goto cifs_no_response_exit2;
+       else if (long_op == 2) /* writes past end of file can take loong time */
+               timeout = 300 * HZ;
+       else if (long_op == 1)
+               timeout = 45 * HZ; /* should be greater than 
+                       servers oplock break timeout (about 43 seconds) */
+       else if (long_op > 2) {
+               timeout = MAX_SCHEDULE_TIMEOUT;
+       } else
+               timeout = 15 * HZ;
+       /* wait for 15 seconds or until woken up due to response arriving or 
+          due to last connection to this server being unmounted */
+       if (signal_pending(current)) {
+               /* 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 */
+       if(timeout != MAX_SCHEDULE_TIMEOUT) {
+               timeout += jiffies;
+               wait_event(ses->server->response_q,
+                       (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
+                       time_after(jiffies, timeout) || 
+                       ((ses->server->tcpStatus != CifsGood) &&
+                        (ses->server->tcpStatus != CifsNew)));
+       } else {
+               wait_event(ses->server->response_q,
+                       (!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
+                       ((ses->server->tcpStatus != CifsGood) &&
+                        (ses->server->tcpStatus != CifsNew)));
+       }
+
+       spin_lock(&GlobalMid_Lock);
+       if (midQ->resp_buf) {
+               spin_unlock(&GlobalMid_Lock);
+               receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf);
+       } else {
+               cERROR(1,("No response buffer"));
+               if(midQ->midState == MID_REQUEST_SUBMITTED) {
+                       if(ses->server->tcpStatus == CifsExiting)
+                               rc = -EHOSTDOWN;
+                       else {
+                               ses->server->tcpStatus = CifsNeedReconnect;
+                               midQ->midState = MID_RETRY_NEEDED;
+                       }
+               }
+
+               if (rc != -EHOSTDOWN) {
+                       if(midQ->midState == MID_RETRY_NEEDED) {
+                               rc = -EAGAIN;
+                               cFYI(1,("marking request for retry"));
+                       } else {
+                               rc = -EIO;
+                       }
+               }
+               spin_unlock(&GlobalMid_Lock);
+               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;
+       }
+  
+       if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
+               cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
+                       receive_len, xid));
+               rc = -EIO;
+       } else {                /* rcvd frame is ok */
+
+               if (midQ->resp_buf && 
+                       (midQ->midState == MID_RESPONSE_RECEIVED)) {
+                       in_buf->smb_buf_length = receive_len;
+                       /* BB verify that length would not overrun small buf */
+                       memcpy((char *)in_buf + 4,
+                              (char *)midQ->resp_buf + 4,
+                              receive_len);
+
+                       dump_smb(in_buf, 80);
+                       /* convert the length into a more usable form */
+                       if((receive_len > 24) &&
+                          (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+                                       SECMODE_SIGN_ENABLED))) {
+                               rc = cifs_verify_signature(in_buf,
+                                               ses->server->mac_signing_key,
+                                               midQ->sequence_number+1);
+                               if(rc) {
+                                       cERROR(1,("Unexpected SMB signature"));
+                                       /* BB FIXME add code to kill session */
+                               }
+                       }
+
+                       *pbytes_returned = in_buf->smb_buf_length;
+
+                       /* BB special case reconnect tid and uid here? */
+                       rc = map_smb_to_linux_error(in_buf);
+
+                       /* convert ByteCount if necessary */
+                       if (receive_len >=
+                           sizeof (struct smb_hdr) -
+                           4 /* do not count RFC1001 header */  +
+                           (2 * in_buf->WordCount) + 2 /* bcc */ )
+                               BCC(in_buf) = le16_to_cpu(BCC(in_buf));
+               } else {
+                       rc = -EIO;
+                       cFYI(1,("Bad MID state? "));
+               }
+       }
+cifs_no_response_exit2:
+       DeleteMidQEntry(midQ);
+
        if(long_op < 3) {
-               atomic_dec(&ses->server->inFlight);
+               atomic_dec(&ses->server->inFlight); 
                wake_up(&ses->server->request_q);
        }
 
        return rc;
-}
 
+out_unlock2:
+       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;
+}
 #endif /* CIFS_EXPERIMENTAL */
 
 int
@@ -610,7 +735,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                                BCC(out_buf) = le16_to_cpu(BCC(out_buf));
                } else {
                        rc = -EIO;
-                       cFYI(1,("Bad MID state? "));
+                       cERROR(1,("Bad MID state? "));
                }
        }
 cifs_no_response_exit: