Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 8 Aug 2008 23:18:34 +0000 (16:18 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 8 Aug 2008 23:18:34 +0000 (16:18 -0700)
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  [CIFS] list entry can not return null
  turn cifs_setattr into a multiplexor that calls the correct function
  move file time and dos attribute setting logic into new function
  spin off cifs_setattr with unix extensions to its own function
  [CIFS] Code cleanup in old sessionsetup code
  [CIFS] cifs_mkdir and cifs_create should respect the setgid bit on parent dir
  Rename CIFSSMBSetFileTimes to CIFSSMBSetFileInfo and add PID arg
  change CIFSSMBSetTimes to CIFSSMBSetPathInfo
  [CIFS] fix trailing whitespace
  bundle up Unix SET_PATH_INFO args into a struct and change name
  Fix missing braces in cifs_revalidate()
  remove locking around tcpSesAllocCount atomic variable
  [CIFS] properly account for new user= field in SPNEGO upcall string allocation
  [CIFS] remove level of indentation from decode_negTokenInit
  [CIFS] cifs send2 not retrying enough in some cases on full socket
  [CIFS] oid should also be checked against class in cifs asn

14 files changed:
fs/cifs/CHANGES
fs/cifs/asn1.c
fs/cifs/cifs_debug.c
fs/cifs/cifs_spnego.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/transport.c

index 1f34652..f5d0083 100644 (file)
@@ -1,3 +1,11 @@
+Version 1.54
+------------
+Fix premature write failure on congested networks (we would give up
+on EAGAIN from the socket too quickly on large writes).
+Cifs_mkdir and cifs_create now respect the setgid bit on parent dir.
+Fix endian problems in acl (mode from/to cifs acl) on bigendian
+architectures.
+
 Version 1.53
 ------------
 DFS support added (Microsoft Distributed File System client support needed
index 6bb440b..5fabd2c 100644 (file)
@@ -483,6 +483,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
 
        asn1_open(&ctx, security_blob, length);
 
+       /* GSSAPI header */
        if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
                cFYI(1, ("Error decoding negTokenInit header"));
                return 0;
@@ -490,153 +491,142 @@ decode_negTokenInit(unsigned char *security_blob, int length,
                   || (tag != ASN1_EOC)) {
                cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag));
                return 0;
-       } else {
-               /*      remember to free obj->oid */
-               rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
-               if (rc) {
-                       if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
-                               rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
-                               if (rc) {
-                                       rc = compare_oid(oid, oidlen,
-                                                        SPNEGO_OID,
-                                                        SPNEGO_OID_LEN);
-                                       kfree(oid);
-                               }
-                       } else
-                               rc = 0;
-               }
+       }
 
-               if (!rc) {
-                       cFYI(1, ("Error decoding negTokenInit header"));
-                       return 0;
-               }
+       /* Check for SPNEGO OID -- remember to free obj->oid */
+       rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
+       if (rc) {
+               if ((tag == ASN1_OJI) && (con == ASN1_PRI) &&
+                   (cls == ASN1_UNI)) {
+                       rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
+                       if (rc) {
+                               rc = compare_oid(oid, oidlen, SPNEGO_OID,
+                                                SPNEGO_OID_LEN);
+                               kfree(oid);
+                       }
+               } else
+                       rc = 0;
+       }
 
-               if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding negTokenInit"));
-                       return 0;
-               } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
-                          || (tag != ASN1_EOC)) {
-                       cFYI(1,
-                            ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
-                             cls, con, tag, end, *end));
-                       return 0;
-               }
+       /* SPNEGO OID not present or garbled -- bail out */
+       if (!rc) {
+               cFYI(1, ("Error decoding negTokenInit header"));
+               return 0;
+       }
 
-               if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding negTokenInit"));
-                       return 0;
-               } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
-                          || (tag != ASN1_SEQ)) {
-                       cFYI(1,
-                            ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
-                             cls, con, tag, end, *end));
-                       return 0;
-               }
+       if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+               cFYI(1, ("Error decoding negTokenInit"));
+               return 0;
+       } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
+                  || (tag != ASN1_EOC)) {
+               cFYI(1,
+                    ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
+                     cls, con, tag, end, *end));
+               return 0;
+       }
 
-               if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding 2nd part of negTokenInit"));
-                       return 0;
-               } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
-                          || (tag != ASN1_EOC)) {
-                       cFYI(1,
-                            ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
-                             cls, con, tag, end, *end));
-                       return 0;
-               }
+       if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+               cFYI(1, ("Error decoding negTokenInit"));
+               return 0;
+       } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
+                  || (tag != ASN1_SEQ)) {
+               cFYI(1,
+                    ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
+                     cls, con, tag, end, *end));
+               return 0;
+       }
 
-               if (asn1_header_decode
-                   (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
-                       cFYI(1, ("Error decoding 2nd part of negTokenInit"));
-                       return 0;
-               } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
-                          || (tag != ASN1_SEQ)) {
-                       cFYI(1,
-                            ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
-                             cls, con, tag, end, *end));
-                       return 0;
-               }
+       if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+               cFYI(1, ("Error decoding 2nd part of negTokenInit"));
+               return 0;
+       } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
+                  || (tag != ASN1_EOC)) {
+               cFYI(1,
+                    ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
+                     cls, con, tag, end, *end));
+               return 0;
+       }
 
-               while (!asn1_eoc_decode(&ctx, sequence_end)) {
-                       rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
-                       if (!rc) {
-                               cFYI(1,
-                                    ("Error decoding negTokenInit hdr exit2"));
-                               return 0;
-                       }
-                       if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
-                               if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) {
-
-                                       cFYI(1,
-                                         ("OID len = %d oid = 0x%lx 0x%lx "
-                                          "0x%lx 0x%lx",
-                                          oidlen, *oid, *(oid + 1),
-                                          *(oid + 2), *(oid + 3)));
-
-                                       if (compare_oid(oid, oidlen,
-                                                       MSKRB5_OID,
-                                                       MSKRB5_OID_LEN))
-                                               use_kerberos = true;
-                                       else if (compare_oid(oid, oidlen,
-                                                            KRB5_OID,
-                                                            KRB5_OID_LEN))
-                                               use_kerberos = true;
-                                       else if (compare_oid(oid, oidlen,
-                                                            NTLMSSP_OID,
-                                                            NTLMSSP_OID_LEN))
-                                               use_ntlmssp = true;
-
-                                       kfree(oid);
-                               }
-                       } else {
-                               cFYI(1, ("Should be an oid what is going on?"));
-                       }
-               }
+       if (asn1_header_decode
+           (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
+               cFYI(1, ("Error decoding 2nd part of negTokenInit"));
+               return 0;
+       } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
+                  || (tag != ASN1_SEQ)) {
+               cFYI(1,
+                    ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
+                     cls, con, tag, end, *end));
+               return 0;
+       }
 
-               if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1,
-                            ("Error decoding last part negTokenInit exit3"));
-                       return 0;
-               } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
-                       /* tag = 3 indicating mechListMIC */
+       while (!asn1_eoc_decode(&ctx, sequence_end)) {
+               rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
+               if (!rc) {
                        cFYI(1,
-                            ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)",
-                             cls, con, tag, end, *end));
+                            ("Error decoding negTokenInit hdr exit2"));
                        return 0;
                }
-               if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1,
-                            ("Error decoding last part negTokenInit exit5"));
-                       return 0;
-               } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
-                          || (tag != ASN1_SEQ)) {
-                       cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)",
-                               cls, con, tag, end, *end));
+               if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
+                       if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) {
+
+                               cFYI(1, ("OID len = %d oid = 0x%lx 0x%lx "
+                                        "0x%lx 0x%lx", oidlen, *oid,
+                                        *(oid + 1), *(oid + 2), *(oid + 3)));
+
+                               if (compare_oid(oid, oidlen, MSKRB5_OID,
+                                               MSKRB5_OID_LEN))
+                                       use_kerberos = true;
+                               else if (compare_oid(oid, oidlen, KRB5_OID,
+                                                    KRB5_OID_LEN))
+                                       use_kerberos = true;
+                               else if (compare_oid(oid, oidlen, NTLMSSP_OID,
+                                                    NTLMSSP_OID_LEN))
+                                       use_ntlmssp = true;
+
+                               kfree(oid);
+                       }
+               } else {
+                       cFYI(1, ("Should be an oid what is going on?"));
                }
+       }
 
-               if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1,
-                            ("Error decoding last part negTokenInit exit 7"));
-                       return 0;
-               } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
-                       cFYI(1,
-                            ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)",
-                             cls, con, tag, end, *end));
-                       return 0;
-               }
-               if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
-                       cFYI(1,
-                            ("Error decoding last part negTokenInit exit9"));
-                       return 0;
-               } else if ((cls != ASN1_UNI) || (con != ASN1_PRI)
-                          || (tag != ASN1_GENSTR)) {
-                       cFYI(1,
-                            ("Exit10 cls = %d con = %d tag = %d end = %p (%d)",
-                             cls, con, tag, end, *end));
-                       return 0;
-               }
-               cFYI(1, ("Need to call asn1_octets_decode() function for %s",
-                        ctx.pointer)); /* is this UTF-8 or ASCII? */
+       if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+               cFYI(1, ("Error decoding last part negTokenInit exit3"));
+               return 0;
+       } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
+               /* tag = 3 indicating mechListMIC */
+               cFYI(1, ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)",
+                        cls, con, tag, end, *end));
+               return 0;
+       }
+       if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+               cFYI(1, ("Error decoding last part negTokenInit exit5"));
+               return 0;
+       } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
+                  || (tag != ASN1_SEQ)) {
+               cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)",
+                       cls, con, tag, end, *end));
+       }
+
+       if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+               cFYI(1, ("Error decoding last part negTokenInit exit 7"));
+               return 0;
+       } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
+               cFYI(1, ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)",
+                        cls, con, tag, end, *end));
+               return 0;
+       }
+       if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+               cFYI(1, ("Error decoding last part negTokenInit exit9"));
+               return 0;
+       } else if ((cls != ASN1_UNI) || (con != ASN1_PRI)
+                  || (tag != ASN1_GENSTR)) {
+               cFYI(1, ("Exit10 cls = %d con = %d tag = %d end = %p (%d)",
+                        cls, con, tag, end, *end));
+               return 0;
        }
+       cFYI(1, ("Need to call asn1_octets_decode() function for %s",
+                ctx.pointer)); /* is this UTF-8 or ASCII? */
 
        if (use_kerberos)
                *secType = Kerberos;
index 688a2d4..69a12aa 100644 (file)
@@ -79,27 +79,25 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
        spin_lock(&GlobalMid_Lock);
        list_for_each(tmp, &server->pending_mid_q) {
                mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
-               if (mid_entry) {
-                       cERROR(1, ("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
-                               mid_entry->midState,
-                               (int)mid_entry->command,
-                               mid_entry->pid,
-                               mid_entry->tsk,
-                               mid_entry->mid));
+               cERROR(1, ("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
+                       mid_entry->midState,
+                       (int)mid_entry->command,
+                       mid_entry->pid,
+                       mid_entry->tsk,
+                       mid_entry->mid));
 #ifdef CONFIG_CIFS_STATS2
-                       cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld",
-                               mid_entry->largeBuf,
-                               mid_entry->resp_buf,
-                               mid_entry->when_received,
-                               jiffies));
+               cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld",
+                       mid_entry->largeBuf,
+                       mid_entry->resp_buf,
+                       mid_entry->when_received,
+                       jiffies));
 #endif /* STATS2 */
-                       cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
-                                 mid_entry->multiEnd));
-                       if (mid_entry->resp_buf) {
-                               cifs_dump_detail(mid_entry->resp_buf);
-                               cifs_dump_mem("existing buf: ",
-                                       mid_entry->resp_buf, 62);
-                       }
+               cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
+                         mid_entry->multiEnd));
+               if (mid_entry->resp_buf) {
+                       cifs_dump_detail(mid_entry->resp_buf);
+                       cifs_dump_mem("existing buf: ",
+                               mid_entry->resp_buf, 62);
                }
        }
        spin_unlock(&GlobalMid_Lock);
@@ -163,16 +161,13 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                                mid_entry = list_entry(tmp1, struct
                                        mid_q_entry,
                                        qhead);
-                               if (mid_entry) {
-                                       seq_printf(m,
-                                                       "State: %d com: %d pid:"
-                                                       " %d tsk: %p mid %d\n",
-                                                       mid_entry->midState,
-                                                       (int)mid_entry->command,
-                                                       mid_entry->pid,
-                                                       mid_entry->tsk,
-                                                       mid_entry->mid);
-                               }
+                               seq_printf(m, "State: %d com: %d pid:"
+                                               " %d tsk: %p mid %d\n",
+                                               mid_entry->midState,
+                                               (int)mid_entry->command,
+                                               mid_entry->pid,
+                                               mid_entry->tsk,
+                                               mid_entry->mid);
                        }
                        spin_unlock(&GlobalMid_Lock);
                }
index 7013aaf..2434ab0 100644 (file)
@@ -66,8 +66,8 @@ struct key_type cifs_spnego_key_type = {
        .describe       = user_describe,
 };
 
-#define MAX_VER_STR_LEN   9 /* length of longest version string e.g.
-                               strlen(";ver=0xFF") */
+#define MAX_VER_STR_LEN   8 /* length of longest version string e.g.
+                               strlen("ver=0xFF") */
 #define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg
                               in future could have strlen(";sec=ntlmsspi") */
 #define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
@@ -81,11 +81,15 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
        struct key *spnego_key;
        const char *hostname = server->hostname;
 
-       /* BB: come up with better scheme for determining length */
-       /* length of fields (with semicolons): ver=0xyz ipv4= ipaddress host=
-          hostname sec=mechanism uid=0x uid */
-       desc_len = MAX_VER_STR_LEN + 5 + MAX_IPV6_ADDR_LEN + 1 + 6 +
-                 strlen(hostname) + MAX_MECH_STR_LEN + 8 + (sizeof(uid_t) * 2);
+       /* length of fields (with semicolons): ver=0xyz ip4=ipaddress
+          host=hostname sec=mechanism uid=0xFF user=username */
+       desc_len = MAX_VER_STR_LEN +
+                  6 /* len of "host=" */ + strlen(hostname) +
+                  5 /* len of ";ipv4=" */ + MAX_IPV6_ADDR_LEN +
+                  MAX_MECH_STR_LEN +
+                  7 /* len of ";uid=0x" */ + (sizeof(uid_t) * 2) +
+                  6 /* len of ";user=" */ + strlen(sesInfo->userName) + 1;
+
        spnego_key = ERR_PTR(-ENOMEM);
        description = kzalloc(desc_len, GFP_KERNEL);
        if (description == NULL)
index 1ec7076..e8da4ee 100644 (file)
@@ -930,36 +930,34 @@ static int cifs_oplock_thread(void *dummyarg)
                        schedule_timeout(39*HZ);
                } else {
                        oplock_item = list_entry(GlobalOplock_Q.next,
-                               struct oplock_q_entry, qhead);
-                       if (oplock_item) {
-                               cFYI(1, ("found oplock item to write out"));
-                               pTcon = oplock_item->tcon;
-                               inode = oplock_item->pinode;
-                               netfid = oplock_item->netfid;
-                               spin_unlock(&GlobalMid_Lock);
-                               DeleteOplockQEntry(oplock_item);
-                               /* can not grab inode sem here since it would
+                                               struct oplock_q_entry, qhead);
+                       cFYI(1, ("found oplock item to write out"));
+                       pTcon = oplock_item->tcon;
+                       inode = oplock_item->pinode;
+                       netfid = oplock_item->netfid;
+                       spin_unlock(&GlobalMid_Lock);
+                       DeleteOplockQEntry(oplock_item);
+                       /* can not grab inode sem here since it would
                                deadlock when oplock received on delete
                                since vfs_unlink holds the i_mutex across
                                the call */
-                               /* mutex_lock(&inode->i_mutex);*/
-                               if (S_ISREG(inode->i_mode)) {
-                                       rc =
-                                          filemap_fdatawrite(inode->i_mapping);
-                                       if (CIFS_I(inode)->clientCanCacheRead
-                                                                        == 0) {
-                                               waitrc = filemap_fdatawait(inode->i_mapping);
-                                               invalidate_remote_inode(inode);
-                                       }
-                                       if (rc == 0)
-                                               rc = waitrc;
-                               } else
-                                       rc = 0;
-                               /* mutex_unlock(&inode->i_mutex);*/
-                               if (rc)
-                                       CIFS_I(inode)->write_behind_rc = rc;
-                               cFYI(1, ("Oplock flush inode %p rc %d",
-                                       inode, rc));
+                       /* mutex_lock(&inode->i_mutex);*/
+                       if (S_ISREG(inode->i_mode)) {
+                               rc = filemap_fdatawrite(inode->i_mapping);
+                               if (CIFS_I(inode)->clientCanCacheRead == 0) {
+                                       waitrc = filemap_fdatawait(
+                                                             inode->i_mapping);
+                                       invalidate_remote_inode(inode);
+                               }
+                               if (rc == 0)
+                                       rc = waitrc;
+                       } else
+                               rc = 0;
+                       /* mutex_unlock(&inode->i_mutex);*/
+                       if (rc)
+                               CIFS_I(inode)->write_behind_rc = rc;
+                       cFYI(1, ("Oplock flush inode %p rc %d",
+                               inode, rc));
 
                                /* releasing stale oplock after recent reconnect
                                of smb session using a now incorrect file
@@ -967,15 +965,13 @@ static int cifs_oplock_thread(void *dummyarg)
                                not bother sending an oplock release if session
                                to server still is disconnected since oplock
                                already released by the server in that case */
-                               if (pTcon->tidStatus != CifsNeedReconnect) {
-                                   rc = CIFSSMBLock(0, pTcon, netfid,
-                                           0 /* len */ , 0 /* offset */, 0,
-                                           0, LOCKING_ANDX_OPLOCK_RELEASE,
-                                           false /* wait flag */);
-                                       cFYI(1, ("Oplock release rc = %d", rc));
-                               }
-                       } else
-                               spin_unlock(&GlobalMid_Lock);
+                       if (pTcon->tidStatus != CifsNeedReconnect) {
+                               rc = CIFSSMBLock(0, pTcon, netfid,
+                                               0 /* len */ , 0 /* offset */, 0,
+                                               0, LOCKING_ANDX_OPLOCK_RELEASE,
+                                               false /* wait flag */);
+                               cFYI(1, ("Oplock release rc = %d", rc));
+                       }
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule_timeout(1);  /* yield in case q were corrupt */
                }
@@ -1001,8 +997,7 @@ static int cifs_dnotify_thread(void *dummyarg)
                list_for_each(tmp, &GlobalSMBSessionList) {
                        ses = list_entry(tmp, struct cifsSesInfo,
                                cifsSessionList);
-                       if (ses && ses->server &&
-                            atomic_read(&ses->server->inFlight))
+                       if (ses->server && atomic_read(&ses->server->inFlight))
                                wake_up_all(&ses->server->response_q);
                }
                read_unlock(&GlobalSMBSeslock);
index 25a6cbd..135c965 100644 (file)
@@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* EXPERIMENTAL */
 
-#define CIFS_VERSION   "1.53"
+#define CIFS_VERSION   "1.54"
 #endif                         /* _CIFSFS_H */
index 409abce..d2a073e 100644 (file)
  */
 #define CIFS_NO_HANDLE        0xFFFF
 
-#define NO_CHANGE_64          cpu_to_le64(0xFFFFFFFFFFFFFFFFULL)
+#define NO_CHANGE_64          0xFFFFFFFFFFFFFFFFULL
 #define NO_CHANGE_32          0xFFFFFFFFUL
 
 /* IPC$ in ASCII */
index b9f5e93..a729d08 100644 (file)
@@ -172,12 +172,13 @@ extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon);
 extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
                        struct kstatfs *FSData);
 
-extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
                        const char *fileName, const FILE_BASIC_INFO *data,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
-extern int CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
-                       const FILE_BASIC_INFO *data, __u16 fid);
+extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+                       const FILE_BASIC_INFO *data, __u16 fid,
+                       __u32 pid_of_opener);
 #if 0
 extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon,
                        char *fileName, __u16 dos_attributes,
@@ -191,9 +192,20 @@ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
 extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
                         __u64 size, __u16 fileHandle, __u32 opener_pid,
                        bool AllocSizeFlag);
-extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon,
-                       char *full_path, __u64 mode, __u64 uid,
-                       __u64 gid, dev_t dev,
+
+struct cifs_unix_set_info_args {
+       __u64   ctime;
+       __u64   atime;
+       __u64   mtime;
+       __u64   mode;
+       __u64   uid;
+       __u64   gid;
+       dev_t   device;
+};
+
+extern int CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *pTcon,
+                       char *fileName,
+                       const struct cifs_unix_set_info_args *args,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
 
index c621ffa..994de7c 100644 (file)
@@ -128,8 +128,7 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
        write_lock(&GlobalSMBSeslock);
        list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
                open_file = list_entry(tmp, struct cifsFileInfo, tlist);
-               if (open_file)
-                       open_file->invalidHandle = true;
+               open_file->invalidHandle = true;
        }
        write_unlock(&GlobalSMBSeslock);
        /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
@@ -4816,8 +4815,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
    time and resort to the original setpathinfo level which takes the ancient
    DOS time format with 2 second granularity */
 int
-CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
-                   const FILE_BASIC_INFO *data, __u16 fid)
+CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
+                   const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        char *data_offset;
@@ -4830,11 +4829,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
        if (rc)
                return rc;
 
-       /* At this point there is no need to override the current pid
-       with the pid of the opener, but that could change if we someday
-       use an existing handle (rather than opening one on the fly) */
-       /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
-       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
+       pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
 
        params = 6;
        pSMB->MaxSetupCount = 0;
@@ -4882,9 +4878,9 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
 
 
 int
-CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
-               const FILE_BASIC_INFO *data,
-               const struct nls_table *nls_codepage, int remap)
+CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
+                  const char *fileName, const FILE_BASIC_INFO *data,
+                  const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
        TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -5013,10 +5009,9 @@ SetAttrLgcyRetry:
 #endif /* temporarily unneeded SetAttr legacy function */
 
 int
-CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
-                   char *fileName, __u64 mode, __u64 uid, __u64 gid,
-                   dev_t device, const struct nls_table *nls_codepage,
-                   int remap)
+CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
+                  const struct cifs_unix_set_info_args *args,
+                  const struct nls_table *nls_codepage, int remap)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
        TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -5025,6 +5020,7 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
        int bytes_returned = 0;
        FILE_UNIX_BASIC_INFO *data_offset;
        __u16 params, param_offset, offset, count, byte_count;
+       __u64 mode = args->mode;
 
        cFYI(1, ("In SetUID/GID/Mode"));
 setPermsRetry:
@@ -5080,16 +5076,16 @@ setPermsRetry:
        set file size and do not want to truncate file size to zero
        accidently as happened on one Samba server beta by putting
        zero instead of -1 here */
-       data_offset->EndOfFile = NO_CHANGE_64;
-       data_offset->NumOfBytes = NO_CHANGE_64;
-       data_offset->LastStatusChange = NO_CHANGE_64;
-       data_offset->LastAccessTime = NO_CHANGE_64;
-       data_offset->LastModificationTime = NO_CHANGE_64;
-       data_offset->Uid = cpu_to_le64(uid);
-       data_offset->Gid = cpu_to_le64(gid);
+       data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
+       data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
+       data_offset->LastStatusChange = cpu_to_le64(args->ctime);
+       data_offset->LastAccessTime = cpu_to_le64(args->atime);
+       data_offset->LastModificationTime = cpu_to_le64(args->mtime);
+       data_offset->Uid = cpu_to_le64(args->uid);
+       data_offset->Gid = cpu_to_le64(args->gid);
        /* better to leave device as zero when it is  */
-       data_offset->DevMajor = cpu_to_le64(MAJOR(device));
-       data_offset->DevMinor = cpu_to_le64(MINOR(device));
+       data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
+       data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
        data_offset->Permissions = cpu_to_le64(mode);
 
        if (S_ISREG(mode))
index b51d577..0711db6 100644 (file)
@@ -151,7 +151,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
        }
        list_for_each(tmp, &GlobalTreeConnectionList) {
                tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
-               if ((tcon) && (tcon->ses) && (tcon->ses->server == server))
+               if ((tcon->ses) && (tcon->ses->server == server))
                        tcon->tidStatus = CifsNeedReconnect;
        }
        read_unlock(&GlobalSMBSeslock);
@@ -173,14 +173,12 @@ cifs_reconnect(struct TCP_Server_Info *server)
                mid_entry = list_entry(tmp, struct
                                        mid_q_entry,
                                        qhead);
-               if (mid_entry) {
-                       if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
+               if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
                                /* Mark other intransit requests as needing
                                   retry so we do not immediately mark the
                                   session bad again (ie after we reconnect
                                   below) as they timeout too */
-                               mid_entry->midState = MID_RETRY_NEEDED;
-                       }
+                       mid_entry->midState = MID_RETRY_NEEDED;
                }
        }
        spin_unlock(&GlobalMid_Lock);
@@ -351,11 +349,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 
        current->flags |= PF_MEMALLOC;
        cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
-       write_lock(&GlobalSMBSeslock);
-       atomic_inc(&tcpSesAllocCount);
-       length = tcpSesAllocCount.counter;
-       write_unlock(&GlobalSMBSeslock);
-       if (length  > 1)
+
+       length = atomic_inc_return(&tcpSesAllocCount);
+       if (length > 1)
                mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
                                GFP_KERNEL);
 
@@ -745,14 +741,11 @@ multi_t2_fnd:
                coming home not much else we can do but free the memory */
        }
 
-       write_lock(&GlobalSMBSeslock);
-       atomic_dec(&tcpSesAllocCount);
-       length = tcpSesAllocCount.counter;
-
        /* last chance to mark ses pointers invalid
        if there are any pointing to this (e.g
        if a crazy root user tried to kill cifsd
        kernel thread explicitly this might happen) */
+       write_lock(&GlobalSMBSeslock);
        list_for_each(tmp, &GlobalSMBSessionList) {
                ses = list_entry(tmp, struct cifsSesInfo,
                                cifsSessionList);
@@ -763,6 +756,8 @@ multi_t2_fnd:
 
        kfree(server->hostname);
        kfree(server);
+
+       length = atomic_dec_return(&tcpSesAllocCount);
        if (length  > 0)
                mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
                                GFP_KERNEL);
@@ -3623,97 +3618,91 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                }
                first_time = 1;
        }
-       if (!rc) {
-               pSesInfo->flags = 0;
-               pSesInfo->capabilities = pSesInfo->server->capabilities;
-               if (linuxExtEnabled == 0)
-                       pSesInfo->capabilities &= (~CAP_UNIX);
+
+       if (rc)
+               goto ss_err_exit;
+
+       pSesInfo->flags = 0;
+       pSesInfo->capabilities = pSesInfo->server->capabilities;
+       if (linuxExtEnabled == 0)
+               pSesInfo->capabilities &= (~CAP_UNIX);
        /*      pSesInfo->sequence_number = 0;*/
-               cFYI(1,
-                     ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
-                       pSesInfo->server->secMode,
-                       pSesInfo->server->capabilities,
-                       pSesInfo->server->timeAdj));
-               if (experimEnabled < 2)
-                       rc = CIFS_SessSetup(xid, pSesInfo,
-                                           first_time, nls_info);
-               else if (extended_security
-                               && (pSesInfo->capabilities
-                                       & CAP_EXTENDED_SECURITY)
-                               && (pSesInfo->server->secType == NTLMSSP)) {
-                       rc = -EOPNOTSUPP;
-               } else if (extended_security
-                          && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
-                          && (pSesInfo->server->secType == RawNTLMSSP)) {
-                       cFYI(1, ("NTLMSSP sesssetup"));
-                       rc = CIFSNTLMSSPNegotiateSessSetup(xid,
-                                               pSesInfo,
-                                               &ntlmv2_flag,
-                                               nls_info);
-                       if (!rc) {
-                               if (ntlmv2_flag) {
-                                       char *v2_response;
-                                       cFYI(1, ("more secure NTLM ver2 hash"));
-                                       if (CalcNTLMv2_partial_mac_key(pSesInfo,
-                                               nls_info)) {
-                                               rc = -ENOMEM;
-                                               goto ss_err_exit;
-                                       } else
-                                               v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
-                                       if (v2_response) {
-                                               CalcNTLMv2_response(pSesInfo,
-                                                                  v2_response);
-                               /*              if (first_time)
-                                                 cifs_calculate_ntlmv2_mac_key(
-                                                  pSesInfo->server->mac_signing_key,
-                                                  response, ntlm_session_key,*/
-                                               kfree(v2_response);
+       cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
+                pSesInfo->server->secMode,
+                pSesInfo->server->capabilities,
+                pSesInfo->server->timeAdj));
+       if (experimEnabled < 2)
+               rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
+       else if (extended_security
+                       && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+                       && (pSesInfo->server->secType == NTLMSSP)) {
+               rc = -EOPNOTSUPP;
+       } else if (extended_security
+                       && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+                       && (pSesInfo->server->secType == RawNTLMSSP)) {
+               cFYI(1, ("NTLMSSP sesssetup"));
+               rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
+                                                  nls_info);
+               if (!rc) {
+                       if (ntlmv2_flag) {
+                               char *v2_response;
+                               cFYI(1, ("more secure NTLM ver2 hash"));
+                               if (CalcNTLMv2_partial_mac_key(pSesInfo,
+                                                               nls_info)) {
+                                       rc = -ENOMEM;
+                                       goto ss_err_exit;
+                               } else
+                                       v2_response = kmalloc(16 + 64 /* blob*/,
+                                                               GFP_KERNEL);
+                               if (v2_response) {
+                                       CalcNTLMv2_response(pSesInfo,
+                                                               v2_response);
+                               /*      if (first_time)
+                                               cifs_calculate_ntlmv2_mac_key */
+                                       kfree(v2_response);
                                        /* BB Put dummy sig in SessSetup PDU? */
-                                       } else {
-                                               rc = -ENOMEM;
-                                               goto ss_err_exit;
-                                       }
-
                                } else {
-                                       SMBNTencrypt(pSesInfo->password,
-                                               pSesInfo->server->cryptKey,
-                                               ntlm_session_key);
-
-                                       if (first_time)
-                                               cifs_calculate_mac_key(
-                                                       &pSesInfo->server->mac_signing_key,
-                                                       ntlm_session_key,
-                                                       pSesInfo->password);
+                                       rc = -ENOMEM;
+                                       goto ss_err_exit;
                                }
+
+                       } else {
+                               SMBNTencrypt(pSesInfo->password,
+                                            pSesInfo->server->cryptKey,
+                                            ntlm_session_key);
+
+                               if (first_time)
+                                       cifs_calculate_mac_key(
+                                            &pSesInfo->server->mac_signing_key,
+                                            ntlm_session_key,
+                                            pSesInfo->password);
+                       }
                        /* for better security the weaker lanman hash not sent
                           in AuthSessSetup so we no longer calculate it */
 
-                               rc = CIFSNTLMSSPAuthSessSetup(xid,
-                                       pSesInfo,
-                                       ntlm_session_key,
-                                       ntlmv2_flag,
-                                       nls_info);
-                       }
-               } else { /* old style NTLM 0.12 session setup */
-                       SMBNTencrypt(pSesInfo->password,
-                               pSesInfo->server->cryptKey,
-                               ntlm_session_key);
+                       rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
+                                                     ntlm_session_key,
+                                                     ntlmv2_flag,
+                                                     nls_info);
+               }
+       } else { /* old style NTLM 0.12 session setup */
+               SMBNTencrypt(pSesInfo->password, pSesInfo->server->cryptKey,
+                            ntlm_session_key);
 
-                       if (first_time)
-                               cifs_calculate_mac_key(
+               if (first_time)
+                       cifs_calculate_mac_key(
                                        &pSesInfo->server->mac_signing_key,
                                        ntlm_session_key, pSesInfo->password);
 
-                       rc = CIFSSessSetup(xid, pSesInfo,
-                               ntlm_session_key, nls_info);
-               }
-               if (rc) {
-                       cERROR(1, ("Send error in SessSetup = %d", rc));
-               } else {
-                       cFYI(1, ("CIFS Session Established successfully"));
+               rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
+       }
+       if (rc) {
+               cERROR(1, ("Send error in SessSetup = %d", rc));
+       } else {
+               cFYI(1, ("CIFS Session Established successfully"));
                        pSesInfo->status = CifsGood;
-               }
        }
+
 ss_err_exit:
        return rc;
 }
index fb69c1f..e962e75 100644 (file)
@@ -226,23 +226,28 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                /* If Open reported that we actually created a file
                then we now have to set the mode if possible */
                if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
+                       struct cifs_unix_set_info_args args = {
+                               .mode   = mode,
+                               .ctime  = NO_CHANGE_64,
+                               .atime  = NO_CHANGE_64,
+                               .mtime  = NO_CHANGE_64,
+                               .device = 0,
+                       };
+
                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-                               CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
-                                       (__u64)current->fsuid,
-                                       (__u64)current->fsgid,
-                                       0 /* dev */,
-                                       cifs_sb->local_nls,
-                                       cifs_sb->mnt_cifs_flags &
-                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+                               args.uid = (__u64) current->fsuid;
+                               if (inode->i_mode & S_ISGID)
+                                       args.gid = (__u64) inode->i_gid;
+                               else
+                                       args.gid = (__u64) current->fsgid;
                        } else {
-                               CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
-                                       (__u64)-1,
-                                       (__u64)-1,
-                                       0 /* dev */,
-                                       cifs_sb->local_nls,
-                                       cifs_sb->mnt_cifs_flags &
-                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+                               args.uid = NO_CHANGE_64;
+                               args.gid = NO_CHANGE_64;
                        }
+                       CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
+                               cifs_sb->local_nls,
+                               cifs_sb->mnt_cifs_flags &
+                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
                } else {
                        /* BB implement mode setting via Windows security
                           descriptors e.g. */
@@ -267,7 +272,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
                                    (cifs_sb->mnt_cifs_flags &
                                     CIFS_MOUNT_SET_UID)) {
                                        newinode->i_uid = current->fsuid;
-                                       newinode->i_gid = current->fsgid;
+                                       if (inode->i_mode & S_ISGID)
+                                               newinode->i_gid =
+                                                       inode->i_gid;
+                                       else
+                                               newinode->i_gid =
+                                                       current->fsgid;
                                }
                        }
                }
@@ -357,21 +367,24 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
        if (full_path == NULL)
                rc = -ENOMEM;
        else if (pTcon->unix_ext) {
-               mode &= ~current->fs->umask;
+               struct cifs_unix_set_info_args args = {
+                       .mode   = mode & ~current->fs->umask,
+                       .ctime  = NO_CHANGE_64,
+                       .atime  = NO_CHANGE_64,
+                       .mtime  = NO_CHANGE_64,
+                       .device = device_number,
+               };
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-                       rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
-                               mode, (__u64)current->fsuid,
-                               (__u64)current->fsgid,
-                               device_number, cifs_sb->local_nls,
-                               cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+                       args.uid = (__u64) current->fsuid;
+                       args.gid = (__u64) current->fsgid;
                } else {
-                       rc = CIFSSMBUnixSetPerms(xid, pTcon,
-                               full_path, mode, (__u64)-1, (__u64)-1,
-                               device_number, cifs_sb->local_nls,
-                               cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+                       args.uid = NO_CHANGE_64;
+                       args.gid = NO_CHANGE_64;
                }
+               rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path,
+                       &args, cifs_sb->local_nls,
+                       cifs_sb->mnt_cifs_flags &
+                               CIFS_MOUNT_MAP_SPECIAL_CHR);
 
                if (!rc) {
                        rc = cifs_get_inode_info_unix(&newinode, full_path,
index e692c42..ff14d14 100644 (file)
@@ -310,18 +310,19 @@ int cifs_open(struct inode *inode, struct file *file)
                /* time to set mode which we can not set earlier due to
                   problems creating new read-only files */
                if (pTcon->unix_ext) {
-                       CIFSSMBUnixSetPerms(xid, pTcon, full_path,
-                                           inode->i_mode,
-                                           (__u64)-1, (__u64)-1, 0 /* dev */,
+                       struct cifs_unix_set_info_args args = {
+                               .mode   = inode->i_mode,
+                               .uid    = NO_CHANGE_64,
+                               .gid    = NO_CHANGE_64,
+                               .ctime  = NO_CHANGE_64,
+                               .atime  = NO_CHANGE_64,
+                               .mtime  = NO_CHANGE_64,
+                               .device = 0,
+                       };
+                       CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
                                            cifs_sb->local_nls,
                                            cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-               } else {
-                       /* BB implement via Windows security descriptors eg
-                          CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
-                                             -1, -1, local_nls);
-                          in the meantime could set r/o dos attribute when
-                          perms are eg: mode & 0222 == 0 */
                }
        }
 
index 46e54d3..28a2209 100644 (file)
@@ -737,7 +737,7 @@ psx_del_no_retry:
                        /* ATTRS set to normal clears r/o bit */
                        pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
                        if (!(pTcon->ses->flags & CIFS_SES_NT4))
-                               rc = CIFSSMBSetTimes(xid, pTcon, full_path,
+                               rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
                                                     pinfo_buf,
                                                     cifs_sb->local_nls,
                                                     cifs_sb->mnt_cifs_flags &
@@ -767,9 +767,10 @@ psx_del_no_retry:
                                                 cifs_sb->mnt_cifs_flags &
                                                    CIFS_MOUNT_MAP_SPECIAL_CHR);
                                if (rc == 0) {
-                                       rc = CIFSSMBSetFileTimes(xid, pTcon,
-                                                                pinfo_buf,
-                                                                netfid);
+                                       rc = CIFSSMBSetFileInfo(xid, pTcon,
+                                                               pinfo_buf,
+                                                               netfid,
+                                                               current->tgid);
                                        CIFSSMBClose(xid, pTcon, netfid);
                                }
                        }
@@ -984,32 +985,41 @@ mkdir_get_info:
                  * failed to get it from the server or was set bogus */
                if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
                                direntry->d_inode->i_nlink = 2;
+
                mode &= ~current->fs->umask;
+               /* must turn on setgid bit if parent dir has it */
+               if (inode->i_mode & S_ISGID)
+                       mode |= S_ISGID;
+
                if (pTcon->unix_ext) {
+                       struct cifs_unix_set_info_args args = {
+                               .mode   = mode,
+                               .ctime  = NO_CHANGE_64,
+                               .atime  = NO_CHANGE_64,
+                               .mtime  = NO_CHANGE_64,
+                               .device = 0,
+                       };
                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-                               CIFSSMBUnixSetPerms(xid, pTcon, full_path,
-                                                   mode,
-                                                   (__u64)current->fsuid,
-                                                   (__u64)current->fsgid,
-                                                   0 /* dev_t */,
-                                                   cifs_sb->local_nls,
-                                                   cifs_sb->mnt_cifs_flags &
-                                                   CIFS_MOUNT_MAP_SPECIAL_CHR);
+                               args.uid = (__u64)current->fsuid;
+                               if (inode->i_mode & S_ISGID)
+                                       args.gid = (__u64)inode->i_gid;
+                               else
+                                       args.gid = (__u64)current->fsgid;
                        } else {
-                               CIFSSMBUnixSetPerms(xid, pTcon, full_path,
-                                                   mode, (__u64)-1,
-                                                   (__u64)-1, 0 /* dev_t */,
-                                                   cifs_sb->local_nls,
-                                                   cifs_sb->mnt_cifs_flags &
-                                                   CIFS_MOUNT_MAP_SPECIAL_CHR);
+                               args.uid = NO_CHANGE_64;
+                               args.gid = NO_CHANGE_64;
                        }
+                       CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
+                                           cifs_sb->local_nls,
+                                           cifs_sb->mnt_cifs_flags &
+                                           CIFS_MOUNT_MAP_SPECIAL_CHR);
                } else {
                        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
                            (mode & S_IWUGO) == 0) {
                                FILE_BASIC_INFO pInfo;
                                memset(&pInfo, 0, sizeof(pInfo));
                                pInfo.Attributes = cpu_to_le32(ATTR_READONLY);
-                               CIFSSMBSetTimes(xid, pTcon, full_path,
+                               CIFSSMBSetPathInfo(xid, pTcon, full_path,
                                                &pInfo, cifs_sb->local_nls,
                                                cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1024,8 +1034,12 @@ mkdir_get_info:
                                     CIFS_MOUNT_SET_UID) {
                                        direntry->d_inode->i_uid =
                                                current->fsuid;
-                                       direntry->d_inode->i_gid =
-                                               current->fsgid;
+                                       if (inode->i_mode & S_ISGID)
+                                               direntry->d_inode->i_gid =
+                                                       inode->i_gid;
+                                       else
+                                               direntry->d_inode->i_gid =
+                                                       current->fsgid;
                                }
                        }
                }
@@ -1310,10 +1324,11 @@ int cifs_revalidate(struct dentry *direntry)
 /*             if (S_ISDIR(direntry->d_inode->i_mode))
                        shrink_dcache_parent(direntry); */
                if (S_ISREG(direntry->d_inode->i_mode)) {
-                       if (direntry->d_inode->i_mapping)
+                       if (direntry->d_inode->i_mapping) {
                                wbrc = filemap_fdatawait(direntry->d_inode->i_mapping);
                                if (wbrc)
                                        CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
+                       }
                        /* may eventually have to do this for open files too */
                        if (list_empty(&(cifsInode->openFileList))) {
                                /* changed on server - flush read ahead pages */
@@ -1489,30 +1504,228 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
        return rc;
 }
 
-int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
+static int
+cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
+                   char *full_path, __u32 dosattr)
+{
+       int rc;
+       int oplock = 0;
+       __u16 netfid;
+       __u32 netpid;
+       bool set_time = false;
+       struct cifsFileInfo *open_file;
+       struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct cifsTconInfo *pTcon = cifs_sb->tcon;
+       FILE_BASIC_INFO info_buf;
+
+       if (attrs->ia_valid & ATTR_ATIME) {
+               set_time = true;
+               info_buf.LastAccessTime =
+                       cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
+       } else
+               info_buf.LastAccessTime = 0;
+
+       if (attrs->ia_valid & ATTR_MTIME) {
+               set_time = true;
+               info_buf.LastWriteTime =
+                   cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
+       } else
+               info_buf.LastWriteTime = 0;
+
+       /*
+        * Samba throws this field away, but windows may actually use it.
+        * Do not set ctime unless other time stamps are changed explicitly
+        * (i.e. by utimes()) since we would then have a mix of client and
+        * server times.
+        */
+       if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
+               cFYI(1, ("CIFS - CTIME changed"));
+               info_buf.ChangeTime =
+                   cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
+       } else
+               info_buf.ChangeTime = 0;
+
+       info_buf.CreationTime = 0;      /* don't change */
+       info_buf.Attributes = cpu_to_le32(dosattr);
+
+       /*
+        * If the file is already open for write, just use that fileid
+        */
+       open_file = find_writable_file(cifsInode);
+       if (open_file) {
+               netfid = open_file->netfid;
+               netpid = open_file->pid;
+               goto set_via_filehandle;
+       }
+
+       /*
+        * NT4 apparently returns success on this call, but it doesn't
+        * really work.
+        */
+       if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
+               rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
+                                    &info_buf, cifs_sb->local_nls,
+                                    cifs_sb->mnt_cifs_flags &
+                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+               if (rc != -EOPNOTSUPP && rc != -EINVAL)
+                       goto out;
+       }
+
+       cFYI(1, ("calling SetFileInfo since SetPathInfo for "
+                "times not supported by this server"));
+       rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
+                        SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
+                        CREATE_NOT_DIR, &netfid, &oplock,
+                        NULL, cifs_sb->local_nls,
+                        cifs_sb->mnt_cifs_flags &
+                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+       if (rc != 0) {
+               if (rc == -EIO)
+                       rc = -EINVAL;
+               goto out;
+       }
+
+       netpid = current->tgid;
+
+set_via_filehandle:
+       rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
+       if (open_file == NULL)
+               CIFSSMBClose(xid, pTcon, netfid);
+       else
+               atomic_dec(&open_file->wrtPending);
+out:
+       return rc;
+}
+
+static int
+cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
 {
+       int rc;
        int xid;
-       struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *pTcon;
        char *full_path = NULL;
-       int rc = -EACCES;
-       FILE_BASIC_INFO time_buf;
-       bool set_time = false;
-       bool set_dosattr = false;
-       __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
-       __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
-       __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
-       struct cifsInodeInfo *cifsInode;
        struct inode *inode = direntry->d_inode;
+       struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct cifsTconInfo *pTcon = cifs_sb->tcon;
+       struct cifs_unix_set_info_args *args = NULL;
+
+       cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x",
+                direntry->d_name.name, attrs->ia_valid));
+
+       xid = GetXid();
+
+       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
+               /* check if we have permission to change attrs */
+               rc = inode_change_ok(inode, attrs);
+               if (rc < 0)
+                       goto out;
+               else
+                       rc = 0;
+       }
+
+       full_path = build_path_from_dentry(direntry);
+       if (full_path == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
+               /*
+                  Flush data before changing file size or changing the last
+                  write time of the file on the server. If the
+                  flush returns error, store it to report later and continue.
+                  BB: This should be smarter. Why bother flushing pages that
+                  will be truncated anyway? Also, should we error out here if
+                  the flush returns error?
+                */
+               rc = filemap_write_and_wait(inode->i_mapping);
+               if (rc != 0) {
+                       cifsInode->write_behind_rc = rc;
+                       rc = 0;
+               }
+       }
+
+       if (attrs->ia_valid & ATTR_SIZE) {
+               rc = cifs_set_file_size(inode, attrs, xid, full_path);
+               if (rc != 0)
+                       goto out;
+       }
+
+       /* skip mode change if it's just for clearing setuid/setgid */
+       if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
+               attrs->ia_valid &= ~ATTR_MODE;
+
+       args = kmalloc(sizeof(*args), GFP_KERNEL);
+       if (args == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       /* set up the struct */
+       if (attrs->ia_valid & ATTR_MODE)
+               args->mode = attrs->ia_mode;
+       else
+               args->mode = NO_CHANGE_64;
+
+       if (attrs->ia_valid & ATTR_UID)
+               args->uid = attrs->ia_uid;
+       else
+               args->uid = NO_CHANGE_64;
+
+       if (attrs->ia_valid & ATTR_GID)
+               args->gid = attrs->ia_gid;
+       else
+               args->gid = NO_CHANGE_64;
+
+       if (attrs->ia_valid & ATTR_ATIME)
+               args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
+       else
+               args->atime = NO_CHANGE_64;
+
+       if (attrs->ia_valid & ATTR_MTIME)
+               args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
+       else
+               args->mtime = NO_CHANGE_64;
+
+       if (attrs->ia_valid & ATTR_CTIME)
+               args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
+       else
+               args->ctime = NO_CHANGE_64;
+
+       args->device = 0;
+       rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, args,
+                               cifs_sb->local_nls,
+                               cifs_sb->mnt_cifs_flags &
+                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+       if (!rc)
+               rc = inode_setattr(inode, attrs);
+out:
+       kfree(args);
+       kfree(full_path);
+       FreeXid(xid);
+       return rc;
+}
+
+static int
+cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
+{
+       int xid;
+       struct inode *inode = direntry->d_inode;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+       char *full_path = NULL;
+       int rc = -EACCES;
+       __u32 dosattr = 0;
+       __u64 mode = NO_CHANGE_64;
 
        xid = GetXid();
 
        cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
                 direntry->d_name.name, attrs->ia_valid));
 
-       cifs_sb = CIFS_SB(inode->i_sb);
-       pTcon = cifs_sb->tcon;
-
        if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
                /* check if we have permission to change attrs */
                rc = inode_change_ok(inode, attrs);
@@ -1528,7 +1741,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                FreeXid(xid);
                return -ENOMEM;
        }
-       cifsInode = CIFS_I(inode);
 
        if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
                /*
@@ -1559,21 +1771,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
         * CIFSACL support + proper Windows to Unix idmapping, we may be
         * able to support this in the future.
         */
-       if (!pTcon->unix_ext &&
-           !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
                attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
-       } else {
-               if (attrs->ia_valid & ATTR_UID) {
-                       cFYI(1, ("UID changed to %d", attrs->ia_uid));
-                       uid = attrs->ia_uid;
-               }
-               if (attrs->ia_valid & ATTR_GID) {
-                       cFYI(1, ("GID changed to %d", attrs->ia_gid));
-                       gid = attrs->ia_gid;
-               }
-       }
-
-       time_buf.Attributes = 0;
 
        /* skip mode change if it's just for clearing setuid/setgid */
        if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
@@ -1584,13 +1783,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                mode = attrs->ia_mode;
        }
 
-       if ((pTcon->unix_ext)
-           && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
-               rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
-                                        0 /* dev_t */, cifs_sb->local_nls,
-                                        cifs_sb->mnt_cifs_flags &
-                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
-       else if (attrs->ia_valid & ATTR_MODE) {
+       if (attrs->ia_valid & ATTR_MODE) {
                rc = 0;
 #ifdef CONFIG_CIFS_EXPERIMENTAL
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
@@ -1599,24 +1792,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 #endif
                if (((mode & S_IWUGO) == 0) &&
                    (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
-                       set_dosattr = true;
-                       time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs |
-                                                         ATTR_READONLY);
+
+                       dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
+
                        /* fix up mode if we're not using dynperm */
                        if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
                                attrs->ia_mode = inode->i_mode & ~S_IWUGO;
                } else if ((mode & S_IWUGO) &&
                           (cifsInode->cifsAttrs & ATTR_READONLY)) {
-                       /* If file is readonly on server, we would
-                       not be able to write to it - so if any write
-                       bit is enabled for user or group or other we
-                       need to at least try to remove r/o dos attr */
-                       set_dosattr = true;
-                       time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
-                                           (~ATTR_READONLY));
-                       /* Windows ignores set to zero */
-                       if (time_buf.Attributes == 0)
-                               time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
+
+                       dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
+                       /* Attributes of 0 are ignored */
+                       if (dosattr == 0)
+                               dosattr |= ATTR_NORMAL;
 
                        /* reset local inode permissions to normal */
                        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
@@ -1634,82 +1822,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
                }
        }
 
-       if (attrs->ia_valid & ATTR_ATIME) {
-               set_time = true;
-               time_buf.LastAccessTime =
-                   cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
-       } else
-               time_buf.LastAccessTime = 0;
-
-       if (attrs->ia_valid & ATTR_MTIME) {
-               set_time = true;
-               time_buf.LastWriteTime =
-                   cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
-       } else
-               time_buf.LastWriteTime = 0;
-       /* Do not set ctime explicitly unless other time
-          stamps are changed explicitly (i.e. by utime()
-          since we would then have a mix of client and
-          server times */
+       if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
+           ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
+               rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
+               /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
 
-       if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
-               set_time = true;
-               /* Although Samba throws this field away
-               it may be useful to Windows - but we do
-               not want to set ctime unless some other
-               timestamp is changing */
-               cFYI(1, ("CIFS - CTIME changed"));
-               time_buf.ChangeTime =
-                   cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
-       } else
-               time_buf.ChangeTime = 0;
-
-       if (set_time || set_dosattr) {
-               time_buf.CreationTime = 0;      /* do not change */
-               /* In the future we should experiment - try setting timestamps
-                  via Handle (SetFileInfo) instead of by path */
-               if (!(pTcon->ses->flags & CIFS_SES_NT4))
-                       rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
-                                            cifs_sb->local_nls,
-                                            cifs_sb->mnt_cifs_flags &
-                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
-               else
-                       rc = -EOPNOTSUPP;
-
-               if (rc == -EOPNOTSUPP) {
-                       int oplock = 0;
-                       __u16 netfid;
-
-                       cFYI(1, ("calling SetFileInfo since SetPathInfo for "
-                                "times not supported by this server"));
-                       /* BB we could scan to see if we already have it open
-                          and pass in pid of opener to function */
-                       rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
-                                        SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
-                                        CREATE_NOT_DIR, &netfid, &oplock,
-                                        NULL, cifs_sb->local_nls,
-                                        cifs_sb->mnt_cifs_flags &
-                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
-                       if (rc == 0) {
-                               rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
-                                                        netfid);
-                               CIFSSMBClose(xid, pTcon, netfid);
-                       } else {
-                       /* BB For even older servers we could convert time_buf
-                          into old DOS style which uses two second
-                          granularity */
-
-                       /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
-                                       &time_buf, cifs_sb->local_nls); */
-                       }
-               }
                /* Even if error on time set, no sense failing the call if
                the server would set the time to a reasonable value anyway,
                and this check ensures that we are not being called from
                sys_utimes in which case we ought to fail the call back to
                the user when the server rejects the call */
                if ((rc) && (attrs->ia_valid &
-                        (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
+                               (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
                        rc = 0;
        }
 
@@ -1723,6 +1847,21 @@ cifs_setattr_exit:
        return rc;
 }
 
+int
+cifs_setattr(struct dentry *direntry, struct iattr *attrs)
+{
+       struct inode *inode = direntry->d_inode;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct cifsTconInfo *pTcon = cifs_sb->tcon;
+
+       if (pTcon->unix_ext)
+               return cifs_setattr_unix(direntry, attrs);
+
+       return cifs_setattr_nounix(direntry, attrs);
+
+       /* BB: add cifs_setattr_legacy for really old servers */
+}
+
 #if 0
 void cifs_delete_inode(struct inode *inode)
 {
index 000ac50..e286db9 100644 (file)
@@ -265,6 +265,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
        cFYI(1, ("Sending smb:  total_len %d", total_len));
        dump_smb(smb_buffer, len);
 
+       i = 0;
        while (total_len) {
                rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
                                    n_vec - first_vec, total_len);