aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/CHANGES8
-rw-r--r--fs/cifs/asn1.c258
-rw-r--r--fs/cifs/cifs_debug.c53
-rw-r--r--fs/cifs/cifs_spnego.c18
-rw-r--r--fs/cifs/cifsfs.c71
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifspdu.h2
-rw-r--r--fs/cifs/cifsproto.h24
-rw-r--r--fs/cifs/cifssmb.c46
-rw-r--r--fs/cifs/connect.c173
-rw-r--r--fs/cifs/dir.c67
-rw-r--r--fs/cifs/file.c19
-rw-r--r--fs/cifs/inode.c419
-rw-r--r--fs/cifs/transport.c1
14 files changed, 652 insertions, 509 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 1f3465201fdf..f5d0083e09fa 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,11 @@
1Version 1.54
2------------
3Fix premature write failure on congested networks (we would give up
4on EAGAIN from the socket too quickly on large writes).
5Cifs_mkdir and cifs_create now respect the setgid bit on parent dir.
6Fix endian problems in acl (mode from/to cifs acl) on bigendian
7architectures.
8
1Version 1.53 9Version 1.53
2------------ 10------------
3DFS support added (Microsoft Distributed File System client support needed 11DFS support added (Microsoft Distributed File System client support needed
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c
index 6bb440b257b0..5fabd2caf93c 100644
--- a/fs/cifs/asn1.c
+++ b/fs/cifs/asn1.c
@@ -483,6 +483,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
483 483
484 asn1_open(&ctx, security_blob, length); 484 asn1_open(&ctx, security_blob, length);
485 485
486 /* GSSAPI header */
486 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { 487 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
487 cFYI(1, ("Error decoding negTokenInit header")); 488 cFYI(1, ("Error decoding negTokenInit header"));
488 return 0; 489 return 0;
@@ -490,153 +491,142 @@ decode_negTokenInit(unsigned char *security_blob, int length,
490 || (tag != ASN1_EOC)) { 491 || (tag != ASN1_EOC)) {
491 cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag)); 492 cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag));
492 return 0; 493 return 0;
493 } else { 494 }
494 /* remember to free obj->oid */
495 rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
496 if (rc) {
497 if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
498 rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
499 if (rc) {
500 rc = compare_oid(oid, oidlen,
501 SPNEGO_OID,
502 SPNEGO_OID_LEN);
503 kfree(oid);
504 }
505 } else
506 rc = 0;
507 }
508 495
509 if (!rc) { 496 /* Check for SPNEGO OID -- remember to free obj->oid */
510 cFYI(1, ("Error decoding negTokenInit header")); 497 rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
511 return 0; 498 if (rc) {
512 } 499 if ((tag == ASN1_OJI) && (con == ASN1_PRI) &&
500 (cls == ASN1_UNI)) {
501 rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
502 if (rc) {
503 rc = compare_oid(oid, oidlen, SPNEGO_OID,
504 SPNEGO_OID_LEN);
505 kfree(oid);
506 }
507 } else
508 rc = 0;
509 }
513 510
514 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { 511 /* SPNEGO OID not present or garbled -- bail out */
515 cFYI(1, ("Error decoding negTokenInit")); 512 if (!rc) {
516 return 0; 513 cFYI(1, ("Error decoding negTokenInit header"));
517 } else if ((cls != ASN1_CTX) || (con != ASN1_CON) 514 return 0;
518 || (tag != ASN1_EOC)) { 515 }
519 cFYI(1,
520 ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
521 cls, con, tag, end, *end));
522 return 0;
523 }
524 516
525 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { 517 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
526 cFYI(1, ("Error decoding negTokenInit")); 518 cFYI(1, ("Error decoding negTokenInit"));
527 return 0; 519 return 0;
528 } else if ((cls != ASN1_UNI) || (con != ASN1_CON) 520 } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
529 || (tag != ASN1_SEQ)) { 521 || (tag != ASN1_EOC)) {
530 cFYI(1, 522 cFYI(1,
531 ("cls = %d con = %d tag = %d end = %p (%d) exit 1", 523 ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
532 cls, con, tag, end, *end)); 524 cls, con, tag, end, *end));
533 return 0; 525 return 0;
534 } 526 }
535 527
536 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { 528 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
537 cFYI(1, ("Error decoding 2nd part of negTokenInit")); 529 cFYI(1, ("Error decoding negTokenInit"));
538 return 0; 530 return 0;
539 } else if ((cls != ASN1_CTX) || (con != ASN1_CON) 531 } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
540 || (tag != ASN1_EOC)) { 532 || (tag != ASN1_SEQ)) {
541 cFYI(1, 533 cFYI(1,
542 ("cls = %d con = %d tag = %d end = %p (%d) exit 0", 534 ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
543 cls, con, tag, end, *end)); 535 cls, con, tag, end, *end));
544 return 0; 536 return 0;
545 } 537 }
546 538
547 if (asn1_header_decode 539 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
548 (&ctx, &sequence_end, &cls, &con, &tag) == 0) { 540 cFYI(1, ("Error decoding 2nd part of negTokenInit"));
549 cFYI(1, ("Error decoding 2nd part of negTokenInit")); 541 return 0;
550 return 0; 542 } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
551 } else if ((cls != ASN1_UNI) || (con != ASN1_CON) 543 || (tag != ASN1_EOC)) {
552 || (tag != ASN1_SEQ)) { 544 cFYI(1,
553 cFYI(1, 545 ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
554 ("cls = %d con = %d tag = %d end = %p (%d) exit 1", 546 cls, con, tag, end, *end));
555 cls, con, tag, end, *end)); 547 return 0;
556 return 0; 548 }
557 }
558 549
559 while (!asn1_eoc_decode(&ctx, sequence_end)) { 550 if (asn1_header_decode
560 rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); 551 (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
561 if (!rc) { 552 cFYI(1, ("Error decoding 2nd part of negTokenInit"));
562 cFYI(1, 553 return 0;
563 ("Error decoding negTokenInit hdr exit2")); 554 } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
564 return 0; 555 || (tag != ASN1_SEQ)) {
565 } 556 cFYI(1,
566 if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { 557 ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
567 if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) { 558 cls, con, tag, end, *end));
568 559 return 0;
569 cFYI(1, 560 }
570 ("OID len = %d oid = 0x%lx 0x%lx "
571 "0x%lx 0x%lx",
572 oidlen, *oid, *(oid + 1),
573 *(oid + 2), *(oid + 3)));
574
575 if (compare_oid(oid, oidlen,
576 MSKRB5_OID,
577 MSKRB5_OID_LEN))
578 use_kerberos = true;
579 else if (compare_oid(oid, oidlen,
580 KRB5_OID,
581 KRB5_OID_LEN))
582 use_kerberos = true;
583 else if (compare_oid(oid, oidlen,
584 NTLMSSP_OID,
585 NTLMSSP_OID_LEN))
586 use_ntlmssp = true;
587
588 kfree(oid);
589 }
590 } else {
591 cFYI(1, ("Should be an oid what is going on?"));
592 }
593 }
594 561
595 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { 562 while (!asn1_eoc_decode(&ctx, sequence_end)) {
596 cFYI(1, 563 rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
597 ("Error decoding last part negTokenInit exit3")); 564 if (!rc) {
598 return 0;
599 } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
600 /* tag = 3 indicating mechListMIC */
601 cFYI(1, 565 cFYI(1,
602 ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)", 566 ("Error decoding negTokenInit hdr exit2"));
603 cls, con, tag, end, *end));
604 return 0; 567 return 0;
605 } 568 }
606 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { 569 if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
607 cFYI(1, 570 if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) {
608 ("Error decoding last part negTokenInit exit5")); 571
609 return 0; 572 cFYI(1, ("OID len = %d oid = 0x%lx 0x%lx "
610 } else if ((cls != ASN1_UNI) || (con != ASN1_CON) 573 "0x%lx 0x%lx", oidlen, *oid,
611 || (tag != ASN1_SEQ)) { 574 *(oid + 1), *(oid + 2), *(oid + 3)));
612 cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)", 575
613 cls, con, tag, end, *end)); 576 if (compare_oid(oid, oidlen, MSKRB5_OID,
577 MSKRB5_OID_LEN))
578 use_kerberos = true;
579 else if (compare_oid(oid, oidlen, KRB5_OID,
580 KRB5_OID_LEN))
581 use_kerberos = true;
582 else if (compare_oid(oid, oidlen, NTLMSSP_OID,
583 NTLMSSP_OID_LEN))
584 use_ntlmssp = true;
585
586 kfree(oid);
587 }
588 } else {
589 cFYI(1, ("Should be an oid what is going on?"));
614 } 590 }
591 }
615 592
616 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { 593 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
617 cFYI(1, 594 cFYI(1, ("Error decoding last part negTokenInit exit3"));
618 ("Error decoding last part negTokenInit exit 7")); 595 return 0;
619 return 0; 596 } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
620 } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { 597 /* tag = 3 indicating mechListMIC */
621 cFYI(1, 598 cFYI(1, ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)",
622 ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)", 599 cls, con, tag, end, *end));
623 cls, con, tag, end, *end)); 600 return 0;
624 return 0; 601 }
625 } 602 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
626 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { 603 cFYI(1, ("Error decoding last part negTokenInit exit5"));
627 cFYI(1, 604 return 0;
628 ("Error decoding last part negTokenInit exit9")); 605 } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
629 return 0; 606 || (tag != ASN1_SEQ)) {
630 } else if ((cls != ASN1_UNI) || (con != ASN1_PRI) 607 cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)",
631 || (tag != ASN1_GENSTR)) { 608 cls, con, tag, end, *end));
632 cFYI(1, 609 }
633 ("Exit10 cls = %d con = %d tag = %d end = %p (%d)", 610
634 cls, con, tag, end, *end)); 611 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
635 return 0; 612 cFYI(1, ("Error decoding last part negTokenInit exit 7"));
636 } 613 return 0;
637 cFYI(1, ("Need to call asn1_octets_decode() function for %s", 614 } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
638 ctx.pointer)); /* is this UTF-8 or ASCII? */ 615 cFYI(1, ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)",
616 cls, con, tag, end, *end));
617 return 0;
618 }
619 if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
620 cFYI(1, ("Error decoding last part negTokenInit exit9"));
621 return 0;
622 } else if ((cls != ASN1_UNI) || (con != ASN1_PRI)
623 || (tag != ASN1_GENSTR)) {
624 cFYI(1, ("Exit10 cls = %d con = %d tag = %d end = %p (%d)",
625 cls, con, tag, end, *end));
626 return 0;
639 } 627 }
628 cFYI(1, ("Need to call asn1_octets_decode() function for %s",
629 ctx.pointer)); /* is this UTF-8 or ASCII? */
640 630
641 if (use_kerberos) 631 if (use_kerberos)
642 *secType = Kerberos; 632 *secType = Kerberos;
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 688a2d42153f..69a12aae91d3 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -79,27 +79,25 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
79 spin_lock(&GlobalMid_Lock); 79 spin_lock(&GlobalMid_Lock);
80 list_for_each(tmp, &server->pending_mid_q) { 80 list_for_each(tmp, &server->pending_mid_q) {
81 mid_entry = list_entry(tmp, struct mid_q_entry, qhead); 81 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
82 if (mid_entry) { 82 cERROR(1, ("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
83 cERROR(1, ("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", 83 mid_entry->midState,
84 mid_entry->midState, 84 (int)mid_entry->command,
85 (int)mid_entry->command, 85 mid_entry->pid,
86 mid_entry->pid, 86 mid_entry->tsk,
87 mid_entry->tsk, 87 mid_entry->mid));
88 mid_entry->mid));
89#ifdef CONFIG_CIFS_STATS2 88#ifdef CONFIG_CIFS_STATS2
90 cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld", 89 cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld",
91 mid_entry->largeBuf, 90 mid_entry->largeBuf,
92 mid_entry->resp_buf, 91 mid_entry->resp_buf,
93 mid_entry->when_received, 92 mid_entry->when_received,
94 jiffies)); 93 jiffies));
95#endif /* STATS2 */ 94#endif /* STATS2 */
96 cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp, 95 cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
97 mid_entry->multiEnd)); 96 mid_entry->multiEnd));
98 if (mid_entry->resp_buf) { 97 if (mid_entry->resp_buf) {
99 cifs_dump_detail(mid_entry->resp_buf); 98 cifs_dump_detail(mid_entry->resp_buf);
100 cifs_dump_mem("existing buf: ", 99 cifs_dump_mem("existing buf: ",
101 mid_entry->resp_buf, 62); 100 mid_entry->resp_buf, 62);
102 }
103 } 101 }
104 } 102 }
105 spin_unlock(&GlobalMid_Lock); 103 spin_unlock(&GlobalMid_Lock);
@@ -163,16 +161,13 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
163 mid_entry = list_entry(tmp1, struct 161 mid_entry = list_entry(tmp1, struct
164 mid_q_entry, 162 mid_q_entry,
165 qhead); 163 qhead);
166 if (mid_entry) { 164 seq_printf(m, "State: %d com: %d pid:"
167 seq_printf(m, 165 " %d tsk: %p mid %d\n",
168 "State: %d com: %d pid:" 166 mid_entry->midState,
169 " %d tsk: %p mid %d\n", 167 (int)mid_entry->command,
170 mid_entry->midState, 168 mid_entry->pid,
171 (int)mid_entry->command, 169 mid_entry->tsk,
172 mid_entry->pid, 170 mid_entry->mid);
173 mid_entry->tsk,
174 mid_entry->mid);
175 }
176 } 171 }
177 spin_unlock(&GlobalMid_Lock); 172 spin_unlock(&GlobalMid_Lock);
178 } 173 }
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
index 7013aaff6aed..2434ab0e8791 100644
--- a/fs/cifs/cifs_spnego.c
+++ b/fs/cifs/cifs_spnego.c
@@ -66,8 +66,8 @@ struct key_type cifs_spnego_key_type = {
66 .describe = user_describe, 66 .describe = user_describe,
67}; 67};
68 68
69#define MAX_VER_STR_LEN 9 /* length of longest version string e.g. 69#define MAX_VER_STR_LEN 8 /* length of longest version string e.g.
70 strlen(";ver=0xFF") */ 70 strlen("ver=0xFF") */
71#define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg 71#define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg
72 in future could have strlen(";sec=ntlmsspi") */ 72 in future could have strlen(";sec=ntlmsspi") */
73#define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ 73#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)
81 struct key *spnego_key; 81 struct key *spnego_key;
82 const char *hostname = server->hostname; 82 const char *hostname = server->hostname;
83 83
84 /* BB: come up with better scheme for determining length */ 84 /* length of fields (with semicolons): ver=0xyz ip4=ipaddress
85 /* length of fields (with semicolons): ver=0xyz ipv4= ipaddress host= 85 host=hostname sec=mechanism uid=0xFF user=username */
86 hostname sec=mechanism uid=0x uid */ 86 desc_len = MAX_VER_STR_LEN +
87 desc_len = MAX_VER_STR_LEN + 5 + MAX_IPV6_ADDR_LEN + 1 + 6 + 87 6 /* len of "host=" */ + strlen(hostname) +
88 strlen(hostname) + MAX_MECH_STR_LEN + 8 + (sizeof(uid_t) * 2); 88 5 /* len of ";ipv4=" */ + MAX_IPV6_ADDR_LEN +
89 MAX_MECH_STR_LEN +
90 7 /* len of ";uid=0x" */ + (sizeof(uid_t) * 2) +
91 6 /* len of ";user=" */ + strlen(sesInfo->userName) + 1;
92
89 spnego_key = ERR_PTR(-ENOMEM); 93 spnego_key = ERR_PTR(-ENOMEM);
90 description = kzalloc(desc_len, GFP_KERNEL); 94 description = kzalloc(desc_len, GFP_KERNEL);
91 if (description == NULL) 95 if (description == NULL)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 1ec7076f7b24..e8da4ee761b5 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -930,36 +930,34 @@ static int cifs_oplock_thread(void *dummyarg)
930 schedule_timeout(39*HZ); 930 schedule_timeout(39*HZ);
931 } else { 931 } else {
932 oplock_item = list_entry(GlobalOplock_Q.next, 932 oplock_item = list_entry(GlobalOplock_Q.next,
933 struct oplock_q_entry, qhead); 933 struct oplock_q_entry, qhead);
934 if (oplock_item) { 934 cFYI(1, ("found oplock item to write out"));
935 cFYI(1, ("found oplock item to write out")); 935 pTcon = oplock_item->tcon;
936 pTcon = oplock_item->tcon; 936 inode = oplock_item->pinode;
937 inode = oplock_item->pinode; 937 netfid = oplock_item->netfid;
938 netfid = oplock_item->netfid; 938 spin_unlock(&GlobalMid_Lock);
939 spin_unlock(&GlobalMid_Lock); 939 DeleteOplockQEntry(oplock_item);
940 DeleteOplockQEntry(oplock_item); 940 /* can not grab inode sem here since it would
941 /* can not grab inode sem here since it would
942 deadlock when oplock received on delete 941 deadlock when oplock received on delete
943 since vfs_unlink holds the i_mutex across 942 since vfs_unlink holds the i_mutex across
944 the call */ 943 the call */
945 /* mutex_lock(&inode->i_mutex);*/ 944 /* mutex_lock(&inode->i_mutex);*/
946 if (S_ISREG(inode->i_mode)) { 945 if (S_ISREG(inode->i_mode)) {
947 rc = 946 rc = filemap_fdatawrite(inode->i_mapping);
948 filemap_fdatawrite(inode->i_mapping); 947 if (CIFS_I(inode)->clientCanCacheRead == 0) {
949 if (CIFS_I(inode)->clientCanCacheRead 948 waitrc = filemap_fdatawait(
950 == 0) { 949 inode->i_mapping);
951 waitrc = filemap_fdatawait(inode->i_mapping); 950 invalidate_remote_inode(inode);
952 invalidate_remote_inode(inode); 951 }
953 } 952 if (rc == 0)
954 if (rc == 0) 953 rc = waitrc;
955 rc = waitrc; 954 } else
956 } else 955 rc = 0;
957 rc = 0; 956 /* mutex_unlock(&inode->i_mutex);*/
958 /* mutex_unlock(&inode->i_mutex);*/ 957 if (rc)
959 if (rc) 958 CIFS_I(inode)->write_behind_rc = rc;
960 CIFS_I(inode)->write_behind_rc = rc; 959 cFYI(1, ("Oplock flush inode %p rc %d",
961 cFYI(1, ("Oplock flush inode %p rc %d", 960 inode, rc));
962 inode, rc));
963 961
964 /* releasing stale oplock after recent reconnect 962 /* releasing stale oplock after recent reconnect
965 of smb session using a now incorrect file 963 of smb session using a now incorrect file
@@ -967,15 +965,13 @@ static int cifs_oplock_thread(void *dummyarg)
967 not bother sending an oplock release if session 965 not bother sending an oplock release if session
968 to server still is disconnected since oplock 966 to server still is disconnected since oplock
969 already released by the server in that case */ 967 already released by the server in that case */
970 if (pTcon->tidStatus != CifsNeedReconnect) { 968 if (pTcon->tidStatus != CifsNeedReconnect) {
971 rc = CIFSSMBLock(0, pTcon, netfid, 969 rc = CIFSSMBLock(0, pTcon, netfid,
972 0 /* len */ , 0 /* offset */, 0, 970 0 /* len */ , 0 /* offset */, 0,
973 0, LOCKING_ANDX_OPLOCK_RELEASE, 971 0, LOCKING_ANDX_OPLOCK_RELEASE,
974 false /* wait flag */); 972 false /* wait flag */);
975 cFYI(1, ("Oplock release rc = %d", rc)); 973 cFYI(1, ("Oplock release rc = %d", rc));
976 } 974 }
977 } else
978 spin_unlock(&GlobalMid_Lock);
979 set_current_state(TASK_INTERRUPTIBLE); 975 set_current_state(TASK_INTERRUPTIBLE);
980 schedule_timeout(1); /* yield in case q were corrupt */ 976 schedule_timeout(1); /* yield in case q were corrupt */
981 } 977 }
@@ -1001,8 +997,7 @@ static int cifs_dnotify_thread(void *dummyarg)
1001 list_for_each(tmp, &GlobalSMBSessionList) { 997 list_for_each(tmp, &GlobalSMBSessionList) {
1002 ses = list_entry(tmp, struct cifsSesInfo, 998 ses = list_entry(tmp, struct cifsSesInfo,
1003 cifsSessionList); 999 cifsSessionList);
1004 if (ses && ses->server && 1000 if (ses->server && atomic_read(&ses->server->inFlight))
1005 atomic_read(&ses->server->inFlight))
1006 wake_up_all(&ses->server->response_q); 1001 wake_up_all(&ses->server->response_q);
1007 } 1002 }
1008 read_unlock(&GlobalSMBSeslock); 1003 read_unlock(&GlobalSMBSeslock);
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 25a6cbd15529..135c965c4137 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
101extern const struct export_operations cifs_export_ops; 101extern const struct export_operations cifs_export_ops;
102#endif /* EXPERIMENTAL */ 102#endif /* EXPERIMENTAL */
103 103
104#define CIFS_VERSION "1.53" 104#define CIFS_VERSION "1.54"
105#endif /* _CIFSFS_H */ 105#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 409abce12732..d2a073edd1b8 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -262,7 +262,7 @@
262 */ 262 */
263#define CIFS_NO_HANDLE 0xFFFF 263#define CIFS_NO_HANDLE 0xFFFF
264 264
265#define NO_CHANGE_64 cpu_to_le64(0xFFFFFFFFFFFFFFFFULL) 265#define NO_CHANGE_64 0xFFFFFFFFFFFFFFFFULL
266#define NO_CHANGE_32 0xFFFFFFFFUL 266#define NO_CHANGE_32 0xFFFFFFFFUL
267 267
268/* IPC$ in ASCII */ 268/* IPC$ in ASCII */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b9f5e935f821..a729d083e6f4 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -172,12 +172,13 @@ extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon);
172extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, 172extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
173 struct kstatfs *FSData); 173 struct kstatfs *FSData);
174 174
175extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, 175extern int CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
176 const char *fileName, const FILE_BASIC_INFO *data, 176 const char *fileName, const FILE_BASIC_INFO *data,
177 const struct nls_table *nls_codepage, 177 const struct nls_table *nls_codepage,
178 int remap_special_chars); 178 int remap_special_chars);
179extern int CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, 179extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
180 const FILE_BASIC_INFO *data, __u16 fid); 180 const FILE_BASIC_INFO *data, __u16 fid,
181 __u32 pid_of_opener);
181#if 0 182#if 0
182extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, 183extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon,
183 char *fileName, __u16 dos_attributes, 184 char *fileName, __u16 dos_attributes,
@@ -191,9 +192,20 @@ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
191extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, 192extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
192 __u64 size, __u16 fileHandle, __u32 opener_pid, 193 __u64 size, __u16 fileHandle, __u32 opener_pid,
193 bool AllocSizeFlag); 194 bool AllocSizeFlag);
194extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon, 195
195 char *full_path, __u64 mode, __u64 uid, 196struct cifs_unix_set_info_args {
196 __u64 gid, dev_t dev, 197 __u64 ctime;
198 __u64 atime;
199 __u64 mtime;
200 __u64 mode;
201 __u64 uid;
202 __u64 gid;
203 dev_t device;
204};
205
206extern int CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *pTcon,
207 char *fileName,
208 const struct cifs_unix_set_info_args *args,
197 const struct nls_table *nls_codepage, 209 const struct nls_table *nls_codepage,
198 int remap_special_chars); 210 int remap_special_chars);
199 211
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index c621ffa2ca90..994de7c90474 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -128,8 +128,7 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
128 write_lock(&GlobalSMBSeslock); 128 write_lock(&GlobalSMBSeslock);
129 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { 129 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
130 open_file = list_entry(tmp, struct cifsFileInfo, tlist); 130 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
131 if (open_file) 131 open_file->invalidHandle = true;
132 open_file->invalidHandle = true;
133 } 132 }
134 write_unlock(&GlobalSMBSeslock); 133 write_unlock(&GlobalSMBSeslock);
135 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted 134 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
@@ -4816,8 +4815,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4816 time and resort to the original setpathinfo level which takes the ancient 4815 time and resort to the original setpathinfo level which takes the ancient
4817 DOS time format with 2 second granularity */ 4816 DOS time format with 2 second granularity */
4818int 4817int
4819CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, 4818CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4820 const FILE_BASIC_INFO *data, __u16 fid) 4819 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
4821{ 4820{
4822 struct smb_com_transaction2_sfi_req *pSMB = NULL; 4821 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4823 char *data_offset; 4822 char *data_offset;
@@ -4830,11 +4829,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4830 if (rc) 4829 if (rc)
4831 return rc; 4830 return rc;
4832 4831
4833 /* At this point there is no need to override the current pid 4832 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4834 with the pid of the opener, but that could change if we someday 4833 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4835 use an existing handle (rather than opening one on the fly) */
4836 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4837 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4838 4834
4839 params = 6; 4835 params = 6;
4840 pSMB->MaxSetupCount = 0; 4836 pSMB->MaxSetupCount = 0;
@@ -4882,9 +4878,9 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4882 4878
4883 4879
4884int 4880int
4885CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName, 4881CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4886 const FILE_BASIC_INFO *data, 4882 const char *fileName, const FILE_BASIC_INFO *data,
4887 const struct nls_table *nls_codepage, int remap) 4883 const struct nls_table *nls_codepage, int remap)
4888{ 4884{
4889 TRANSACTION2_SPI_REQ *pSMB = NULL; 4885 TRANSACTION2_SPI_REQ *pSMB = NULL;
4890 TRANSACTION2_SPI_RSP *pSMBr = NULL; 4886 TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -5013,10 +5009,9 @@ SetAttrLgcyRetry:
5013#endif /* temporarily unneeded SetAttr legacy function */ 5009#endif /* temporarily unneeded SetAttr legacy function */
5014 5010
5015int 5011int
5016CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, 5012CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5017 char *fileName, __u64 mode, __u64 uid, __u64 gid, 5013 const struct cifs_unix_set_info_args *args,
5018 dev_t device, const struct nls_table *nls_codepage, 5014 const struct nls_table *nls_codepage, int remap)
5019 int remap)
5020{ 5015{
5021 TRANSACTION2_SPI_REQ *pSMB = NULL; 5016 TRANSACTION2_SPI_REQ *pSMB = NULL;
5022 TRANSACTION2_SPI_RSP *pSMBr = NULL; 5017 TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -5025,6 +5020,7 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
5025 int bytes_returned = 0; 5020 int bytes_returned = 0;
5026 FILE_UNIX_BASIC_INFO *data_offset; 5021 FILE_UNIX_BASIC_INFO *data_offset;
5027 __u16 params, param_offset, offset, count, byte_count; 5022 __u16 params, param_offset, offset, count, byte_count;
5023 __u64 mode = args->mode;
5028 5024
5029 cFYI(1, ("In SetUID/GID/Mode")); 5025 cFYI(1, ("In SetUID/GID/Mode"));
5030setPermsRetry: 5026setPermsRetry:
@@ -5080,16 +5076,16 @@ setPermsRetry:
5080 set file size and do not want to truncate file size to zero 5076 set file size and do not want to truncate file size to zero
5081 accidently as happened on one Samba server beta by putting 5077 accidently as happened on one Samba server beta by putting
5082 zero instead of -1 here */ 5078 zero instead of -1 here */
5083 data_offset->EndOfFile = NO_CHANGE_64; 5079 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5084 data_offset->NumOfBytes = NO_CHANGE_64; 5080 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5085 data_offset->LastStatusChange = NO_CHANGE_64; 5081 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5086 data_offset->LastAccessTime = NO_CHANGE_64; 5082 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5087 data_offset->LastModificationTime = NO_CHANGE_64; 5083 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5088 data_offset->Uid = cpu_to_le64(uid); 5084 data_offset->Uid = cpu_to_le64(args->uid);
5089 data_offset->Gid = cpu_to_le64(gid); 5085 data_offset->Gid = cpu_to_le64(args->gid);
5090 /* better to leave device as zero when it is */ 5086 /* better to leave device as zero when it is */
5091 data_offset->DevMajor = cpu_to_le64(MAJOR(device)); 5087 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5092 data_offset->DevMinor = cpu_to_le64(MINOR(device)); 5088 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5093 data_offset->Permissions = cpu_to_le64(mode); 5089 data_offset->Permissions = cpu_to_le64(mode);
5094 5090
5095 if (S_ISREG(mode)) 5091 if (S_ISREG(mode))
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index b51d5777cde6..0711db65afe8 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -151,7 +151,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
151 } 151 }
152 list_for_each(tmp, &GlobalTreeConnectionList) { 152 list_for_each(tmp, &GlobalTreeConnectionList) {
153 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); 153 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
154 if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) 154 if ((tcon->ses) && (tcon->ses->server == server))
155 tcon->tidStatus = CifsNeedReconnect; 155 tcon->tidStatus = CifsNeedReconnect;
156 } 156 }
157 read_unlock(&GlobalSMBSeslock); 157 read_unlock(&GlobalSMBSeslock);
@@ -173,14 +173,12 @@ cifs_reconnect(struct TCP_Server_Info *server)
173 mid_entry = list_entry(tmp, struct 173 mid_entry = list_entry(tmp, struct
174 mid_q_entry, 174 mid_q_entry,
175 qhead); 175 qhead);
176 if (mid_entry) { 176 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
177 if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
178 /* Mark other intransit requests as needing 177 /* Mark other intransit requests as needing
179 retry so we do not immediately mark the 178 retry so we do not immediately mark the
180 session bad again (ie after we reconnect 179 session bad again (ie after we reconnect
181 below) as they timeout too */ 180 below) as they timeout too */
182 mid_entry->midState = MID_RETRY_NEEDED; 181 mid_entry->midState = MID_RETRY_NEEDED;
183 }
184 } 182 }
185 } 183 }
186 spin_unlock(&GlobalMid_Lock); 184 spin_unlock(&GlobalMid_Lock);
@@ -351,11 +349,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
351 349
352 current->flags |= PF_MEMALLOC; 350 current->flags |= PF_MEMALLOC;
353 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current))); 351 cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
354 write_lock(&GlobalSMBSeslock); 352
355 atomic_inc(&tcpSesAllocCount); 353 length = atomic_inc_return(&tcpSesAllocCount);
356 length = tcpSesAllocCount.counter; 354 if (length > 1)
357 write_unlock(&GlobalSMBSeslock);
358 if (length > 1)
359 mempool_resize(cifs_req_poolp, length + cifs_min_rcv, 355 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
360 GFP_KERNEL); 356 GFP_KERNEL);
361 357
@@ -745,14 +741,11 @@ multi_t2_fnd:
745 coming home not much else we can do but free the memory */ 741 coming home not much else we can do but free the memory */
746 } 742 }
747 743
748 write_lock(&GlobalSMBSeslock);
749 atomic_dec(&tcpSesAllocCount);
750 length = tcpSesAllocCount.counter;
751
752 /* last chance to mark ses pointers invalid 744 /* last chance to mark ses pointers invalid
753 if there are any pointing to this (e.g 745 if there are any pointing to this (e.g
754 if a crazy root user tried to kill cifsd 746 if a crazy root user tried to kill cifsd
755 kernel thread explicitly this might happen) */ 747 kernel thread explicitly this might happen) */
748 write_lock(&GlobalSMBSeslock);
756 list_for_each(tmp, &GlobalSMBSessionList) { 749 list_for_each(tmp, &GlobalSMBSessionList) {
757 ses = list_entry(tmp, struct cifsSesInfo, 750 ses = list_entry(tmp, struct cifsSesInfo,
758 cifsSessionList); 751 cifsSessionList);
@@ -763,6 +756,8 @@ multi_t2_fnd:
763 756
764 kfree(server->hostname); 757 kfree(server->hostname);
765 kfree(server); 758 kfree(server);
759
760 length = atomic_dec_return(&tcpSesAllocCount);
766 if (length > 0) 761 if (length > 0)
767 mempool_resize(cifs_req_poolp, length + cifs_min_rcv, 762 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
768 GFP_KERNEL); 763 GFP_KERNEL);
@@ -3623,97 +3618,91 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3623 } 3618 }
3624 first_time = 1; 3619 first_time = 1;
3625 } 3620 }
3626 if (!rc) { 3621
3627 pSesInfo->flags = 0; 3622 if (rc)
3628 pSesInfo->capabilities = pSesInfo->server->capabilities; 3623 goto ss_err_exit;
3629 if (linuxExtEnabled == 0) 3624
3630 pSesInfo->capabilities &= (~CAP_UNIX); 3625 pSesInfo->flags = 0;
3626 pSesInfo->capabilities = pSesInfo->server->capabilities;
3627 if (linuxExtEnabled == 0)
3628 pSesInfo->capabilities &= (~CAP_UNIX);
3631 /* pSesInfo->sequence_number = 0;*/ 3629 /* pSesInfo->sequence_number = 0;*/
3632 cFYI(1, 3630 cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
3633 ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", 3631 pSesInfo->server->secMode,
3634 pSesInfo->server->secMode, 3632 pSesInfo->server->capabilities,
3635 pSesInfo->server->capabilities, 3633 pSesInfo->server->timeAdj));
3636 pSesInfo->server->timeAdj)); 3634 if (experimEnabled < 2)
3637 if (experimEnabled < 2) 3635 rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
3638 rc = CIFS_SessSetup(xid, pSesInfo, 3636 else if (extended_security
3639 first_time, nls_info); 3637 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3640 else if (extended_security 3638 && (pSesInfo->server->secType == NTLMSSP)) {
3641 && (pSesInfo->capabilities 3639 rc = -EOPNOTSUPP;
3642 & CAP_EXTENDED_SECURITY) 3640 } else if (extended_security
3643 && (pSesInfo->server->secType == NTLMSSP)) { 3641 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
3644 rc = -EOPNOTSUPP; 3642 && (pSesInfo->server->secType == RawNTLMSSP)) {
3645 } else if (extended_security 3643 cFYI(1, ("NTLMSSP sesssetup"));
3646 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) 3644 rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag,
3647 && (pSesInfo->server->secType == RawNTLMSSP)) { 3645 nls_info);
3648 cFYI(1, ("NTLMSSP sesssetup")); 3646 if (!rc) {
3649 rc = CIFSNTLMSSPNegotiateSessSetup(xid, 3647 if (ntlmv2_flag) {
3650 pSesInfo, 3648 char *v2_response;
3651 &ntlmv2_flag, 3649 cFYI(1, ("more secure NTLM ver2 hash"));
3652 nls_info); 3650 if (CalcNTLMv2_partial_mac_key(pSesInfo,
3653 if (!rc) { 3651 nls_info)) {
3654 if (ntlmv2_flag) { 3652 rc = -ENOMEM;
3655 char *v2_response; 3653 goto ss_err_exit;
3656 cFYI(1, ("more secure NTLM ver2 hash")); 3654 } else
3657 if (CalcNTLMv2_partial_mac_key(pSesInfo, 3655 v2_response = kmalloc(16 + 64 /* blob*/,
3658 nls_info)) { 3656 GFP_KERNEL);
3659 rc = -ENOMEM; 3657 if (v2_response) {
3660 goto ss_err_exit; 3658 CalcNTLMv2_response(pSesInfo,
3661 } else 3659 v2_response);
3662 v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); 3660 /* if (first_time)
3663 if (v2_response) { 3661 cifs_calculate_ntlmv2_mac_key */
3664 CalcNTLMv2_response(pSesInfo, 3662 kfree(v2_response);
3665 v2_response);
3666 /* if (first_time)
3667 cifs_calculate_ntlmv2_mac_key(
3668 pSesInfo->server->mac_signing_key,
3669 response, ntlm_session_key,*/
3670 kfree(v2_response);
3671 /* BB Put dummy sig in SessSetup PDU? */ 3663 /* BB Put dummy sig in SessSetup PDU? */
3672 } else {
3673 rc = -ENOMEM;
3674 goto ss_err_exit;
3675 }
3676
3677 } else { 3664 } else {
3678 SMBNTencrypt(pSesInfo->password, 3665 rc = -ENOMEM;
3679 pSesInfo->server->cryptKey, 3666 goto ss_err_exit;
3680 ntlm_session_key);
3681
3682 if (first_time)
3683 cifs_calculate_mac_key(
3684 &pSesInfo->server->mac_signing_key,
3685 ntlm_session_key,
3686 pSesInfo->password);
3687 } 3667 }
3668
3669 } else {
3670 SMBNTencrypt(pSesInfo->password,
3671 pSesInfo->server->cryptKey,
3672 ntlm_session_key);
3673
3674 if (first_time)
3675 cifs_calculate_mac_key(
3676 &pSesInfo->server->mac_signing_key,
3677 ntlm_session_key,
3678 pSesInfo->password);
3679 }
3688 /* for better security the weaker lanman hash not sent 3680 /* for better security the weaker lanman hash not sent
3689 in AuthSessSetup so we no longer calculate it */ 3681 in AuthSessSetup so we no longer calculate it */
3690 3682
3691 rc = CIFSNTLMSSPAuthSessSetup(xid, 3683 rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo,
3692 pSesInfo, 3684 ntlm_session_key,
3693 ntlm_session_key, 3685 ntlmv2_flag,
3694 ntlmv2_flag, 3686 nls_info);
3695 nls_info); 3687 }
3696 } 3688 } else { /* old style NTLM 0.12 session setup */
3697 } else { /* old style NTLM 0.12 session setup */ 3689 SMBNTencrypt(pSesInfo->password, pSesInfo->server->cryptKey,
3698 SMBNTencrypt(pSesInfo->password, 3690 ntlm_session_key);
3699 pSesInfo->server->cryptKey,
3700 ntlm_session_key);
3701 3691
3702 if (first_time) 3692 if (first_time)
3703 cifs_calculate_mac_key( 3693 cifs_calculate_mac_key(
3704 &pSesInfo->server->mac_signing_key, 3694 &pSesInfo->server->mac_signing_key,
3705 ntlm_session_key, pSesInfo->password); 3695 ntlm_session_key, pSesInfo->password);
3706 3696
3707 rc = CIFSSessSetup(xid, pSesInfo, 3697 rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info);
3708 ntlm_session_key, nls_info); 3698 }
3709 } 3699 if (rc) {
3710 if (rc) { 3700 cERROR(1, ("Send error in SessSetup = %d", rc));
3711 cERROR(1, ("Send error in SessSetup = %d", rc)); 3701 } else {
3712 } else { 3702 cFYI(1, ("CIFS Session Established successfully"));
3713 cFYI(1, ("CIFS Session Established successfully"));
3714 pSesInfo->status = CifsGood; 3703 pSesInfo->status = CifsGood;
3715 }
3716 } 3704 }
3705
3717ss_err_exit: 3706ss_err_exit:
3718 return rc; 3707 return rc;
3719} 3708}
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index fb69c1fa85c9..e962e75e6f7b 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -226,23 +226,28 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
226 /* If Open reported that we actually created a file 226 /* If Open reported that we actually created a file
227 then we now have to set the mode if possible */ 227 then we now have to set the mode if possible */
228 if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { 228 if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
229 struct cifs_unix_set_info_args args = {
230 .mode = mode,
231 .ctime = NO_CHANGE_64,
232 .atime = NO_CHANGE_64,
233 .mtime = NO_CHANGE_64,
234 .device = 0,
235 };
236
229 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 237 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
230 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, 238 args.uid = (__u64) current->fsuid;
231 (__u64)current->fsuid, 239 if (inode->i_mode & S_ISGID)
232 (__u64)current->fsgid, 240 args.gid = (__u64) inode->i_gid;
233 0 /* dev */, 241 else
234 cifs_sb->local_nls, 242 args.gid = (__u64) current->fsgid;
235 cifs_sb->mnt_cifs_flags &
236 CIFS_MOUNT_MAP_SPECIAL_CHR);
237 } else { 243 } else {
238 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, 244 args.uid = NO_CHANGE_64;
239 (__u64)-1, 245 args.gid = NO_CHANGE_64;
240 (__u64)-1,
241 0 /* dev */,
242 cifs_sb->local_nls,
243 cifs_sb->mnt_cifs_flags &
244 CIFS_MOUNT_MAP_SPECIAL_CHR);
245 } 246 }
247 CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
248 cifs_sb->local_nls,
249 cifs_sb->mnt_cifs_flags &
250 CIFS_MOUNT_MAP_SPECIAL_CHR);
246 } else { 251 } else {
247 /* BB implement mode setting via Windows security 252 /* BB implement mode setting via Windows security
248 descriptors e.g. */ 253 descriptors e.g. */
@@ -267,7 +272,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
267 (cifs_sb->mnt_cifs_flags & 272 (cifs_sb->mnt_cifs_flags &
268 CIFS_MOUNT_SET_UID)) { 273 CIFS_MOUNT_SET_UID)) {
269 newinode->i_uid = current->fsuid; 274 newinode->i_uid = current->fsuid;
270 newinode->i_gid = current->fsgid; 275 if (inode->i_mode & S_ISGID)
276 newinode->i_gid =
277 inode->i_gid;
278 else
279 newinode->i_gid =
280 current->fsgid;
271 } 281 }
272 } 282 }
273 } 283 }
@@ -357,21 +367,24 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
357 if (full_path == NULL) 367 if (full_path == NULL)
358 rc = -ENOMEM; 368 rc = -ENOMEM;
359 else if (pTcon->unix_ext) { 369 else if (pTcon->unix_ext) {
360 mode &= ~current->fs->umask; 370 struct cifs_unix_set_info_args args = {
371 .mode = mode & ~current->fs->umask,
372 .ctime = NO_CHANGE_64,
373 .atime = NO_CHANGE_64,
374 .mtime = NO_CHANGE_64,
375 .device = device_number,
376 };
361 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 377 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
362 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, 378 args.uid = (__u64) current->fsuid;
363 mode, (__u64)current->fsuid, 379 args.gid = (__u64) current->fsgid;
364 (__u64)current->fsgid,
365 device_number, cifs_sb->local_nls,
366 cifs_sb->mnt_cifs_flags &
367 CIFS_MOUNT_MAP_SPECIAL_CHR);
368 } else { 380 } else {
369 rc = CIFSSMBUnixSetPerms(xid, pTcon, 381 args.uid = NO_CHANGE_64;
370 full_path, mode, (__u64)-1, (__u64)-1, 382 args.gid = NO_CHANGE_64;
371 device_number, cifs_sb->local_nls,
372 cifs_sb->mnt_cifs_flags &
373 CIFS_MOUNT_MAP_SPECIAL_CHR);
374 } 383 }
384 rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path,
385 &args, cifs_sb->local_nls,
386 cifs_sb->mnt_cifs_flags &
387 CIFS_MOUNT_MAP_SPECIAL_CHR);
375 388
376 if (!rc) { 389 if (!rc) {
377 rc = cifs_get_inode_info_unix(&newinode, full_path, 390 rc = cifs_get_inode_info_unix(&newinode, full_path,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e692c42f24b5..ff14d14903a0 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -310,18 +310,19 @@ int cifs_open(struct inode *inode, struct file *file)
310 /* time to set mode which we can not set earlier due to 310 /* time to set mode which we can not set earlier due to
311 problems creating new read-only files */ 311 problems creating new read-only files */
312 if (pTcon->unix_ext) { 312 if (pTcon->unix_ext) {
313 CIFSSMBUnixSetPerms(xid, pTcon, full_path, 313 struct cifs_unix_set_info_args args = {
314 inode->i_mode, 314 .mode = inode->i_mode,
315 (__u64)-1, (__u64)-1, 0 /* dev */, 315 .uid = NO_CHANGE_64,
316 .gid = NO_CHANGE_64,
317 .ctime = NO_CHANGE_64,
318 .atime = NO_CHANGE_64,
319 .mtime = NO_CHANGE_64,
320 .device = 0,
321 };
322 CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
316 cifs_sb->local_nls, 323 cifs_sb->local_nls,
317 cifs_sb->mnt_cifs_flags & 324 cifs_sb->mnt_cifs_flags &
318 CIFS_MOUNT_MAP_SPECIAL_CHR); 325 CIFS_MOUNT_MAP_SPECIAL_CHR);
319 } else {
320 /* BB implement via Windows security descriptors eg
321 CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
322 -1, -1, local_nls);
323 in the meantime could set r/o dos attribute when
324 perms are eg: mode & 0222 == 0 */
325 } 326 }
326 } 327 }
327 328
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 46e54d39461d..28a22092d450 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -737,7 +737,7 @@ psx_del_no_retry:
737 /* ATTRS set to normal clears r/o bit */ 737 /* ATTRS set to normal clears r/o bit */
738 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); 738 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
739 if (!(pTcon->ses->flags & CIFS_SES_NT4)) 739 if (!(pTcon->ses->flags & CIFS_SES_NT4))
740 rc = CIFSSMBSetTimes(xid, pTcon, full_path, 740 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
741 pinfo_buf, 741 pinfo_buf,
742 cifs_sb->local_nls, 742 cifs_sb->local_nls,
743 cifs_sb->mnt_cifs_flags & 743 cifs_sb->mnt_cifs_flags &
@@ -767,9 +767,10 @@ psx_del_no_retry:
767 cifs_sb->mnt_cifs_flags & 767 cifs_sb->mnt_cifs_flags &
768 CIFS_MOUNT_MAP_SPECIAL_CHR); 768 CIFS_MOUNT_MAP_SPECIAL_CHR);
769 if (rc == 0) { 769 if (rc == 0) {
770 rc = CIFSSMBSetFileTimes(xid, pTcon, 770 rc = CIFSSMBSetFileInfo(xid, pTcon,
771 pinfo_buf, 771 pinfo_buf,
772 netfid); 772 netfid,
773 current->tgid);
773 CIFSSMBClose(xid, pTcon, netfid); 774 CIFSSMBClose(xid, pTcon, netfid);
774 } 775 }
775 } 776 }
@@ -984,32 +985,41 @@ mkdir_get_info:
984 * failed to get it from the server or was set bogus */ 985 * failed to get it from the server or was set bogus */
985 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) 986 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
986 direntry->d_inode->i_nlink = 2; 987 direntry->d_inode->i_nlink = 2;
988
987 mode &= ~current->fs->umask; 989 mode &= ~current->fs->umask;
990 /* must turn on setgid bit if parent dir has it */
991 if (inode->i_mode & S_ISGID)
992 mode |= S_ISGID;
993
988 if (pTcon->unix_ext) { 994 if (pTcon->unix_ext) {
995 struct cifs_unix_set_info_args args = {
996 .mode = mode,
997 .ctime = NO_CHANGE_64,
998 .atime = NO_CHANGE_64,
999 .mtime = NO_CHANGE_64,
1000 .device = 0,
1001 };
989 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 1002 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
990 CIFSSMBUnixSetPerms(xid, pTcon, full_path, 1003 args.uid = (__u64)current->fsuid;
991 mode, 1004 if (inode->i_mode & S_ISGID)
992 (__u64)current->fsuid, 1005 args.gid = (__u64)inode->i_gid;
993 (__u64)current->fsgid, 1006 else
994 0 /* dev_t */, 1007 args.gid = (__u64)current->fsgid;
995 cifs_sb->local_nls,
996 cifs_sb->mnt_cifs_flags &
997 CIFS_MOUNT_MAP_SPECIAL_CHR);
998 } else { 1008 } else {
999 CIFSSMBUnixSetPerms(xid, pTcon, full_path, 1009 args.uid = NO_CHANGE_64;
1000 mode, (__u64)-1, 1010 args.gid = NO_CHANGE_64;
1001 (__u64)-1, 0 /* dev_t */,
1002 cifs_sb->local_nls,
1003 cifs_sb->mnt_cifs_flags &
1004 CIFS_MOUNT_MAP_SPECIAL_CHR);
1005 } 1011 }
1012 CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args,
1013 cifs_sb->local_nls,
1014 cifs_sb->mnt_cifs_flags &
1015 CIFS_MOUNT_MAP_SPECIAL_CHR);
1006 } else { 1016 } else {
1007 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 1017 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1008 (mode & S_IWUGO) == 0) { 1018 (mode & S_IWUGO) == 0) {
1009 FILE_BASIC_INFO pInfo; 1019 FILE_BASIC_INFO pInfo;
1010 memset(&pInfo, 0, sizeof(pInfo)); 1020 memset(&pInfo, 0, sizeof(pInfo));
1011 pInfo.Attributes = cpu_to_le32(ATTR_READONLY); 1021 pInfo.Attributes = cpu_to_le32(ATTR_READONLY);
1012 CIFSSMBSetTimes(xid, pTcon, full_path, 1022 CIFSSMBSetPathInfo(xid, pTcon, full_path,
1013 &pInfo, cifs_sb->local_nls, 1023 &pInfo, cifs_sb->local_nls,
1014 cifs_sb->mnt_cifs_flags & 1024 cifs_sb->mnt_cifs_flags &
1015 CIFS_MOUNT_MAP_SPECIAL_CHR); 1025 CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1024,8 +1034,12 @@ mkdir_get_info:
1024 CIFS_MOUNT_SET_UID) { 1034 CIFS_MOUNT_SET_UID) {
1025 direntry->d_inode->i_uid = 1035 direntry->d_inode->i_uid =
1026 current->fsuid; 1036 current->fsuid;
1027 direntry->d_inode->i_gid = 1037 if (inode->i_mode & S_ISGID)
1028 current->fsgid; 1038 direntry->d_inode->i_gid =
1039 inode->i_gid;
1040 else
1041 direntry->d_inode->i_gid =
1042 current->fsgid;
1029 } 1043 }
1030 } 1044 }
1031 } 1045 }
@@ -1310,10 +1324,11 @@ int cifs_revalidate(struct dentry *direntry)
1310/* if (S_ISDIR(direntry->d_inode->i_mode)) 1324/* if (S_ISDIR(direntry->d_inode->i_mode))
1311 shrink_dcache_parent(direntry); */ 1325 shrink_dcache_parent(direntry); */
1312 if (S_ISREG(direntry->d_inode->i_mode)) { 1326 if (S_ISREG(direntry->d_inode->i_mode)) {
1313 if (direntry->d_inode->i_mapping) 1327 if (direntry->d_inode->i_mapping) {
1314 wbrc = filemap_fdatawait(direntry->d_inode->i_mapping); 1328 wbrc = filemap_fdatawait(direntry->d_inode->i_mapping);
1315 if (wbrc) 1329 if (wbrc)
1316 CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; 1330 CIFS_I(direntry->d_inode)->write_behind_rc = wbrc;
1331 }
1317 /* may eventually have to do this for open files too */ 1332 /* may eventually have to do this for open files too */
1318 if (list_empty(&(cifsInode->openFileList))) { 1333 if (list_empty(&(cifsInode->openFileList))) {
1319 /* changed on server - flush read ahead pages */ 1334 /* changed on server - flush read ahead pages */
@@ -1489,30 +1504,228 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
1489 return rc; 1504 return rc;
1490} 1505}
1491 1506
1492int cifs_setattr(struct dentry *direntry, struct iattr *attrs) 1507static int
1508cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
1509 char *full_path, __u32 dosattr)
1510{
1511 int rc;
1512 int oplock = 0;
1513 __u16 netfid;
1514 __u32 netpid;
1515 bool set_time = false;
1516 struct cifsFileInfo *open_file;
1517 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1518 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1519 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1520 FILE_BASIC_INFO info_buf;
1521
1522 if (attrs->ia_valid & ATTR_ATIME) {
1523 set_time = true;
1524 info_buf.LastAccessTime =
1525 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1526 } else
1527 info_buf.LastAccessTime = 0;
1528
1529 if (attrs->ia_valid & ATTR_MTIME) {
1530 set_time = true;
1531 info_buf.LastWriteTime =
1532 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1533 } else
1534 info_buf.LastWriteTime = 0;
1535
1536 /*
1537 * Samba throws this field away, but windows may actually use it.
1538 * Do not set ctime unless other time stamps are changed explicitly
1539 * (i.e. by utimes()) since we would then have a mix of client and
1540 * server times.
1541 */
1542 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
1543 cFYI(1, ("CIFS - CTIME changed"));
1544 info_buf.ChangeTime =
1545 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1546 } else
1547 info_buf.ChangeTime = 0;
1548
1549 info_buf.CreationTime = 0; /* don't change */
1550 info_buf.Attributes = cpu_to_le32(dosattr);
1551
1552 /*
1553 * If the file is already open for write, just use that fileid
1554 */
1555 open_file = find_writable_file(cifsInode);
1556 if (open_file) {
1557 netfid = open_file->netfid;
1558 netpid = open_file->pid;
1559 goto set_via_filehandle;
1560 }
1561
1562 /*
1563 * NT4 apparently returns success on this call, but it doesn't
1564 * really work.
1565 */
1566 if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
1567 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
1568 &info_buf, cifs_sb->local_nls,
1569 cifs_sb->mnt_cifs_flags &
1570 CIFS_MOUNT_MAP_SPECIAL_CHR);
1571 if (rc != -EOPNOTSUPP && rc != -EINVAL)
1572 goto out;
1573 }
1574
1575 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1576 "times not supported by this server"));
1577 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1578 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1579 CREATE_NOT_DIR, &netfid, &oplock,
1580 NULL, cifs_sb->local_nls,
1581 cifs_sb->mnt_cifs_flags &
1582 CIFS_MOUNT_MAP_SPECIAL_CHR);
1583
1584 if (rc != 0) {
1585 if (rc == -EIO)
1586 rc = -EINVAL;
1587 goto out;
1588 }
1589
1590 netpid = current->tgid;
1591
1592set_via_filehandle:
1593 rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
1594 if (open_file == NULL)
1595 CIFSSMBClose(xid, pTcon, netfid);
1596 else
1597 atomic_dec(&open_file->wrtPending);
1598out:
1599 return rc;
1600}
1601
1602static int
1603cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
1493{ 1604{
1605 int rc;
1494 int xid; 1606 int xid;
1495 struct cifs_sb_info *cifs_sb;
1496 struct cifsTconInfo *pTcon;
1497 char *full_path = NULL; 1607 char *full_path = NULL;
1498 int rc = -EACCES;
1499 FILE_BASIC_INFO time_buf;
1500 bool set_time = false;
1501 bool set_dosattr = false;
1502 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
1503 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
1504 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
1505 struct cifsInodeInfo *cifsInode;
1506 struct inode *inode = direntry->d_inode; 1608 struct inode *inode = direntry->d_inode;
1609 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1610 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1611 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1612 struct cifs_unix_set_info_args *args = NULL;
1613
1614 cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x",
1615 direntry->d_name.name, attrs->ia_valid));
1616
1617 xid = GetXid();
1618
1619 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
1620 /* check if we have permission to change attrs */
1621 rc = inode_change_ok(inode, attrs);
1622 if (rc < 0)
1623 goto out;
1624 else
1625 rc = 0;
1626 }
1627
1628 full_path = build_path_from_dentry(direntry);
1629 if (full_path == NULL) {
1630 rc = -ENOMEM;
1631 goto out;
1632 }
1633
1634 if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
1635 /*
1636 Flush data before changing file size or changing the last
1637 write time of the file on the server. If the
1638 flush returns error, store it to report later and continue.
1639 BB: This should be smarter. Why bother flushing pages that
1640 will be truncated anyway? Also, should we error out here if
1641 the flush returns error?
1642 */
1643 rc = filemap_write_and_wait(inode->i_mapping);
1644 if (rc != 0) {
1645 cifsInode->write_behind_rc = rc;
1646 rc = 0;
1647 }
1648 }
1649
1650 if (attrs->ia_valid & ATTR_SIZE) {
1651 rc = cifs_set_file_size(inode, attrs, xid, full_path);
1652 if (rc != 0)
1653 goto out;
1654 }
1655
1656 /* skip mode change if it's just for clearing setuid/setgid */
1657 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
1658 attrs->ia_valid &= ~ATTR_MODE;
1659
1660 args = kmalloc(sizeof(*args), GFP_KERNEL);
1661 if (args == NULL) {
1662 rc = -ENOMEM;
1663 goto out;
1664 }
1665
1666 /* set up the struct */
1667 if (attrs->ia_valid & ATTR_MODE)
1668 args->mode = attrs->ia_mode;
1669 else
1670 args->mode = NO_CHANGE_64;
1671
1672 if (attrs->ia_valid & ATTR_UID)
1673 args->uid = attrs->ia_uid;
1674 else
1675 args->uid = NO_CHANGE_64;
1676
1677 if (attrs->ia_valid & ATTR_GID)
1678 args->gid = attrs->ia_gid;
1679 else
1680 args->gid = NO_CHANGE_64;
1681
1682 if (attrs->ia_valid & ATTR_ATIME)
1683 args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
1684 else
1685 args->atime = NO_CHANGE_64;
1686
1687 if (attrs->ia_valid & ATTR_MTIME)
1688 args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
1689 else
1690 args->mtime = NO_CHANGE_64;
1691
1692 if (attrs->ia_valid & ATTR_CTIME)
1693 args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
1694 else
1695 args->ctime = NO_CHANGE_64;
1696
1697 args->device = 0;
1698 rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, args,
1699 cifs_sb->local_nls,
1700 cifs_sb->mnt_cifs_flags &
1701 CIFS_MOUNT_MAP_SPECIAL_CHR);
1702
1703 if (!rc)
1704 rc = inode_setattr(inode, attrs);
1705out:
1706 kfree(args);
1707 kfree(full_path);
1708 FreeXid(xid);
1709 return rc;
1710}
1711
1712static int
1713cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
1714{
1715 int xid;
1716 struct inode *inode = direntry->d_inode;
1717 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1718 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1719 char *full_path = NULL;
1720 int rc = -EACCES;
1721 __u32 dosattr = 0;
1722 __u64 mode = NO_CHANGE_64;
1507 1723
1508 xid = GetXid(); 1724 xid = GetXid();
1509 1725
1510 cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", 1726 cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
1511 direntry->d_name.name, attrs->ia_valid)); 1727 direntry->d_name.name, attrs->ia_valid));
1512 1728
1513 cifs_sb = CIFS_SB(inode->i_sb);
1514 pTcon = cifs_sb->tcon;
1515
1516 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { 1729 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
1517 /* check if we have permission to change attrs */ 1730 /* check if we have permission to change attrs */
1518 rc = inode_change_ok(inode, attrs); 1731 rc = inode_change_ok(inode, attrs);
@@ -1528,7 +1741,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1528 FreeXid(xid); 1741 FreeXid(xid);
1529 return -ENOMEM; 1742 return -ENOMEM;
1530 } 1743 }
1531 cifsInode = CIFS_I(inode);
1532 1744
1533 if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { 1745 if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
1534 /* 1746 /*
@@ -1559,21 +1771,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1559 * CIFSACL support + proper Windows to Unix idmapping, we may be 1771 * CIFSACL support + proper Windows to Unix idmapping, we may be
1560 * able to support this in the future. 1772 * able to support this in the future.
1561 */ 1773 */
1562 if (!pTcon->unix_ext && 1774 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
1563 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
1564 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); 1775 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
1565 } else {
1566 if (attrs->ia_valid & ATTR_UID) {
1567 cFYI(1, ("UID changed to %d", attrs->ia_uid));
1568 uid = attrs->ia_uid;
1569 }
1570 if (attrs->ia_valid & ATTR_GID) {
1571 cFYI(1, ("GID changed to %d", attrs->ia_gid));
1572 gid = attrs->ia_gid;
1573 }
1574 }
1575
1576 time_buf.Attributes = 0;
1577 1776
1578 /* skip mode change if it's just for clearing setuid/setgid */ 1777 /* skip mode change if it's just for clearing setuid/setgid */
1579 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) 1778 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
@@ -1584,13 +1783,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1584 mode = attrs->ia_mode; 1783 mode = attrs->ia_mode;
1585 } 1784 }
1586 1785
1587 if ((pTcon->unix_ext) 1786 if (attrs->ia_valid & ATTR_MODE) {
1588 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
1589 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
1590 0 /* dev_t */, cifs_sb->local_nls,
1591 cifs_sb->mnt_cifs_flags &
1592 CIFS_MOUNT_MAP_SPECIAL_CHR);
1593 else if (attrs->ia_valid & ATTR_MODE) {
1594 rc = 0; 1787 rc = 0;
1595#ifdef CONFIG_CIFS_EXPERIMENTAL 1788#ifdef CONFIG_CIFS_EXPERIMENTAL
1596 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) 1789 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
@@ -1599,24 +1792,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1599#endif 1792#endif
1600 if (((mode & S_IWUGO) == 0) && 1793 if (((mode & S_IWUGO) == 0) &&
1601 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { 1794 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
1602 set_dosattr = true; 1795
1603 time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs | 1796 dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
1604 ATTR_READONLY); 1797
1605 /* fix up mode if we're not using dynperm */ 1798 /* fix up mode if we're not using dynperm */
1606 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) 1799 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
1607 attrs->ia_mode = inode->i_mode & ~S_IWUGO; 1800 attrs->ia_mode = inode->i_mode & ~S_IWUGO;
1608 } else if ((mode & S_IWUGO) && 1801 } else if ((mode & S_IWUGO) &&
1609 (cifsInode->cifsAttrs & ATTR_READONLY)) { 1802 (cifsInode->cifsAttrs & ATTR_READONLY)) {
1610 /* If file is readonly on server, we would 1803
1611 not be able to write to it - so if any write 1804 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
1612 bit is enabled for user or group or other we 1805 /* Attributes of 0 are ignored */
1613 need to at least try to remove r/o dos attr */ 1806 if (dosattr == 0)
1614 set_dosattr = true; 1807 dosattr |= ATTR_NORMAL;
1615 time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
1616 (~ATTR_READONLY));
1617 /* Windows ignores set to zero */
1618 if (time_buf.Attributes == 0)
1619 time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
1620 1808
1621 /* reset local inode permissions to normal */ 1809 /* reset local inode permissions to normal */
1622 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { 1810 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
@@ -1634,82 +1822,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1634 } 1822 }
1635 } 1823 }
1636 1824
1637 if (attrs->ia_valid & ATTR_ATIME) { 1825 if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
1638 set_time = true; 1826 ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
1639 time_buf.LastAccessTime = 1827 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
1640 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); 1828 /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
1641 } else
1642 time_buf.LastAccessTime = 0;
1643
1644 if (attrs->ia_valid & ATTR_MTIME) {
1645 set_time = true;
1646 time_buf.LastWriteTime =
1647 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1648 } else
1649 time_buf.LastWriteTime = 0;
1650 /* Do not set ctime explicitly unless other time
1651 stamps are changed explicitly (i.e. by utime()
1652 since we would then have a mix of client and
1653 server times */
1654 1829
1655 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
1656 set_time = true;
1657 /* Although Samba throws this field away
1658 it may be useful to Windows - but we do
1659 not want to set ctime unless some other
1660 timestamp is changing */
1661 cFYI(1, ("CIFS - CTIME changed"));
1662 time_buf.ChangeTime =
1663 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1664 } else
1665 time_buf.ChangeTime = 0;
1666
1667 if (set_time || set_dosattr) {
1668 time_buf.CreationTime = 0; /* do not change */
1669 /* In the future we should experiment - try setting timestamps
1670 via Handle (SetFileInfo) instead of by path */
1671 if (!(pTcon->ses->flags & CIFS_SES_NT4))
1672 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
1673 cifs_sb->local_nls,
1674 cifs_sb->mnt_cifs_flags &
1675 CIFS_MOUNT_MAP_SPECIAL_CHR);
1676 else
1677 rc = -EOPNOTSUPP;
1678
1679 if (rc == -EOPNOTSUPP) {
1680 int oplock = 0;
1681 __u16 netfid;
1682
1683 cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1684 "times not supported by this server"));
1685 /* BB we could scan to see if we already have it open
1686 and pass in pid of opener to function */
1687 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1688 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1689 CREATE_NOT_DIR, &netfid, &oplock,
1690 NULL, cifs_sb->local_nls,
1691 cifs_sb->mnt_cifs_flags &
1692 CIFS_MOUNT_MAP_SPECIAL_CHR);
1693 if (rc == 0) {
1694 rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
1695 netfid);
1696 CIFSSMBClose(xid, pTcon, netfid);
1697 } else {
1698 /* BB For even older servers we could convert time_buf
1699 into old DOS style which uses two second
1700 granularity */
1701
1702 /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
1703 &time_buf, cifs_sb->local_nls); */
1704 }
1705 }
1706 /* Even if error on time set, no sense failing the call if 1830 /* Even if error on time set, no sense failing the call if
1707 the server would set the time to a reasonable value anyway, 1831 the server would set the time to a reasonable value anyway,
1708 and this check ensures that we are not being called from 1832 and this check ensures that we are not being called from
1709 sys_utimes in which case we ought to fail the call back to 1833 sys_utimes in which case we ought to fail the call back to
1710 the user when the server rejects the call */ 1834 the user when the server rejects the call */
1711 if ((rc) && (attrs->ia_valid & 1835 if ((rc) && (attrs->ia_valid &
1712 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) 1836 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
1713 rc = 0; 1837 rc = 0;
1714 } 1838 }
1715 1839
@@ -1723,6 +1847,21 @@ cifs_setattr_exit:
1723 return rc; 1847 return rc;
1724} 1848}
1725 1849
1850int
1851cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1852{
1853 struct inode *inode = direntry->d_inode;
1854 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1855 struct cifsTconInfo *pTcon = cifs_sb->tcon;
1856
1857 if (pTcon->unix_ext)
1858 return cifs_setattr_unix(direntry, attrs);
1859
1860 return cifs_setattr_nounix(direntry, attrs);
1861
1862 /* BB: add cifs_setattr_legacy for really old servers */
1863}
1864
1726#if 0 1865#if 0
1727void cifs_delete_inode(struct inode *inode) 1866void cifs_delete_inode(struct inode *inode)
1728{ 1867{
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 000ac509c98a..e286db9f5ee2 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -265,6 +265,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
265 cFYI(1, ("Sending smb: total_len %d", total_len)); 265 cFYI(1, ("Sending smb: total_len %d", total_len));
266 dump_smb(smb_buffer, len); 266 dump_smb(smb_buffer, len);
267 267
268 i = 0;
268 while (total_len) { 269 while (total_len) {
269 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], 270 rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
270 n_vec - first_vec, total_len); 271 n_vec - first_vec, total_len);