Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
authorSteve French <sfrench@us.ibm.com>
Wed, 10 Aug 2005 15:05:35 +0000 (08:05 -0700)
committerSteve French <sfrench@us.ibm.com>
Wed, 10 Aug 2005 15:05:35 +0000 (08:05 -0700)
french@hera:~/linux-2.6(0)$ cg-update
l
`/pub/scm/linux/kernel/git/torvalds/linux-2.6.git/refs/heads/master' ->
`.git/refs/heads/origin'
cp: cannot create link `.git/objects/info/packs': File exists
progress: 213 objects, 646653 bytes, 77% done
`/pub/scm/linux/kernel/git/torvalds/linux-2.6.git/objects/info/packs' ->
`.git/objects/info/packs'
progress: 983 objects, 2805763 bytes, 100% done
cg-pull: objects pull failed

18 files changed:
fs/cifs/CHANGES
fs/cifs/cifs_debug.c
fs/cifs/cifs_fs_sb.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
fs/cifs/xattr.c

index dab4774ee7bbb6c7d9a92655a4a600d80c0da896..3196d4c4eed36fde53bc857563b2dff2d403abb9 100644 (file)
@@ -1,3 +1,9 @@
+Version 1.35
+------------
+Add writepage performance improvements.  Fix path name conversions
+for long filenames on mounts which were done with "mapchars" mount option
+specified.
+
 Version 1.34
 ------------
 Fix error mapping of the TOO_MANY_LINKS (hardlinks) case.
index 4061e43471c1a1dc1822fcae3dca02c4406794f0..8381713280769679464e2609c035653e7111bc6d 100644 (file)
@@ -283,6 +283,12 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
                        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 +366,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 +425,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..6b93587c490e538a56980282fe2d76eafd21aa13 100644 (file)
@@ -24,6 +24,8 @@
 #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 */
 
 struct cifs_sb_info {
        struct cifsTconInfo *tcon;      /* primary mount */
index 81babab265e1a31fcad6c97429fadc8d052890fd..d3773e57acf99e75aa490f59d89bc18c9a133458 100644 (file)
@@ -219,6 +219,9 @@ struct cifsTconInfo {
        atomic_t num_rmdirs;
        atomic_t num_renames;
        atomic_t num_t2renames;
+       atomic_t num_ffirst;
+       atomic_t num_fnext;
+       atomic_t num_fclose;
        __u64    bytes_read;
        __u64    bytes_written;
        spinlock_t stat_lock;
@@ -306,6 +309,13 @@ 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 '\\';
+}
 
 /* one of these for every pending CIFS request to the server */
 struct mid_q_entry {
index aede6a81316794a1a20de497c9684f96e20f6f0c..3cef57b7a34f38d1438c319bd5856cae2322e642 100644 (file)
@@ -59,6 +59,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
@@ -1411,6 +1420,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 +1597,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 */
index ea239dea571e1f0a02374079ca0e918bf072cb01..66eaa6b40373166730ecc3123ef7fdc8633bdb85 100644 (file)
@@ -40,13 +40,17 @@ extern unsigned int _GetXid(void);
 extern void _FreeXid(unsigned int);
 #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid));
 #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));}
-extern char *build_path_from_dentry(struct dentry *);
+extern char *build_path_from_dentry(struct dentry *, const struct cifs_sb_info *cifs_sb);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 extern void renew_parental_timestamps(struct dentry *direntry);
 extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
                        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);
@@ -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);
@@ -125,6 +129,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);
@@ -222,7 +229,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, 
index 3c628bf667a5f010ff17c14d2ffc04f499d80c7d..e555cb5cf493766d25a9f48f78abdd7649d41a73 100644 (file)
@@ -738,7 +738,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 +758,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 =
@@ -951,56 +957,69 @@ 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);
        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 +1028,8 @@ int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 
        return rc;
 }
+
+
 #endif /* CIFS_EXPERIMENTAL */
 
 int
@@ -2396,7 +2417,9 @@ findUniqueRetry:
        if (rc) {
                cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
        } else {                /* decode response */
-
+#ifdef CONFIG_CIFS_STATS
+               atomic_inc(&tcon->num_ffirst);
+#endif
                /* BB fill in */
        }
 
@@ -2414,7 +2437,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 +2464,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 +2478,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;
@@ -2509,6 +2532,9 @@ findFirstRetry:
                if (rc == -EAGAIN)
                        goto findFirstRetry;
        } else { /* decode response */
+#ifdef CONFIG_CIFS_STATS
+               atomic_inc(&tcon->num_ffirst);
+#endif
                /* BB remember to free buffer if error BB */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
                if(rc == 0) {
@@ -2602,6 +2628,9 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
        if(name_len < PATH_MAX) {
                memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
                byte_count += name_len;
+               /* 14 byte parm len above enough for 2 byte null terminator */
+               pSMB->ResumeFileName[name_len] = 0;
+               pSMB->ResumeFileName[name_len+1] = 0;
        } else {
                rc = -EINVAL;
                goto FNext2_err_exit;
@@ -2622,6 +2651,9 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
                } else
                        cFYI(1, ("FindNext returned = %d", rc));
        } else {                /* decode response */
+#ifdef CONFIG_CIFS_STATS
+               atomic_inc(&tcon->num_fnext);
+#endif
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
                
                if(rc == 0) {
@@ -2691,6 +2723,9 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
        if (rc) {
                cERROR(1, ("Send error in FindClose = %d", rc));
        }
+#ifdef CONFIG_CIFS_STATS
+       atomic_inc(&tcon->num_fclose);
+#endif
        cifs_small_buf_release(pSMB);
 
        /* Since session is dead, search handle closed on server already */
@@ -3254,6 +3289,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,
index e568cc47a7f93005518d1470696f89ee1444a1ae..36f78596c81a8a97900b36eb7c6b88486b3798fc 100644 (file)
@@ -74,6 +74,8 @@ 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 int rsize;
        unsigned int wsize;
        unsigned int sockopt;
@@ -745,6 +747,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;
 
@@ -1023,6 +1028,14 @@ 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, "setuids", 7) == 0) {
                        vol->setuids = 1;
                } else if (strnicmp(data, "nosetuids", 9) == 0) {
@@ -1679,6 +1692,9 @@ 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.direct_io) {
                        cERROR(1,("mounting share using direct i/o"));
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
@@ -1781,6 +1797,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"));
+                                       }
+                               }
                        }
                }
        }
index 3f3538d4a1fad105c0a776ef5f6d6e18fef0ff6c..c0f20fc092903702a472c792583a0579160d350b 100644 (file)
@@ -43,7 +43,7 @@ renew_parental_timestamps(struct dentry *direntry)
 
 /* Note: caller must free return buffer */
 char *
-build_path_from_dentry(struct dentry *direntry)
+build_path_from_dentry(struct dentry *direntry, const struct cifs_sb_info *cifs_sb)
 {
        struct dentry *temp;
        int namelen = 0;
@@ -74,7 +74,7 @@ cifs_bp_rename_retry:
                if (namelen < 0) {
                        break;
                } else {
-                       full_path[namelen] = '\\';
+                       full_path[namelen] = CIFS_DIR_SEP(cifs_sb);
                        strncpy(full_path + namelen + 1, temp->d_name.name,
                                temp->d_name.len);
                        cFYI(0, (" name: %s ", full_path + namelen));
@@ -138,7 +138,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        pTcon = cifs_sb->tcon;
 
        down(&direntry->d_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        up(&direntry->d_sb->s_vfs_rename_sem);
        if(full_path == NULL) {
                FreeXid(xid);
@@ -209,7 +209,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 */
                }
@@ -299,7 +299,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
        pTcon = cifs_sb->tcon;
 
        down(&direntry->d_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        up(&direntry->d_sb->s_vfs_rename_sem);
        if(full_path == NULL)
                rc = -ENOMEM;
@@ -326,6 +326,42 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
                        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);
@@ -360,7 +396,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
        /* can not grab the rename sem here since it would
        deadlock in the cases (beginning of sys_rename itself)
        in which we already have the sb rename sem */
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        if(full_path == NULL) {
                FreeXid(xid);
                return ERR_PTR(-ENOMEM);
index 7d2a9202c39a3291969307c1c57bdc18237fca57..d47ce7f49dc313a60102fc19d7e02f36adbec247 100644 (file)
@@ -83,7 +83,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
        pTcon = cifs_sb->tcon;
 
        down(&file->f_dentry->d_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(file->f_dentry);
+       full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
        up(&file->f_dentry->d_sb->s_vfs_rename_sem);
 
        if(full_path == NULL) {
index 30ab70ce554716df92739f0b1643ce79053497e7..ddb25a0a63d5bc0fcb00883e65540e7fe950b050 100644 (file)
@@ -196,7 +196,7 @@ int cifs_open(struct inode *inode, struct file *file)
        }
 
        down(&inode->i_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(file->f_dentry);
+       full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
        up(&inode->i_sb->s_vfs_rename_sem);
        if (full_path == NULL) {
                FreeXid(xid);
@@ -359,7 +359,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
    those that already have the rename sem can end up causing writepage
    to get called and if the server was down that means we end up here,
    and we can never tell if the caller already has the rename_sem */
-       full_path = build_path_from_dentry(file->f_dentry);
+       full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
        if (full_path == NULL) {
                up(&pCifsFile->fh_sem);
                FreeXid(xid);
@@ -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, 
index 8d336a90025584a6fb524001ef71c123b6d881ec..628aa1a9fe64396e89f6c968fd043404d54c7133 100644 (file)
@@ -320,6 +320,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
@@ -412,7 +422,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
        /* Unlink can be called from rename so we can not grab the sem here
           since we deadlock otherwise */
 /*     down(&direntry->d_sb->s_vfs_rename_sem);*/
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
 /*     up(&direntry->d_sb->s_vfs_rename_sem);*/
        if (full_path == NULL) {
                FreeXid(xid);
@@ -556,7 +566,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
        pTcon = cifs_sb->tcon;
 
        down(&inode->i_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        up(&inode->i_sb->s_vfs_rename_sem);
        if (full_path == NULL) {
                FreeXid(xid);
@@ -627,7 +637,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
        pTcon = cifs_sb->tcon;
 
        down(&inode->i_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        up(&inode->i_sb->s_vfs_rename_sem);
        if (full_path == NULL) {
                FreeXid(xid);
@@ -680,8 +690,8 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
 
        /* we already  have the rename sem so we do not need to grab it again
           here to protect the path integrity */
-       fromName = build_path_from_dentry(source_direntry);
-       toName = build_path_from_dentry(target_direntry);
+       fromName = build_path_from_dentry(source_direntry, cifs_sb_source);
+       toName = build_path_from_dentry(target_direntry, cifs_sb_target);
        if ((fromName == NULL) || (toName == NULL)) {
                rc = -ENOMEM;
                goto cifs_rename_exit;
@@ -797,7 +807,7 @@ int cifs_revalidate(struct dentry *direntry)
 
        /* can not safely grab the rename sem here if rename calls revalidate
           since that would deadlock */
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        if (full_path == NULL) {
                FreeXid(xid);
                return -ENOMEM;
@@ -946,7 +956,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
        pTcon = cifs_sb->tcon;
 
        down(&direntry->d_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        up(&direntry->d_sb->s_vfs_rename_sem);
        if (full_path == NULL) {
                FreeXid(xid);
index bde0fabfece0aeeaecd9ab4b1c2cf733009975b1..214aa816f66919aa5f37bfeedf506db0b4733769 100644 (file)
@@ -49,8 +49,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
    BB note DFS case in future though (when we may have to check) */
 
        down(&inode->i_sb->s_vfs_rename_sem);
-       fromName = build_path_from_dentry(old_file);
-       toName = build_path_from_dentry(direntry);
+       fromName = build_path_from_dentry(old_file, cifs_sb_target);
+       toName = build_path_from_dentry(direntry, cifs_sb_target);
        up(&inode->i_sb->s_vfs_rename_sem);
        if((fromName == NULL) || (toName == NULL)) {
                rc = -ENOMEM;
@@ -105,16 +105,17 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
 
        xid = GetXid();
 
+       cifs_sb = CIFS_SB(inode->i_sb);
+       pTcon = cifs_sb->tcon;
+
        down(&direntry->d_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        up(&direntry->d_sb->s_vfs_rename_sem);
 
        if (!full_path)
                goto out_no_free;
 
        cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
-       cifs_sb = CIFS_SB(inode->i_sb);
-       pTcon = cifs_sb->tcon;
        target_path = kmalloc(PATH_MAX, GFP_KERNEL);
        if (!target_path) {
                target_path = ERR_PTR(-ENOMEM);
@@ -167,7 +168,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
        pTcon = cifs_sb->tcon;
 
        down(&inode->i_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        up(&inode->i_sb->s_vfs_rename_sem);
 
        if(full_path == NULL) {
@@ -233,7 +234,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
 /* BB would it be safe against deadlock to grab this sem 
       even though rename itself grabs the sem and calls lookup? */
 /*       down(&inode->i_sb->s_vfs_rename_sem);*/
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
 /*       up(&inode->i_sb->s_vfs_rename_sem);*/
 
        if(full_path == NULL) {
index 072b4ee8c53e1a28c51002d8a331c497a0b8c05c..20ae4153f791673d4137bf885db2b8b92cda8852 100644 (file)
@@ -611,6 +611,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
                src_char = source[i];
                switch (src_char) {
                        case 0:
+                               target[j] = 0;
                                goto ctoUCS_out;
                        case ':':
                                target[j] = cpu_to_le16(UNI_COLON);
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..dec3c9dd04d7e1a4d2c276a0dd482c2c3986332e 100644 (file)
@@ -148,6 +148,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;
@@ -190,8 +197,9 @@ static void fill_in_inode(struct inode *tmp_inode,
                tmp_inode->i_data.a_ops = &cifs_addr_ops;
 
                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)) {
@@ -353,7 +361,7 @@ static int initiate_cifs_search(const int xid, struct file *file)
                return -EINVAL;
 
        down(&file->f_dentry->d_sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(file->f_dentry);
+       full_path = build_path_from_dentry(file->f_dentry, cifs_sb);
        up(&file->f_dentry->d_sb->s_vfs_rename_sem);
 
        if(full_path == NULL) {
@@ -374,7 +382,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 +544,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;
        }
@@ -555,7 +564,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
                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);
@@ -721,7 +730,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));
        }
@@ -906,7 +916,8 @@ 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;
index 0046c219833d6cfbef77e85addc663e1be71e290..496a2738bbe3d5915276072194770b22545c243b 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
index c1e02eff1d25a222613f48b5312cb055776abc00..f4fc8ddebba75d7de8bae505195d48261e4258f1 100644 (file)
@@ -63,7 +63,7 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name)
        pTcon = cifs_sb->tcon;
                                                                                      
        down(&sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        up(&sb->s_vfs_rename_sem);
        if(full_path == NULL) {
                FreeXid(xid);
@@ -118,7 +118,7 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
        pTcon = cifs_sb->tcon;
 
        down(&sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        up(&sb->s_vfs_rename_sem);
        if(full_path == NULL) {
                FreeXid(xid);
@@ -227,7 +227,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
        pTcon = cifs_sb->tcon;
 
        down(&sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        up(&sb->s_vfs_rename_sem);
        if(full_path == NULL) {
                FreeXid(xid);
@@ -328,7 +328,7 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
        pTcon = cifs_sb->tcon;
 
        down(&sb->s_vfs_rename_sem);
-       full_path = build_path_from_dentry(direntry);
+       full_path = build_path_from_dentry(direntry, cifs_sb);
        up(&sb->s_vfs_rename_sem);
        if(full_path == NULL) {
                FreeXid(xid);