summaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-10-13 11:05:51 +0200
committerIngo Molnar <mingo@elte.hu>2008-10-13 11:05:51 +0200
commitaccba5f3965d6a9d1bf7c1e1a7995d17e9d521b6 (patch)
tree8fb40782e79472ed882ff2098d4dd295557278ee /fs/cifs
parent6852fd9b86d05063c6ef49d2e12e061cc7f6a105 (diff)
parent4480f15b3306f43bbb0310d461142b4e897ca45b (diff)
Merge branch 'linus' into oprofile-v2
Conflicts: arch/x86/kernel/apic_32.c arch/x86/oprofile/nmi_int.c include/linux/pci_ids.h
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/CHANGES16
-rw-r--r--fs/cifs/README44
-rw-r--r--fs/cifs/asn1.c265
-rw-r--r--fs/cifs/cifs_debug.c696
-rw-r--r--fs/cifs/cifs_dfs_ref.c2
-rw-r--r--fs/cifs/cifs_spnego.c45
-rw-r--r--fs/cifs/cifs_spnego.h2
-rw-r--r--fs/cifs/cifsacl.c41
-rw-r--r--fs/cifs/cifsencrypt.c4
-rw-r--r--fs/cifs/cifsfs.c77
-rw-r--r--fs/cifs/cifsfs.h4
-rw-r--r--fs/cifs/cifsglob.h10
-rw-r--r--fs/cifs/cifspdu.h10
-rw-r--r--fs/cifs/cifsproto.h28
-rw-r--r--fs/cifs/cifssmb.c140
-rw-r--r--fs/cifs/connect.c223
-rw-r--r--fs/cifs/dir.c67
-rw-r--r--fs/cifs/dns_resolve.c77
-rw-r--r--fs/cifs/file.c155
-rw-r--r--fs/cifs/inode.c1016
-rw-r--r--fs/cifs/misc.c8
-rw-r--r--fs/cifs/readdir.c129
-rw-r--r--fs/cifs/sess.c17
-rw-r--r--fs/cifs/transport.c4
24 files changed, 1669 insertions, 1411 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 1f3465201fd..06e521a945c 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,19 @@
+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. Fix problems with preserving timestamps on copying open
+files (e.g. "cp -a") to Windows servers. For mkdir and create honor setgid bit
+on parent directory when server supports Unix Extensions but not POSIX
+create. Update cifs.upcall version to handle new Kerberos sec flags
+(this requires update of cifs.upcall program from Samba). Fix memory leak
+on dns_upcall (resolving DFS referralls). Fix plain text password
+authentication (requires setting SecurityFlags to 0x30030 to enable
+lanman and plain text though). Fix writes to be at correct offset when
+file is open with O_APPEND and file is on a directio (forcediretio) mount.
+
Version 1.53
------------
DFS support added (Microsoft Distributed File System client support needed
diff --git a/fs/cifs/README b/fs/cifs/README
index 2bd6fe556f8..bd2343d4c6a 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -542,10 +542,20 @@ SecurityFlags Flags which control security negotiation and
hashing mechanisms (as "must use") on the other hand
does not make much sense. Default flags are
0x07007
- (NTLM, NTLMv2 and packet signing allowed). Maximum
+ (NTLM, NTLMv2 and packet signing allowed). The maximum
allowable flags if you want to allow mounts to servers
using weaker password hashes is 0x37037 (lanman,
- plaintext, ntlm, ntlmv2, signing allowed):
+ plaintext, ntlm, ntlmv2, signing allowed). Some
+ SecurityFlags require the corresponding menuconfig
+ options to be enabled (lanman and plaintext require
+ CONFIG_CIFS_WEAK_PW_HASH for example). Enabling
+ plaintext authentication currently requires also
+ enabling lanman authentication in the security flags
+ because the cifs module only supports sending
+ laintext passwords using the older lanman dialect
+ form of the session setup SMB. (e.g. for authentication
+ using plain text passwords, set the SecurityFlags
+ to 0x30030):
may use packet signing 0x00001
must use packet signing 0x01001
@@ -642,8 +652,30 @@ The statistics for the number of total SMBs and oplock breaks are different in
that they represent all for that share, not just those for which the server
returned success.
-Also note that "cat /proc/fs/cifs/DebugData" will display information about
+Also note that "cat /proc/fs/cifs/DebugData" will display information about
the active sessions and the shares that are mounted.
-Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is
-on but requires a user space helper (from the Samba project). NTLM and NTLMv2 and
-LANMAN support do not require this helper.
+
+Enabling Kerberos (extended security) works but requires version 1.2 or later
+of the helper program cifs.upcall to be present and to be configured in the
+/etc/request-key.conf file. The cifs.upcall helper program is from the Samba
+project(http://www.samba.org). NTLM and NTLMv2 and LANMAN support do not
+require this helper. Note that NTLMv2 security (which does not require the
+cifs.upcall helper program), instead of using Kerberos, is sufficient for
+some use cases.
+
+Enabling DFS support (used to access shares transparently in an MS-DFS
+global name space) requires that CONFIG_CIFS_EXPERIMENTAL be enabled. In
+addition, DFS support for target shares which are specified as UNC
+names which begin with host names (rather than IP addresses) requires
+a user space helper (such as cifs.upcall) to be present in order to
+translate host names to ip address, and the user space helper must also
+be configured in the file /etc/request-key.conf
+
+To use cifs Kerberos and DFS support, the Linux keyutils package should be
+installed and something like the following lines should be added to the
+/etc/request-key.conf file:
+
+create cifs.spnego * * /usr/local/sbin/cifs.upcall %k
+create dns_resolver * * /usr/local/sbin/cifs.upcall %k
+
+
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c
index f58e41d3ba4..1b09f167006 100644
--- a/fs/cifs/asn1.c
+++ b/fs/cifs/asn1.c
@@ -400,7 +400,7 @@ asn1_oid_decode(struct asn1_ctx *ctx,
size = eoc - ctx->pointer + 1;
/* first subid actually encodes first two subids */
- if (size < 2 || size > ULONG_MAX/sizeof(unsigned long))
+ if (size < 2 || size > UINT_MAX/sizeof(unsigned long))
return 0;
*oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC);
@@ -476,6 +476,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
unsigned int cls, con, tag, oidlen, rc;
bool use_ntlmssp = false;
bool use_kerberos = false;
+ bool use_mskerberos = false;
*secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/
@@ -483,6 +484,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,156 +492,149 @@ 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) && (cls == 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)
+ use_mskerberos = true;
+ else if (compare_oid(oid, oidlen, KRB5_OID,
+ KRB5_OID_LEN) &&
+ !use_mskerberos)
+ 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;
+ else if (use_mskerberos)
+ *secType = MSKerberos;
else if (use_ntlmssp)
*secType = NTLMSSP;
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index cc950f69e51..69a12aae91d 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)
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);
@@ -107,9 +105,7 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
#endif /* CONFIG_CIFS_DEBUG2 */
#ifdef CONFIG_PROC_FS
-static int
-cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
- int count, int *eof, void *data)
+static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
{
struct list_head *tmp;
struct list_head *tmp1;
@@ -117,23 +113,13 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
struct cifsSesInfo *ses;
struct cifsTconInfo *tcon;
int i;
- int length = 0;
- char *original_buf = buf;
-
- *beginBuffer = buf + offset;
- length =
- sprintf(buf,
+ seq_puts(m,
"Display Internal CIFS Data Structures for Debugging\n"
"---------------------------------------------------\n");
- buf += length;
- length = sprintf(buf, "CIFS Version %s\n", CIFS_VERSION);
- buf += length;
- length = sprintf(buf,
- "Active VFS Requests: %d\n", GlobalTotalActiveXid);
- buf += length;
- length = sprintf(buf, "Servers:");
- buf += length;
+ seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
+ seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
+ seq_printf(m, "Servers:");
i = 0;
read_lock(&GlobalSMBSeslock);
@@ -142,11 +128,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) ||
(ses->serverNOS == NULL)) {
- buf += sprintf(buf, "\nentry for %s not fully "
+ seq_printf(m, "\nentry for %s not fully "
"displayed\n\t", ses->serverName);
} else {
- length =
- sprintf(buf,
+ seq_printf(m,
"\n%d) Name: %s Domain: %s Mounts: %d OS:"
" %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB"
" session status: %d\t",
@@ -154,10 +139,9 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
atomic_read(&ses->inUse),
ses->serverOS, ses->serverNOS,
ses->capabilities, ses->status);
- buf += length;
}
if (ses->server) {
- buf += sprintf(buf, "TCP status: %d\n\tLocal Users To "
+ seq_printf(m, "TCP status: %d\n\tLocal Users To "
"Server: %d SecMode: 0x%x Req On Wire: %d",
ses->server->tcpStatus,
atomic_read(&ses->server->socketUseCount),
@@ -165,41 +149,34 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
atomic_read(&ses->server->inFlight));
#ifdef CONFIG_CIFS_STATS2
- buf += sprintf(buf, " In Send: %d In MaxReq Wait: %d",
+ seq_printf(m, " In Send: %d In MaxReq Wait: %d",
atomic_read(&ses->server->inSend),
atomic_read(&ses->server->num_waiters));
#endif
- length = sprintf(buf, "\nMIDs:\n");
- buf += length;
+ seq_puts(m, "\nMIDs:\n");
spin_lock(&GlobalMid_Lock);
list_for_each(tmp1, &ses->server->pending_mid_q) {
mid_entry = list_entry(tmp1, struct
mid_q_entry,
qhead);
- if (mid_entry) {
- length = sprintf(buf,
- "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);
- buf += length;
- }
+ 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);
}
}
read_unlock(&GlobalSMBSeslock);
- sprintf(buf, "\n");
- buf++;
+ seq_putc(m, '\n');
- length = sprintf(buf, "Shares:");
- buf += length;
+ seq_puts(m, "Shares:");
i = 0;
read_lock(&GlobalSMBSeslock);
@@ -208,62 +185,52 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
i++;
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
- length = sprintf(buf, "\n%d) %s Uses: %d ", i,
+ seq_printf(m, "\n%d) %s Uses: %d ", i,
tcon->treeName, atomic_read(&tcon->useCount));
- buf += length;
if (tcon->nativeFileSystem) {
- length = sprintf(buf, "Type: %s ",
+ seq_printf(m, "Type: %s ",
tcon->nativeFileSystem);
- buf += length;
}
- length = sprintf(buf, "DevInfo: 0x%x Attributes: 0x%x"
+ seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
"\nPathComponentMax: %d Status: %d",
le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
le32_to_cpu(tcon->fsAttrInfo.Attributes),
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
tcon->tidStatus);
- buf += length;
if (dev_type == FILE_DEVICE_DISK)
- length = sprintf(buf, " type: DISK ");
+ seq_puts(m, " type: DISK ");
else if (dev_type == FILE_DEVICE_CD_ROM)
- length = sprintf(buf, " type: CDROM ");
+ seq_puts(m, " type: CDROM ");
else
- length =
- sprintf(buf, " type: %d ", dev_type);
- buf += length;
- if (tcon->tidStatus == CifsNeedReconnect) {
- buf += sprintf(buf, "\tDISCONNECTED ");
- length += 14;
- }
+ seq_printf(m, " type: %d ", dev_type);
+
+ if (tcon->tidStatus == CifsNeedReconnect)
+ seq_puts(m, "\tDISCONNECTED ");
}
read_unlock(&GlobalSMBSeslock);
- length = sprintf(buf, "\n");
- buf += length;
+ seq_putc(m, '\n');
/* BB add code to dump additional info such as TCP session info now */
- /* Now calculate total size of returned data */
- length = buf - original_buf;
-
- if (offset + count >= length)
- *eof = 1;
- if (length < offset) {
- *eof = 1;
- return 0;
- } else {
- length = length - offset;
- }
- if (length > count)
- length = count;
+ return 0;
+}
- return length;
+static int cifs_debug_data_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cifs_debug_data_proc_show, NULL);
}
-#ifdef CONFIG_CIFS_STATS
+static const struct file_operations cifs_debug_data_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = cifs_debug_data_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
-static int
-cifs_stats_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+#ifdef CONFIG_CIFS_STATS
+static ssize_t cifs_stats_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
{
char c;
int rc;
@@ -307,236 +274,132 @@ cifs_stats_write(struct file *file, const char __user *buffer,
return count;
}
-static int
-cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
- int count, int *eof, void *data)
+static int cifs_stats_proc_show(struct seq_file *m, void *v)
{
- int item_length, i, length;
+ int i;
struct list_head *tmp;
struct cifsTconInfo *tcon;
- *beginBuffer = buf + offset;
-
- length = sprintf(buf,
+ seq_printf(m,
"Resources in use\nCIFS Session: %d\n",
sesInfoAllocCount.counter);
- buf += length;
- item_length =
- sprintf(buf, "Share (unique mount targets): %d\n",
+ seq_printf(m, "Share (unique mount targets): %d\n",
tconInfoAllocCount.counter);
- length += item_length;
- buf += item_length;
- item_length =
- sprintf(buf, "SMB Request/Response Buffer: %d Pool size: %d\n",
+ seq_printf(m, "SMB Request/Response Buffer: %d Pool size: %d\n",
bufAllocCount.counter,
cifs_min_rcv + tcpSesAllocCount.counter);
- length += item_length;
- buf += item_length;
- item_length =
- sprintf(buf, "SMB Small Req/Resp Buffer: %d Pool size: %d\n",
+ seq_printf(m, "SMB Small Req/Resp Buffer: %d Pool size: %d\n",
smBufAllocCount.counter, cifs_min_small);
- length += item_length;
- buf += item_length;
#ifdef CONFIG_CIFS_STATS2
- item_length = sprintf(buf, "Total Large %d Small %d Allocations\n",
+ seq_printf(m, "Total Large %d Small %d Allocations\n",
atomic_read(&totBufAllocCount),
atomic_read(&totSmBufAllocCount));
- length += item_length;
- buf += item_length;
#endif /* CONFIG_CIFS_STATS2 */
- item_length =
- sprintf(buf, "Operations (MIDs): %d\n",
- midCount.counter);
- length += item_length;
- buf += item_length;
- item_length = sprintf(buf,
+ seq_printf(m, "Operations (MIDs): %d\n", midCount.counter);
+ seq_printf(m,
"\n%d session %d share reconnects\n",
tcpSesReconnectCount.counter, tconInfoReconnectCount.counter);
- length += item_length;
- buf += item_length;
- item_length = sprintf(buf,
+ seq_printf(m,
"Total vfs operations: %d maximum at one time: %d\n",
GlobalCurrentXid, GlobalMaxActiveXid);
- length += item_length;
- buf += item_length;
i = 0;
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalTreeConnectionList) {
i++;
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
- item_length = sprintf(buf, "\n%d) %s", i, tcon->treeName);
- buf += item_length;
- length += item_length;
- if (tcon->tidStatus == CifsNeedReconnect) {
- buf += sprintf(buf, "\tDISCONNECTED ");
- length += 14;
- }
- item_length = sprintf(buf, "\nSMBs: %d Oplock Breaks: %d",
+ seq_printf(m, "\n%d) %s", i, tcon->treeName);
+ if (tcon->tidStatus == CifsNeedReconnect)
+ seq_puts(m, "\tDISCONNECTED ");
+ seq_printf(m, "\nSMBs: %d Oplock Breaks: %d",
atomic_read(&tcon->num_smbs_sent),
atomic_read(&tcon->num_oplock_brks));
- buf += item_length;
- length += item_length;
- item_length = sprintf(buf, "\nReads: %d Bytes: %lld",
+ seq_printf(m, "\nReads: %d Bytes: %lld",
atomic_read(&tcon->num_reads),
(long long)(tcon->bytes_read));
- buf += item_length;
- length += item_length;
- item_length = sprintf(buf, "\nWrites: %d Bytes: %lld",
+ seq_printf(m, "\nWrites: %d Bytes: %lld",
atomic_read(&tcon->num_writes),
(long long)(tcon->bytes_written));
- buf += item_length;
- length += item_length;
- item_length = sprintf(buf,
+ seq_printf(m,
"\nLocks: %d HardLinks: %d Symlinks: %d",
atomic_read(&tcon->num_locks),
atomic_read(&tcon->num_hardlinks),
atomic_read(&tcon->num_symlinks));
- buf += item_length;
- length += item_length;
- item_length = sprintf(buf, "\nOpens: %d Closes: %d Deletes: %d",
+ seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d",
atomic_read(&tcon->num_opens),
atomic_read(&tcon->num_closes),
atomic_read(&tcon->num_deletes));
- buf += item_length;
- length += item_length;
- item_length = sprintf(buf, "\nMkdirs: %d Rmdirs: %d",
+ seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
atomic_read(&tcon->num_mkdirs),
atomic_read(&tcon->num_rmdirs));
- buf += item_length;
- length += item_length;
- item_length = sprintf(buf, "\nRenames: %d T2 Renames %d",
+ seq_printf(m, "\nRenames: %d T2 Renames %d",
atomic_read(&tcon->num_renames),
atomic_read(&tcon->num_t2renames));
- buf += item_length;
- length += item_length;
- item_length = sprintf(buf, "\nFindFirst: %d FNext %d FClose %d",
+ seq_printf(m, "\nFindFirst: %d FNext %d FClose %d",
atomic_read(&tcon->num_ffirst),
atomic_read(&tcon->num_fnext),
atomic_read(&tcon->num_fclose));
- buf += item_length;
- length += item_length;
}
read_unlock(&GlobalSMBSeslock);
- buf += sprintf(buf, "\n");
- length++;
-
- if (offset + count >= length)
- *eof = 1;
- if (length < offset) {
- *eof = 1;
- return 0;
- } else {
- length = length - offset;
- }
- if (length > count)
- length = count;
+ seq_putc(m, '\n');
+ return 0;
+}
- return length;
+static int cifs_stats_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cifs_stats_proc_show, NULL);
}
+
+static const struct file_operations cifs_stats_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = cifs_stats_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = cifs_stats_proc_write,
+};
#endif /* STATS */
static struct proc_dir_entry *proc_fs_cifs;
-read_proc_t cifs_txanchor_read;
-static read_proc_t cifsFYI_read;
-static write_proc_t cifsFYI_write;
-static read_proc_t oplockEnabled_read;
-static write_proc_t oplockEnabled_write;
-static read_proc_t lookupFlag_read;
-static write_proc_t lookupFlag_write;
-static read_proc_t traceSMB_read;
-static write_proc_t traceSMB_write;
-static read_proc_t multiuser_mount_read;
-static write_proc_t multiuser_mount_write;
-static read_proc_t security_flags_read;
-static write_proc_t security_flags_write;
-/* static read_proc_t ntlmv2_enabled_read;
-static write_proc_t ntlmv2_enabled_write;
-static read_proc_t packet_signing_enabled_read;
-static write_proc_t packet_signing_enabled_write;*/
-static read_proc_t experimEnabled_read;
-static write_proc_t experimEnabled_write;
-static read_proc_t linuxExtensionsEnabled_read;
-static write_proc_t linuxExtensionsEnabled_write;
+static const struct file_operations cifsFYI_proc_fops;
+static const struct file_operations cifs_oplock_proc_fops;
+static const struct file_operations cifs_lookup_cache_proc_fops;
+static const struct file_operations traceSMB_proc_fops;
+static const struct file_operations cifs_multiuser_mount_proc_fops;
+static const struct file_operations cifs_security_flags_proc_fops;
+static const struct file_operations cifs_experimental_proc_fops;
+static const struct file_operations cifs_linux_ext_proc_fops;
void
cifs_proc_init(void)
{
- struct proc_dir_entry *pde;
-
proc_fs_cifs = proc_mkdir("fs/cifs", NULL);
if (proc_fs_cifs == NULL)
return;
proc_fs_cifs->owner = THIS_MODULE;
- create_proc_read_entry("DebugData", 0, proc_fs_cifs,
- cifs_debug_data_read, NULL);
+ proc_create("DebugData", 0, proc_fs_cifs, &cifs_debug_data_proc_fops);
#ifdef CONFIG_CIFS_STATS
- pde = create_proc_read_entry("Stats", 0, proc_fs_cifs,
- cifs_stats_read, NULL);
- if (pde)
- pde->write_proc = cifs_stats_write;
+ proc_create("Stats", 0, proc_fs_cifs, &cifs_stats_proc_fops);
#endif /* STATS */
- pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs,
- cifsFYI_read, NULL);
- if (pde)
- pde->write_proc = cifsFYI_write;
-
- pde =
- create_proc_read_entry("traceSMB", 0, proc_fs_cifs,
- traceSMB_read, NULL);
- if (pde)
- pde->write_proc = traceSMB_write;
-
- pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs,
- oplockEnabled_read, NULL);
- if (pde)
- pde->write_proc = oplockEnabled_write;
-
- pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs,
- experimEnabled_read, NULL);
- if (pde)
- pde->write_proc = experimEnabled_write;
-
- pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs,
- linuxExtensionsEnabled_read, NULL);
- if (pde)
- pde->write_proc = linuxExtensionsEnabled_write;
-
- pde =
- create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs,
- multiuser_mount_read, NULL);
- if (pde)
- pde->write_proc = multiuser_mount_write;
-
- pde =
- create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs,
- security_flags_read, NULL);
- if (pde)
- pde->write_proc = security_flags_write;
-
- pde =
- create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs,
- lookupFlag_read, NULL);
- if (pde)
- pde->write_proc = lookupFlag_write;
-
-/* pde =
- create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
- ntlmv2_enabled_read, NULL);
- if (pde)
- pde->write_proc = ntlmv2_enabled_write;
-
- pde =
- create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
- packet_signing_enabled_read, NULL);
- if (pde)
- pde->write_proc = packet_signing_enabled_write;*/
+ proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops);
+ proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops);
+ proc_create("OplockEnabled", 0, proc_fs_cifs, &cifs_oplock_proc_fops);
+ proc_create("Experimental", 0, proc_fs_cifs,
+ &cifs_experimental_proc_fops);
+ proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs,
+ &cifs_linux_ext_proc_fops);
+ proc_create("MultiuserMount", 0, proc_fs_cifs,
+ &cifs_multiuser_mount_proc_fops);
+ proc_create("SecurityFlags", 0, proc_fs_cifs,
+ &cifs_security_flags_proc_fops);
+ proc_create("LookupCacheEnabled", 0, proc_fs_cifs,
+ &cifs_lookup_cache_proc_fops);
}
void
@@ -553,39 +416,26 @@ cifs_proc_clean(void)
#endif
remove_proc_entry("MultiuserMount", proc_fs_cifs);
remove_proc_entry("OplockEnabled", proc_fs_cifs);
-/* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
remove_proc_entry("SecurityFlags", proc_fs_cifs);
-/* remove_proc_entry("PacketSigningEnabled", proc_fs_cifs); */
remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
remove_proc_entry("Experimental", proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
remove_proc_entry("fs/cifs", NULL);
}
-static int
-cifsFYI_read(char *page, char **start, off_t off, int count,
- int *eof, void *data)
+static int cifsFYI_proc_show(struct seq_file *m, void *v)
{
- int len;
-
- len = sprintf(page, "%d\n", cifsFYI);
-
- len -= off;
- *start = page + off;
-
- if (len > count)
- len = count;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
+ seq_printf(m, "%d\n", cifsFYI);
+ return 0;
+}
- return len;
+static int cifsFYI_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cifsFYI_proc_show, NULL);
}
-static int
-cifsFYI_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+
+static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
{
char c;
int rc;
@@ -603,30 +453,28 @@ cifsFYI_write(struct file *file, const char __user *buffer,
return count;
}
-static int
-oplockEnabled_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len;
-
- len = sprintf(page, "%d\n", oplockEnabled);
-
- len -= off;
- *start = page + off;
+static const struct file_operations cifsFYI_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = cifsFYI_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = cifsFYI_proc_write,
+};
- if (len > count)
- len = count;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
+static int cifs_oplock_proc_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%d\n", oplockEnabled);
+ return 0;
+}
- return len;
+static int cifs_oplock_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cifs_oplock_proc_show, NULL);
}
-static int
-oplockEnabled_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+
+static ssize_t cifs_oplock_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
{
char c;
int rc;
@@ -642,30 +490,28 @@ oplockEnabled_write(struct file *file, const char __user *buffer,
return count;
}
-static int
-experimEnabled_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len;
-
- len = sprintf(page, "%d\n", experimEnabled);
+static const struct file_operations cifs_oplock_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = cifs_oplock_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = cifs_oplock_proc_write,
+};
- len -= off;
- *start = page + off;
-
- if (len > count)
- len = count;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
+static int cifs_experimental_proc_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%d\n", experimEnabled);
+ return 0;
+}
- return len;
+static int cifs_experimental_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cifs_experimental_proc_show, NULL);
}
-static int
-experimEnabled_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+
+static ssize_t cifs_experimental_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
{
char c;
int rc;
@@ -683,29 +529,28 @@ experimEnabled_write(struct file *file, const char __user *buffer,
return count;
}
-static int
-linuxExtensionsEnabled_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len;
-
- len = sprintf(page, "%d\n", linuxExtEnabled);
- len -= off;
- *start = page + off;
+static const struct file_operations cifs_experimental_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = cifs_experimental_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = cifs_experimental_proc_write,
+};
- if (len > count)
- len = count;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
+static int cifs_linux_ext_proc_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%d\n", linuxExtEnabled);
+ return 0;
+}
- return len;
+static int cifs_linux_ext_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cifs_linux_ext_proc_show, NULL);
}
-static int
-linuxExtensionsEnabled_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+
+static ssize_t cifs_linux_ext_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
{
char c;
int rc;
@@ -721,31 +566,28 @@ linuxExtensionsEnabled_write(struct file *file, const char __user *buffer,
return count;
}
+static const struct file_operations cifs_linux_ext_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = cifs_linux_ext_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = cifs_linux_ext_proc_write,
+};
-static int
-lookupFlag_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int cifs_lookup_cache_proc_show(struct seq_file *m, void *v)
{
- int len;
-
- len = sprintf(page, "%d\n", lookupCacheEnabled);
-
- len -= off;
- *start = page + off;
-
- if (len > count)
- len = count;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
+ seq_printf(m, "%d\n", lookupCacheEnabled);
+ return 0;
+}
- return len;
+static int cifs_lookup_cache_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cifs_lookup_cache_proc_show, NULL);
}
-static int
-lookupFlag_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+
+static ssize_t cifs_lookup_cache_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
{
char c;
int rc;
@@ -760,30 +602,29 @@ lookupFlag_write(struct file *file, const char __user *buffer,
return count;
}
-static int
-traceSMB_read(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- int len;
-
- len = sprintf(page, "%d\n", traceSMB);
-
- len -= off;
- *start = page + off;
- if (len > count)
- len = count;
- else
- *eof = 1;
+static const struct file_operations cifs_lookup_cache_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = cifs_lookup_cache_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = cifs_lookup_cache_proc_write,
+};
- if (len < 0)
- len = 0;
+static int traceSMB_proc_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%d\n", traceSMB);
+ return 0;
+}
- return len;
+static int traceSMB_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, traceSMB_proc_show, NULL);
}
-static int
-traceSMB_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+
+static ssize_t traceSMB_proc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
{
char c;
int rc;
@@ -799,30 +640,28 @@ traceSMB_write(struct file *file, const char __user *buffer,
return count;
}
-static int
-multiuser_mount_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len;
-
- len = sprintf(page, "%d\n", multiuser_mount);
-
- len -= off;
- *start = page + off;
+static const struct file_operations traceSMB_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = traceSMB_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = traceSMB_proc_write,
+};
- if (len > count)
- len = count;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
+static int cifs_multiuser_mount_proc_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "%d\n", multiuser_mount);
+ return 0;
+}
- return len;
+static int cifs_multiuser_mount_proc_open(struct inode *inode, struct file *fh)
+{
+ return single_open(fh, cifs_multiuser_mount_proc_show, NULL);
}
-static int
-multiuser_mount_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+
+static ssize_t cifs_multiuser_mount_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
{
char c;
int rc;
@@ -838,30 +677,28 @@ multiuser_mount_write(struct file *file, const char __user *buffer,
return count;
}
-static int
-security_flags_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len;
-
- len = sprintf(page, "0x%x\n", extended_security);
-
- len -= off;
- *start = page + off;
+static const struct file_operations cifs_multiuser_mount_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = cifs_multiuser_mount_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = cifs_multiuser_mount_proc_write,
+};
- if (len > count)
- len = count;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
+static int cifs_security_flags_proc_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "0x%x\n", extended_security);
+ return 0;
+}
- return len;
+static int cifs_security_flags_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cifs_security_flags_proc_show, NULL);
}
-static int
-security_flags_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+
+static ssize_t cifs_security_flags_proc_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
{
unsigned int flags;
char flags_string[12];
@@ -917,6 +754,15 @@ security_flags_write(struct file *file, const char __user *buffer,
/* BB should we turn on MAY flags for other MUST options? */
return count;
}
+
+static const struct file_operations cifs_security_flags_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = cifs_security_flags_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = cifs_security_flags_proc_write,
+};
#else
inline void cifs_proc_init(void)
{
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index d82374c9e32..d2c8eef84f3 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -226,7 +226,7 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
int err;
mntget(newmnt);
- err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist);
+ err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags, mntlist);
switch (err) {
case 0:
path_put(&nd->path);
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c
index 7013aaff6ae..fcee9298b62 100644
--- a/fs/cifs/cifs_spnego.c
+++ b/fs/cifs/cifs_spnego.c
@@ -66,11 +66,28 @@ 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_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 */
+/* length of longest version string e.g. strlen("ver=0xFF") */
+#define MAX_VER_STR_LEN 8
+
+/* length of longest security mechanism name, eg in future could have
+ * strlen(";sec=ntlmsspi") */
+#define MAX_MECH_STR_LEN 13
+
+/* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */
+#define MAX_IPV6_ADDR_LEN 42
+
+/* strlen of "host=" */
+#define HOST_KEY_LEN 5
+
+/* strlen of ";ip4=" or ";ip6=" */
+#define IP_KEY_LEN 5
+
+/* strlen of ";uid=0x" */
+#define UID_KEY_LEN 7
+
+/* strlen of ";user=" */
+#define USER_KEY_LEN 6
+
/* get a key struct with a SPNEGO security blob, suitable for session setup */
struct key *
cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
@@ -81,11 +98,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 +
+ HOST_KEY_LEN + strlen(hostname) +
+ IP_KEY_LEN + MAX_IPV6_ADDR_LEN +
+ MAX_MECH_STR_LEN +
+ UID_KEY_LEN + (sizeof(uid_t) * 2) +
+ USER_KEY_LEN + strlen(sesInfo->userName) + 1;
+
spnego_key = ERR_PTR(-ENOMEM);
description = kzalloc(desc_len, GFP_KERNEL);
if (description == NULL)
@@ -110,9 +131,11 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
dp = description + strlen(description);
- /* for now, only sec=krb5 is valid */
+ /* for now, only sec=krb5 and sec=mskrb5 are valid */
if (server->secType == Kerberos)
sprintf(dp, ";sec=krb5");
+ else if (server->secType == MSKerberos)
+ sprintf(dp, ";sec=mskrb5");
else
goto out;
diff --git a/fs/cifs/cifs_spnego.h b/fs/cifs/cifs_spnego.h
index 05a34b17a1a..e4041ec4d71 100644
--- a/fs/cifs/cifs_spnego.h
+++ b/fs/cifs/cifs_spnego.h
@@ -23,7 +23,7 @@
#ifndef _CIFS_SPNEGO_H
#define _CIFS_SPNEGO_H
-#define CIFS_SPNEGO_UPCALL_VERSION 1
+#define CIFS_SPNEGO_UPCALL_VERSION 2
/*
* The version field should always be set to CIFS_SPNEGO_UPCALL_VERSION.
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 0e9fc2ba90e..57ecdc83c26 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -56,7 +56,7 @@ int match_sid(struct cifs_sid *ctsid)
struct cifs_sid *cwsid;
if (!ctsid)
- return (-1);
+ return -1;
for (i = 0; i < NUM_WK_SIDS; ++i) {
cwsid = &(wksidarr[i].cifssid);
@@ -87,11 +87,11 @@ int match_sid(struct cifs_sid *ctsid)
}
cFYI(1, ("matching sid: %s\n", wksidarr[i].sidname));
- return (0); /* sids compare/match */
+ return 0; /* sids compare/match */
}
cFYI(1, ("No matching sid"));
- return (-1);
+ return -1;
}
/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
@@ -102,16 +102,16 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
int num_subauth, num_sat, num_saw;
if ((!ctsid) || (!cwsid))
- return (0);
+ return 0;
/* compare the revision */
if (ctsid->revision != cwsid->revision)
- return (0);
+ return 0;
/* compare all of the six auth values */
for (i = 0; i < 6; ++i) {
if (ctsid->authority[i] != cwsid->authority[i])
- return (0);
+ return 0;
}
/* compare all of the subauth values if any */
@@ -121,11 +121,11 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
if (num_subauth) {
for (i = 0; i < num_subauth; ++i) {
if (ctsid->sub_auth[i] != cwsid->sub_auth[i])
- return (0);
+ return 0;
}
}
- return (1); /* sids compare/match */
+ return 1; /* sids compare/match */
}
@@ -169,8 +169,7 @@ static void copy_sec_desc(const struct cifs_ntsd *pntsd,
for (i = 0; i < 6; i++)
ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
for (i = 0; i < 5; i++)
- ngroup_sid_ptr->sub_auth[i] =
- cpu_to_le32(group_sid_ptr->sub_auth[i]);
+ ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
return;
}
@@ -285,7 +284,7 @@ static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
pntace->size = cpu_to_le16(size);
- return (size);
+ return size;
}
@@ -426,7 +425,7 @@ static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
pndacl->num_aces = cpu_to_le32(3);
- return (0);
+ return 0;
}
@@ -510,7 +509,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
sizeof(struct cifs_sid)); */
- return (0);
+ return 0;
}
@@ -527,7 +526,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
- return (-EIO);
+ return -EIO;
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
le32_to_cpu(pntsd->osidoffset));
@@ -550,7 +549,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
/* copy security descriptor control portion and owner and group sid */
copy_sec_desc(pntsd, pnntsd, sidsoffset);
- return (rc);
+ return rc;
}
@@ -629,11 +628,11 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
cFYI(DBG2, ("set ACL for %s from mode 0x%x", path, inode->i_mode));
if (!inode)
- return (rc);
+ return rc;
sb = inode->i_sb;
if (sb == NULL)
- return (rc);
+ return rc;
cifs_sb = CIFS_SB(sb);
xid = GetXid();
@@ -652,7 +651,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
if (rc != 0) {
cERROR(1, ("Unable to open file to set ACL"));
FreeXid(xid);
- return (rc);
+ return rc;
}
}
@@ -665,7 +664,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
FreeXid(xid);
- return (rc);
+ return rc;
}
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
@@ -715,7 +714,7 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
if (!pnntsd) {
cERROR(1, ("Unable to allocate security descriptor"));
kfree(pntsd);
- return (-ENOMEM);
+ return -ENOMEM;
}
rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
@@ -732,6 +731,6 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
kfree(pntsd);
}
- return (rc);
+ return rc;
}
#endif /* CONFIG_CIFS_EXPERIMENTAL */
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 4ff8939c6cc..bd5f13d3845 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -294,6 +294,7 @@ void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
if (extended_security & CIFSSEC_MAY_PLNTXT) {
+ memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
memcpy(lnm_session_key, password_with_pad,
CIFS_ENCPWD_SIZE);
return;
@@ -310,9 +311,8 @@ void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
utf8 and other multibyte codepages each need their own strupper
function since a byte at a time will ont work. */
- for (i = 0; i < CIFS_ENCPWD_SIZE; i++) {
+ for (i = 0; i < CIFS_ENCPWD_SIZE; i++)
password_with_pad[i] = toupper(password_with_pad[i]);
- }
SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key);
/* clear password before we return/free memory */
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 22857c639df..25ecbd5b040 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -175,6 +175,8 @@ out_no_root:
if (inode)
iput(inode);
+ cifs_umount(sb, cifs_sb);
+
out_mount_failed:
if (cifs_sb) {
#ifdef CONFIG_CIFS_DFS_UPCALL
@@ -267,7 +269,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
-static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd)
+static int cifs_permission(struct inode *inode, int mask)
{
struct cifs_sb_info *cifs_sb;
@@ -766,7 +768,7 @@ const struct file_operations cifs_dir_ops = {
};
static void
-cifs_init_once(struct kmem_cache *cachep, void *inode)
+cifs_init_once(void *inode)
{
struct cifsInodeInfo *cifsi = inode;
@@ -930,36 +932,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 +967,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 +999,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);
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 25a6cbd1552..f7b4a5cd837 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -41,7 +41,7 @@ extern int cifs_create(struct inode *, struct dentry *, int,
struct nameidata *);
extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
struct nameidata *);
-extern int cifs_unlink(struct inode *, struct dentry *);
+extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
extern int cifs_mknod(struct inode *, struct dentry *, int, dev_t);
extern int cifs_mkdir(struct inode *, struct dentry *, int);
@@ -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 */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 9cfcf326ead..0d22479d99b 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -27,7 +27,7 @@
#define MAX_SES_INFO 2
#define MAX_TCON_INFO 4
-#define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1
+#define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1)
#define MAX_SERVER_SIZE 15
#define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */
#define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null
@@ -80,7 +80,8 @@ enum securityEnum {
NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */
RawNTLMSSP, /* NTLMSSP without SPNEGO */
NTLMSSP, /* NTLMSSP via SPNEGO */
- Kerberos /* Kerberos via SPNEGO */
+ Kerberos, /* Kerberos via SPNEGO */
+ MSKerberos, /* MS Kerberos via SPNEGO */
};
enum protocolEnum {
@@ -308,6 +309,7 @@ struct cifs_search_info {
__u32 resume_key;
char *ntwrk_buf_start;
char *srch_entries_start;
+ char *last_entry;
char *presume_name;
unsigned int resume_name_len;
bool endOfSearch:1;
@@ -537,8 +539,8 @@ require use of the stronger protocol */
#endif /* WEAK_PW_HASH */
#define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */
-#define CIFSSEC_DEF CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2
-#define CIFSSEC_MAX CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2
+#define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2)
+#define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2)
#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5)
/*
*****************************************************************
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 0f327c224da..d2a073edd1b 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -31,7 +31,7 @@
#else
#define CIFS_PROT 0
#endif
-#define POSIX_PROT CIFS_PROT+1
+#define POSIX_PROT (CIFS_PROT+1)
#define BAD_PROT 0xFFFF
/* SMB command codes */
@@ -262,7 +262,7 @@
*/
#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 */
@@ -341,7 +341,7 @@
#define CREATE_COMPLETE_IF_OPLK 0x00000100 /* should be zero */
#define CREATE_NO_EA_KNOWLEDGE 0x00000200
#define CREATE_EIGHT_DOT_THREE 0x00000400 /* doc says this is obsolete
- "open for recovery" flag - should
+ "open for recovery" flag should
be zero in any case */
#define CREATE_OPEN_FOR_RECOVERY 0x00000400
#define CREATE_RANDOM_ACCESS 0x00000800
@@ -414,8 +414,8 @@ struct smb_hdr {
__u8 WordCount;
} __attribute__((packed));
/* given a pointer to an smb_hdr retrieve the value of byte count */
-#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount)))
-#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount)))
+#define BCC(smb_var) (*(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount)))
+#define BCC_LE(smb_var) (*(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount)))
/* given a pointer to an smb_hdr retrieve the pointer to the byte area */
#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount) + 2)
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b9f5e935f82..0cff7fe986e 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -172,12 +172,15 @@ 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);
+extern int CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
+ bool delete_file, __u16 fid, __u32 pid_of_opener);
#if 0
extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon,
char *fileName, __u16 dos_attributes,
@@ -191,9 +194,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);
@@ -217,7 +231,7 @@ extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
const struct nls_table *nls_codepage,
int remap_special_chars);
extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
- int netfid, char *target_name,
+ int netfid, const char *target_name,
const struct nls_table *nls_codepage,
int remap_special_chars);
extern int CIFSCreateHardLink(const int xid,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 4511b708f0f..6f4ffe15d68 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -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
@@ -686,11 +685,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
SecurityBlob,
count - 16,
&server->secType);
- if (rc == 1) {
+ if (rc == 1)
rc = 0;
- } else {
+ else
rc = -EINVAL;
- }
}
} else
server->capabilities &= ~CAP_EXTENDED_SECURITY;
@@ -2019,7 +2017,7 @@ renameRetry:
}
int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
- int netfid, char *target_name,
+ int netfid, const char *target_name,
const struct nls_table *nls_codepage, int remap)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
@@ -2073,7 +2071,7 @@ int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
remap);
}
rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
- count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
+ count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
byte_count += count;
pSMB->DataCount = cpu_to_le16(count);
pSMB->TotalDataCount = pSMB->DataCount;
@@ -3616,6 +3614,8 @@ findFirstRetry:
/* BB remember to free buffer if error BB */
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc == 0) {
+ unsigned int lnoff;
+
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
psrch_inf->unicode = true;
else
@@ -3638,6 +3638,17 @@ findFirstRetry:
le16_to_cpu(parms->SearchCount);
psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
psrch_inf->entries_in_buffer;
+ lnoff = le16_to_cpu(parms->LastNameOffset);
+ if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
+ lnoff) {
+ cERROR(1, ("ignoring corrupt resume name"));
+ psrch_inf->last_entry = NULL;
+ return rc;
+ }
+
+ psrch_inf->last_entry = psrch_inf->srch_entries_start +
+ lnoff;
+
*pnetfid = parms->SearchHandle;
} else {
cifs_buf_release(pSMB);
@@ -3727,6 +3738,8 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc == 0) {
+ unsigned int lnoff;
+
/* BB fixme add lock for file (srch_info) struct here */
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
psrch_inf->unicode = true;
@@ -3753,6 +3766,16 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
le16_to_cpu(parms->SearchCount);
psrch_inf->index_of_last_entry +=
psrch_inf->entries_in_buffer;
+ lnoff = le16_to_cpu(parms->LastNameOffset);
+ if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
+ lnoff) {
+ cERROR(1, ("ignoring corrupt resume name"));
+ psrch_inf->last_entry = NULL;
+ return rc;
+ } else
+ psrch_inf->last_entry =
+ psrch_inf->srch_entries_start + lnoff;
+
/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
@@ -3914,7 +3937,10 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
bool is_unicode;
struct dfs_referral_level_3 *ref;
- is_unicode = pSMBr->hdr.Flags2 & SMBFLG2_UNICODE;
+ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+ is_unicode = true;
+ else
+ is_unicode = false;
*num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
if (*num_of_nodes < 1) {
@@ -4814,8 +4840,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;
@@ -4828,11 +4854,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;
@@ -4878,11 +4901,66 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
return rc;
}
+int
+CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
+ bool delete_file, __u16 fid, __u32 pid_of_opener)
+{
+ struct smb_com_transaction2_sfi_req *pSMB = NULL;
+ char *data_offset;
+ int rc = 0;
+ __u16 params, param_offset, offset, byte_count, count;
+
+ cFYI(1, ("Set File Disposition (via SetFileInfo)"));
+ rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+ if (rc)
+ return rc;
+
+ 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;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+ offset = param_offset + params;
+
+ data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+
+ count = 1;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ /* BB find max SMB PDU from sess */
+ pSMB->MaxDataCount = cpu_to_le16(1000);
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+ byte_count = 3 /* pad */ + params + count;
+ pSMB->DataCount = cpu_to_le16(count);
+ pSMB->ParameterCount = cpu_to_le16(params);
+ pSMB->TotalDataCount = pSMB->DataCount;
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->ParameterOffset = cpu_to_le16(param_offset);
+ pSMB->DataOffset = cpu_to_le16(offset);
+ pSMB->Fid = fid;
+ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += byte_count;
+ pSMB->ByteCount = cpu_to_le16(byte_count);
+ *data_offset = delete_file ? 1 : 0;
+ rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
+ if (rc)
+ cFYI(1, ("Send error in SetFileDisposition = %d", rc));
+
+ return rc;
+}
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;
@@ -5011,10 +5089,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;
@@ -5023,6 +5100,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:
@@ -5078,16 +5156,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))
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index e8fa46c7cff..4c13bcdb92a 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -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);
@@ -455,7 +451,7 @@ incomplete_rcv:
/* Note that FC 1001 length is big endian on the wire,
but we convert it here so it is always manipulated
as host byte order */
- pdu_length = ntohl(smb_buffer->smb_buf_length);
+ pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length);
smb_buffer->smb_buf_length = pdu_length;
cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
@@ -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);
@@ -1461,6 +1456,39 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
return rc;
}
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static struct lock_class_key cifs_key[2];
+static struct lock_class_key cifs_slock_key[2];
+
+static inline void
+cifs_reclassify_socket4(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+ BUG_ON(sock_owned_by_user(sk));
+ sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS",
+ &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]);
+}
+
+static inline void
+cifs_reclassify_socket6(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+ BUG_ON(sock_owned_by_user(sk));
+ sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS",
+ &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]);
+}
+#else
+static inline void
+cifs_reclassify_socket4(struct socket *sock)
+{
+}
+
+static inline void
+cifs_reclassify_socket6(struct socket *sock)
+{
+}
+#endif
+
/* See RFC1001 section 14 on representation of Netbios names */
static void rfc1002mangle(char *target, char *source, unsigned int length)
{
@@ -1495,6 +1523,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
/* BB other socket options to set KEEPALIVE, NODELAY? */
cFYI(1, ("Socket created"));
(*csocket)->sk->sk_allocation = GFP_NOFS;
+ cifs_reclassify_socket4(*csocket);
}
}
@@ -1627,6 +1656,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
/* BB other socket options to set KEEPALIVE, NODELAY? */
cFYI(1, ("ipv6 Socket created"));
(*csocket)->sk->sk_allocation = GFP_NOFS;
+ cifs_reclassify_socket6(*csocket);
}
}
@@ -3568,19 +3598,21 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
char ntlm_session_key[CIFS_SESS_KEY_SIZE];
bool ntlmv2_flag = false;
int first_time = 0;
+ struct TCP_Server_Info *server = pSesInfo->server;
/* what if server changes its buffer size after dropping the session? */
- if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
+ if (server->maxBuf == 0) /* no need to send on reconnect */ {
rc = CIFSSMBNegotiate(xid, pSesInfo);
- if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
+ if (rc == -EAGAIN) {
+ /* retry only once on 1st time connection */
rc = CIFSSMBNegotiate(xid, pSesInfo);
if (rc == -EAGAIN)
rc = -EHOSTDOWN;
}
if (rc == 0) {
spin_lock(&GlobalMid_Lock);
- if (pSesInfo->server->tcpStatus != CifsExiting)
- pSesInfo->server->tcpStatus = CifsGood;
+ if (server->tcpStatus != CifsExiting)
+ server->tcpStatus = CifsGood;
else
rc = -EHOSTDOWN;
spin_unlock(&GlobalMid_Lock);
@@ -3588,97 +3620,90 @@ 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 = 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",
+ server->secMode, server->capabilities, server->timeAdj));
+
+ if (experimEnabled < 2)
+ rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info);
+ else if (extended_security
+ && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+ && (server->secType == NTLMSSP)) {
+ rc = -EOPNOTSUPP;
+ } else if (extended_security
+ && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+ && (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,
+ server->cryptKey,
+ ntlm_session_key);
+
+ if (first_time)
+ cifs_calculate_mac_key(
+ &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, server->cryptKey,
+ ntlm_session_key);
- if (first_time)
- cifs_calculate_mac_key(
- &pSesInfo->server->mac_signing_key,
- ntlm_session_key, pSesInfo->password);
+ if (first_time)
+ cifs_calculate_mac_key(&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;
}
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index fb69c1fa85c..e962e75e6f7 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,
/* 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,
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index f730ef35499..1e0c1bd8f2e 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -29,38 +29,13 @@
#include "cifsproto.h"
#include "cifs_debug.h"
-static int dns_resolver_instantiate(struct key *key, const void *data,
- size_t datalen)
-{
- int rc = 0;
- char *ip;
-
- ip = kmalloc(datalen+1, GFP_KERNEL);
- if (!ip)
- return -ENOMEM;
-
- memcpy(ip, data, datalen);
- ip[datalen] = '\0';
-
- rcu_assign_pointer(key->payload.data, ip);
-
- return rc;
-}
-
-struct key_type key_type_dns_resolver = {
- .name = "dns_resolver",
- .def_datalen = sizeof(struct in_addr),
- .describe = user_describe,
- .instantiate = dns_resolver_instantiate,
- .match = user_match,
-};
-
/* Checks if supplied name is IP address
* returns:
* 1 - name is IP
* 0 - name is not IP
*/
-static int is_ip(const char *name)
+static int
+is_ip(const char *name)
{
int rc;
struct sockaddr_in sin_server;
@@ -82,6 +57,47 @@ static int is_ip(const char *name)
return 0;
}
+static int
+dns_resolver_instantiate(struct key *key, const void *data,
+ size_t datalen)
+{
+ int rc = 0;
+ char *ip;
+
+ ip = kmalloc(datalen + 1, GFP_KERNEL);
+ if (!ip)
+ return -ENOMEM;
+
+ memcpy(ip, data, datalen);
+ ip[datalen] = '\0';
+
+ /* make sure this looks like an address */
+ if (!is_ip((const char *) ip)) {
+ kfree(ip);
+ return -EINVAL;
+ }
+
+ key->type_data.x[0] = datalen;
+ rcu_assign_pointer(key->payload.data, ip);
+
+ return rc;
+}
+
+static void
+dns_resolver_destroy(struct key *key)
+{
+ kfree(key->payload.data);
+}
+
+struct key_type key_type_dns_resolver = {
+ .name = "dns_resolver",
+ .def_datalen = sizeof(struct in_addr),
+ .describe = user_describe,
+ .instantiate = dns_resolver_instantiate,
+ .destroy = dns_resolver_destroy,
+ .match = user_match,
+};
+
/* Resolves server name to ip address.
* input:
* unc - server UNC
@@ -133,6 +149,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
rkey = request_key(&key_type_dns_resolver, name, "");
if (!IS_ERR(rkey)) {
+ len = rkey->type_data.x[0];
data = rkey->payload.data;
} else {
cERROR(1, ("%s: unable to resolve: %s", __func__, name));
@@ -141,11 +158,9 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
skip_upcall:
if (data) {
- len = strlen(data);
- *ip_addr = kmalloc(len+1, GFP_KERNEL);
+ *ip_addr = kmalloc(len + 1, GFP_KERNEL);
if (*ip_addr) {
- memcpy(*ip_addr, data, len);
- (*ip_addr)[len] = '\0';
+ memcpy(*ip_addr, data, len + 1);
if (!IS_ERR(rkey))
cFYI(1, ("%s: resolved: %s to %s", __func__,
name,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 0aac824371a..c4a8a060512 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -107,7 +107,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
/* want handles we can use to read with first
in the list so we do not have to walk the
- list to search for one in prepare_write */
+ list to search for one in write_begin */
if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
list_add_tail(&pCifsFile->flist,
&pCifsInode->openFileList);
@@ -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 */
}
}
@@ -832,6 +833,10 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
return -EBADF;
open_file = (struct cifsFileInfo *) file->private_data;
+ rc = generic_write_checks(file, poffset, &write_size, 0);
+ if (rc)
+ return rc;
+
xid = GetXid();
if (*poffset > file->f_path.dentry->d_inode->i_size)
@@ -910,7 +915,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
}
static ssize_t cifs_write(struct file *file, const char *write_data,
- size_t write_size, loff_t *poffset)
+ size_t write_size, loff_t *poffset)
{
int rc = 0;
unsigned int bytes_written = 0;
@@ -1060,6 +1065,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
{
struct cifsFileInfo *open_file;
+ bool any_available = false;
int rc;
/* Having a null inode here (because mapping->host was set to zero by
@@ -1075,8 +1081,10 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
read_lock(&GlobalSMBSeslock);
refind_writable:
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
- if (open_file->closePend)
+ if (open_file->closePend ||
+ (!any_available && open_file->pid != current->tgid))
continue;
+
if (open_file->pfile &&
((open_file->pfile->f_flags & O_RDWR) ||
(open_file->pfile->f_flags & O_WRONLY))) {
@@ -1126,6 +1134,11 @@ refind_writable:
of the loop here. */
}
}
+ /* couldn't find useable FH with same pid, try any available */
+ if (!any_available) {
+ any_available = true;
+ goto refind_writable;
+ }
read_unlock(&GlobalSMBSeslock);
return NULL;
}
@@ -1280,7 +1293,7 @@ retry:
if (first < 0)
lock_page(page);
- else if (TestSetPageLocked(page))
+ else if (!trylock_page(page))
break;
if (unlikely(page->mapping != mapping)) {
@@ -1442,49 +1455,52 @@ static int cifs_writepage(struct page *page, struct writeback_control *wbc)
return rc;
}
-static int cifs_commit_write(struct file *file, struct page *page,
- unsigned offset, unsigned to)
+static int cifs_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata)
{
- int xid;
- int rc = 0;
- struct inode *inode = page->mapping->host;
- loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
- char *page_data;
+ int rc;
+ struct inode *inode = mapping->host;
- xid = GetXid();
- cFYI(1, ("commit write for page %p up to position %lld for %d",
- page, position, to));
- spin_lock(&inode->i_lock);
- if (position > inode->i_size)
- i_size_write(inode, position);
+ cFYI(1, ("write_end for page %p from pos %lld with %d bytes",
+ page, pos, copied));
+
+ if (!PageUptodate(page) && copied == PAGE_CACHE_SIZE)
+ SetPageUptodate(page);
- spin_unlock(&inode->i_lock);
if (!PageUptodate(page)) {
- position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
- /* can not rely on (or let) writepage write this data */
- if (to < offset) {
- cFYI(1, ("Illegal offsets, can not copy from %d to %d",
- offset, to));
- FreeXid(xid);
- return rc;
- }
+ char *page_data;
+ unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
+ int xid;
+
+ xid = GetXid();
/* this is probably better than directly calling
partialpage_write since in this function the file handle is
known which we might as well leverage */
/* BB check if anything else missing out of ppw
such as updating last write time */
page_data = kmap(page);
- rc = cifs_write(file, page_data + offset, to-offset,
- &position);
- if (rc > 0)
- rc = 0;
- /* else if (rc < 0) should we set writebehind rc? */
+ rc = cifs_write(file, page_data + offset, copied, &pos);
+ /* if (rc < 0) should we set writebehind rc? */
kunmap(page);
+
+ FreeXid(xid);
} else {
+ rc = copied;
+ pos += copied;
set_page_dirty(page);
}
- FreeXid(xid);
+ if (rc > 0) {
+ spin_lock(&inode->i_lock);
+ if (pos > inode->i_size)
+ i_size_write(inode, pos);
+ spin_unlock(&inode->i_lock);
+ }
+
+ unlock_page(page);
+ page_cache_release(page);
+
return rc;
}
@@ -2030,49 +2046,44 @@ bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
return true;
}
-static int cifs_prepare_write(struct file *file, struct page *page,
- unsigned from, unsigned to)
+static int cifs_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata)
{
- int rc = 0;
- loff_t i_size;
- loff_t offset;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+ loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
+
+ cFYI(1, ("write_begin from %lld len %d", (long long)pos, len));
- cFYI(1, ("prepare write for page %p from %d to %d", page, from, to));
- if (PageUptodate(page))
+ *pagep = __grab_cache_page(mapping, index);
+ if (!*pagep)
+ return -ENOMEM;
+
+ if (PageUptodate(*pagep))
return 0;
/* If we are writing a full page it will be up to date,
no need to read from the server */
- if ((to == PAGE_CACHE_SIZE) && (from == 0)) {
- SetPageUptodate(page);
+ if (len == PAGE_CACHE_SIZE && flags & AOP_FLAG_UNINTERRUPTIBLE)
return 0;
- }
- offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
- i_size = i_size_read(page->mapping->host);
+ if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
+ int rc;
- if ((offset >= i_size) ||
- ((from == 0) && (offset + to) >= i_size)) {
- /*
- * We don't need to read data beyond the end of the file.
- * zero it, and set the page uptodate
- */
- simple_prepare_write(file, page, from, to);
- SetPageUptodate(page);
- } else if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
/* might as well read a page, it is fast enough */
- rc = cifs_readpage_worker(file, page, &offset);
+ rc = cifs_readpage_worker(file, *pagep, &offset);
+
+ /* we do not need to pass errors back
+ e.g. if we do not have read access to the file
+ because cifs_write_end will attempt synchronous writes
+ -- shaggy */
} else {
/* we could try using another file handle if there is one -
but how would we lock it to prevent close of that handle
racing with this read? In any case
- this will be written out by commit_write so is fine */
+ this will be written out by write_end so is fine */
}
- /* we do not need to pass errors back
- e.g. if we do not have read access to the file
- because cifs_commit_write will do the right thing. -- shaggy */
-
return 0;
}
@@ -2081,8 +2092,8 @@ const struct address_space_operations cifs_addr_ops = {
.readpages = cifs_readpages,
.writepage = cifs_writepage,
.writepages = cifs_writepages,
- .prepare_write = cifs_prepare_write,
- .commit_write = cifs_commit_write,
+ .write_begin = cifs_write_begin,
+ .write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers,
/* .sync_page = cifs_sync_page, */
/* .direct_IO = */
@@ -2097,8 +2108,8 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
.readpage = cifs_readpage,
.writepage = cifs_writepage,
.writepages = cifs_writepages,
- .prepare_write = cifs_prepare_write,
- .commit_write = cifs_commit_write,
+ .write_begin = cifs_write_begin,
+ .write_end = cifs_write_end,
.set_page_dirty = __set_page_dirty_nobuffers,
/* .sync_page = cifs_sync_page, */
/* .direct_IO = */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 2e904bd111c..a8c833345fc 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -546,7 +546,8 @@ int cifs_get_inode_info(struct inode **pinode,
if ((inode->i_mode & S_IWUGO) == 0 &&
(attr & ATTR_READONLY) == 0)
inode->i_mode |= (S_IWUGO & default_mode);
- inode->i_mode &= ~S_IFMT;
+
+ inode->i_mode &= ~S_IFMT;
}
/* clear write bits if ATTR_READONLY is set */
if (attr & ATTR_READONLY)
@@ -649,6 +650,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
inode->i_fop = &simple_dir_operations;
inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid;
+ } else if (rc) {
_FreeXid(xid);
iget_failed(inode);
return ERR_PTR(rc);
@@ -663,40 +665,201 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
return inode;
}
-int cifs_unlink(struct inode *inode, struct dentry *direntry)
+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 == 0) {
+ cifsInode->cifsAttrs = dosattr;
+ goto out;
+ } else 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 (!rc)
+ cifsInode->cifsAttrs = dosattr;
+
+ if (open_file == NULL)
+ CIFSSMBClose(xid, pTcon, netfid);
+ else
+ atomic_dec(&open_file->wrtPending);
+out:
+ return rc;
+}
+
+/*
+ * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
+ * and rename it to a random name that hopefully won't conflict with
+ * anything else.
+ */
+static int
+cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid)
+{
+ int oplock = 0;
+ int rc;
+ __u16 netfid;
+ struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct cifsTconInfo *tcon = cifs_sb->tcon;
+ __u32 dosattr;
+ FILE_BASIC_INFO *info_buf;
+
+ rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
+ DELETE|FILE_WRITE_ATTRIBUTES,
+ CREATE_NOT_DIR|CREATE_DELETE_ON_CLOSE,
+ &netfid, &oplock, NULL, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (rc != 0)
+ goto out;
+
+ /* set ATTR_HIDDEN and clear ATTR_READONLY */
+ cifsInode = CIFS_I(inode);
+ dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
+ if (dosattr == 0)
+ dosattr |= ATTR_NORMAL;
+ dosattr |= ATTR_HIDDEN;
+
+ info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
+ if (info_buf == NULL) {
+ rc = -ENOMEM;
+ goto out_close;
+ }
+ info_buf->Attributes = cpu_to_le32(dosattr);
+ rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, current->tgid);
+ kfree(info_buf);
+ if (rc != 0)
+ goto out_close;
+ cifsInode->cifsAttrs = dosattr;
+
+ /* silly-rename the file */
+ CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+ /* set DELETE_ON_CLOSE */
+ rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid);
+
+ /*
+ * some samba versions return -ENOENT when we try to set the file
+ * disposition here. Likely a samba bug, but work around it for now
+ */
+ if (rc == -ENOENT)
+ rc = 0;
+
+out_close:
+ CIFSSMBClose(xid, tcon, netfid);
+out:
+ return rc;
+}
+
+int cifs_unlink(struct inode *dir, struct dentry *dentry)
{
int rc = 0;
int xid;
- struct cifs_sb_info *cifs_sb;
- struct cifsTconInfo *pTcon;
char *full_path = NULL;
- struct cifsInodeInfo *cifsInode;
- FILE_BASIC_INFO *pinfo_buf;
+ struct inode *inode = dentry->d_inode;
+ struct cifsInodeInfo *cifsInode = CIFS_I(inode);
+ struct super_block *sb = dir->i_sb;
+ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct cifsTconInfo *tcon = cifs_sb->tcon;
+ struct iattr *attrs = NULL;
+ __u32 dosattr = 0, origattr = 0;
- cFYI(1, ("cifs_unlink, inode = 0x%p", inode));
+ cFYI(1, ("cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry));
xid = GetXid();
- if (inode)
- cifs_sb = CIFS_SB(inode->i_sb);
- else
- cifs_sb = CIFS_SB(direntry->d_sb);
- pTcon = cifs_sb->tcon;
-
- /* Unlink can be called from rename so we can not grab the sem here
- since we deadlock otherwise */
-/* mutex_lock(&direntry->d_sb->s_vfs_rename_mutex);*/
- full_path = build_path_from_dentry(direntry);
-/* mutex_unlock(&direntry->d_sb->s_vfs_rename_mutex);*/
+ /* Unlink can be called from rename so we can not take the
+ * sb->s_vfs_rename_mutex here */
+ full_path = build_path_from_dentry(dentry);
if (full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
- if ((pTcon->ses->capabilities & CAP_UNIX) &&
+ if ((tcon->ses->capabilities & CAP_UNIX) &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
- le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
- rc = CIFSPOSIXDelFile(xid, pTcon, full_path,
+ le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+ rc = CIFSPOSIXDelFile(xid, tcon, full_path,
SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1, ("posix del rc %d", rc));
@@ -704,124 +867,60 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
goto psx_del_no_retry;
}
- rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
+retry_std_delete:
+ rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+
psx_del_no_retry:
if (!rc) {
- if (direntry->d_inode)
- drop_nlink(direntry->d_inode);
+ if (inode)
+ drop_nlink(inode);
} else if (rc == -ENOENT) {
- d_drop(direntry);
+ d_drop(dentry);
} else if (rc == -ETXTBSY) {
- int oplock = 0;
- __u16 netfid;
-
- rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
- CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
- &netfid, &oplock, NULL, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc == 0) {
- CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- CIFSSMBClose(xid, pTcon, netfid);
- if (direntry->d_inode)
- drop_nlink(direntry->d_inode);
+ rc = cifs_rename_pending_delete(full_path, inode, xid);
+ if (rc == 0)
+ drop_nlink(inode);
+ } else if (rc == -EACCES && dosattr == 0) {
+ attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
+ if (attrs == NULL) {
+ rc = -ENOMEM;
+ goto out_reval;
}
- } else if (rc == -EACCES) {
- /* try only if r/o attribute set in local lookup data? */
- pinfo_buf = kzalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
- if (pinfo_buf) {
- /* 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,
- pinfo_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;
- /* rc = CIFSSMBSetAttrLegacy(xid, pTcon,
- full_path,
- (__u16)ATTR_NORMAL,
- cifs_sb->local_nls);
- For some strange reason it seems that NT4 eats the
- old setattr call without actually setting the
- attributes so on to the third attempted workaround
- */
-
- /* BB 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, 0,
- &netfid, &oplock, NULL,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc == 0) {
- rc = CIFSSMBSetFileTimes(xid, pTcon,
- pinfo_buf,
- netfid);
- CIFSSMBClose(xid, pTcon, netfid);
- }
- }
- kfree(pinfo_buf);
- }
- if (rc == 0) {
- rc = CIFSSMBDelFile(xid, pTcon, full_path,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (!rc) {
- if (direntry->d_inode)
- drop_nlink(direntry->d_inode);
- } else if (rc == -ETXTBSY) {
- int oplock = 0;
- __u16 netfid;
-
- rc = CIFSSMBOpen(xid, pTcon, full_path,
- FILE_OPEN, DELETE,
- CREATE_NOT_DIR |
- CREATE_DELETE_ON_CLOSE,
- &netfid, &oplock, NULL,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc == 0) {
- CIFSSMBRenameOpenFile(xid, pTcon,
- netfid, NULL,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- CIFSSMBClose(xid, pTcon, netfid);
- if (direntry->d_inode)
- drop_nlink(direntry->d_inode);
- }
- /* BB if rc = -ETXTBUSY goto the rename logic BB */
- }
- }
- }
- if (direntry->d_inode) {
- cifsInode = CIFS_I(direntry->d_inode);
- cifsInode->time = 0; /* will force revalidate to get info
- when needed */
- direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
+ /* try to reset dos attributes */
+ origattr = cifsInode->cifsAttrs;
+ if (origattr == 0)
+ origattr |= ATTR_NORMAL;
+ dosattr = origattr & ~ATTR_READONLY;
+ if (dosattr == 0)
+ dosattr |= ATTR_NORMAL;
+ dosattr |= ATTR_HIDDEN;
+
+ rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
+ if (rc != 0)
+ goto out_reval;
+
+ goto retry_std_delete;
}
+
+ /* undo the setattr if we errored out and it's needed */
+ if (rc != 0 && dosattr != 0)
+ cifs_set_file_info(inode, attrs, xid, full_path, origattr);
+
+out_reval:
if (inode) {
- inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
cifsInode = CIFS_I(inode);
- cifsInode->time = 0; /* force revalidate of dir as well */
+ cifsInode->time = 0; /* will force revalidate to get info
+ when needed */
+ inode->i_ctime = current_fs_time(sb);
}
+ dir->i_ctime = dir->i_mtime = current_fs_time(sb);
+ cifsInode = CIFS_I(dir);
+ CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
kfree(full_path);
+ kfree(attrs);
FreeXid(xid);
return rc;
}
@@ -866,7 +965,7 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
{
- int rc = 0;
+ int rc = 0, tmprc;
int xid;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
@@ -928,6 +1027,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
kfree(pInfo);
goto mkdir_get_info;
}
+
/* Is an i_ino of zero legal? */
/* Are there sanity checks we can use to ensure that
the server is really filling in that field? */
@@ -984,35 +1084,52 @@ 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;
+ struct cifsInodeInfo *cifsInode;
+ u32 dosattrs;
+
memset(&pInfo, 0, sizeof(pInfo));
- pInfo.Attributes = cpu_to_le32(ATTR_READONLY);
- CIFSSMBSetTimes(xid, pTcon, full_path,
- &pInfo, cifs_sb->local_nls,
+ cifsInode = CIFS_I(newinode);
+ dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
+ pInfo.Attributes = cpu_to_le32(dosattrs);
+ tmprc = CIFSSMBSetPathInfo(xid, pTcon,
+ full_path, &pInfo,
+ cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (tmprc == 0)
+ cifsInode->cifsAttrs = dosattrs;
}
if (direntry->d_inode) {
if (cifs_sb->mnt_cifs_flags &
@@ -1024,8 +1141,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;
}
}
}
@@ -1080,117 +1201,141 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
return rc;
}
+static int
+cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
+ struct dentry *to_dentry, const char *toPath)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
+ struct cifsTconInfo *pTcon = cifs_sb->tcon;
+ __u16 srcfid;
+ int oplock, rc;
+
+ /* try path-based rename first */
+ rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+ /*
+ * don't bother with rename by filehandle unless file is busy and
+ * source Note that cross directory moves do not work with
+ * rename by filehandle to various Windows servers.
+ */
+ if (rc == 0 || rc != -ETXTBSY)
+ return rc;
+
+ /* open the file to be renamed -- we need DELETE perms */
+ rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
+ CREATE_NOT_DIR, &srcfid, &oplock, NULL,
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+ if (rc == 0) {
+ rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
+ (const char *) to_dentry->d_name.name,
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+ CIFSSMBClose(xid, pTcon, srcfid);
+ }
+
+ return rc;
+}
+
int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
struct inode *target_inode, struct dentry *target_direntry)
{
- char *fromName;
- char *toName;
+ char *fromName = NULL;
+ char *toName = NULL;
struct cifs_sb_info *cifs_sb_source;
struct cifs_sb_info *cifs_sb_target;
struct cifsTconInfo *pTcon;
+ FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
+ FILE_UNIX_BASIC_INFO *info_buf_target;
int xid;
- int rc = 0;
-
- xid = GetXid();
+ int rc;
cifs_sb_target = CIFS_SB(target_inode->i_sb);
cifs_sb_source = CIFS_SB(source_inode->i_sb);
pTcon = cifs_sb_source->tcon;
+ xid = GetXid();
+
+ /*
+ * BB: this might be allowed if same server, but different share.
+ * Consider adding support for this
+ */
if (pTcon != cifs_sb_target->tcon) {
- FreeXid(xid);
- return -EXDEV; /* BB actually could be allowed if same server,
- but different share.
- Might eventually add support for this */
+ rc = -EXDEV;
+ goto cifs_rename_exit;
}
- /* we already have the rename sem so we do not need to grab it again
- here to protect the path integrity */
+ /*
+ * we already have the rename sem so we do not need to
+ * grab it again here to protect the path integrity
+ */
fromName = build_path_from_dentry(source_direntry);
+ if (fromName == NULL) {
+ rc = -ENOMEM;
+ goto cifs_rename_exit;
+ }
+
toName = build_path_from_dentry(target_direntry);
- if ((fromName == NULL) || (toName == NULL)) {
+ if (toName == NULL) {
rc = -ENOMEM;
goto cifs_rename_exit;
}
- rc = CIFSSMBRename(xid, pTcon, fromName, toName,
- cifs_sb_source->local_nls,
- cifs_sb_source->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ rc = cifs_do_rename(xid, source_direntry, fromName,
+ target_direntry, toName);
+
if (rc == -EEXIST) {
- /* check if they are the same file because rename of hardlinked
- files is a noop */
- FILE_UNIX_BASIC_INFO *info_buf_source;
- FILE_UNIX_BASIC_INFO *info_buf_target;
-
- info_buf_source =
- kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
- if (info_buf_source != NULL) {
+ if (pTcon->unix_ext) {
+ /*
+ * Are src and dst hardlinks of same inode? We can
+ * only tell with unix extensions enabled
+ */
+ info_buf_source =
+ kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
+ GFP_KERNEL);
+ if (info_buf_source == NULL)
+ goto unlink_target;
+
info_buf_target = info_buf_source + 1;
- if (pTcon->unix_ext)
- rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
- info_buf_source,
- cifs_sb_source->local_nls,
- cifs_sb_source->mnt_cifs_flags &
+ rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
+ info_buf_source,
+ cifs_sb_source->local_nls,
+ cifs_sb_source->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- /* else rc is still EEXIST so will fall through to
- unlink the target and retry rename */
- if (rc == 0) {
- rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
- info_buf_target,
+ if (rc != 0)
+ goto unlink_target;
+
+ rc = CIFSSMBUnixQPathInfo(xid, pTcon,
+ toName, info_buf_target,
cifs_sb_target->local_nls,
/* remap based on source sb */
cifs_sb_source->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- }
- if ((rc == 0) &&
- (info_buf_source->UniqueId ==
- info_buf_target->UniqueId)) {
- /* do not rename since the files are hardlinked which
- is a noop */
- } else {
- /* we either can not tell the files are hardlinked
- (as with Windows servers) or files are not
- hardlinked so delete the target manually before
- renaming to follow POSIX rather than Windows
- semantics */
- cifs_unlink(target_inode, target_direntry);
- rc = CIFSSMBRename(xid, pTcon, fromName,
- toName,
- cifs_sb_source->local_nls,
- cifs_sb_source->mnt_cifs_flags
- & CIFS_MOUNT_MAP_SPECIAL_CHR);
- }
- kfree(info_buf_source);
- } /* if we can not get memory just leave rc as EEXIST */
- }
-
- if (rc)
- cFYI(1, ("rename rc %d", rc));
-
- if ((rc == -EIO) || (rc == -EEXIST)) {
- int oplock = 0;
- __u16 netfid;
-
- /* BB FIXME Is Generic Read correct for rename? */
- /* if renaming directory - we should not say CREATE_NOT_DIR,
- need to test renaming open directory, also GENERIC_READ
- might not right be right access to request */
- rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
- CREATE_NOT_DIR, &netfid, &oplock, NULL,
- cifs_sb_source->local_nls,
- cifs_sb_source->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc == 0) {
- rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
- cifs_sb_source->local_nls,
- cifs_sb_source->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- CIFSSMBClose(xid, pTcon, netfid);
- }
+
+ if (rc == 0 && (info_buf_source->UniqueId ==
+ info_buf_target->UniqueId))
+ /* same file, POSIX says that this is a noop */
+ goto cifs_rename_exit;
+ } /* else ... BB we could add the same check for Windows by
+ checking the UniqueId via FILE_INTERNAL_INFO */
+unlink_target:
+ /*
+ * we either can not tell the files are hardlinked (as with
+ * Windows servers) or files are not hardlinked. Delete the
+ * target manually before renaming to follow POSIX rather than
+ * Windows semantics
+ */
+ cifs_unlink(target_inode, target_direntry);
+ rc = cifs_do_rename(xid, source_direntry, fromName,
+ target_direntry, toName);
}
cifs_rename_exit:
+ kfree(info_buf_source);
kfree(fromName);
kfree(toName);
FreeXid(xid);
@@ -1310,10 +1455,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 */
@@ -1413,31 +1559,209 @@ out_busy:
return -ETXTBSY;
}
-int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
+static int
+cifs_set_file_size(struct inode *inode, struct iattr *attrs,
+ int xid, char *full_path)
{
+ int rc;
+ 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;
+
+ /*
+ * To avoid spurious oplock breaks from server, in the case of
+ * inodes that we already have open, avoid doing path based
+ * setting of file size if we can do it by handle.
+ * This keeps our caching token (oplock) and avoids timeouts
+ * when the local oplock break takes longer to flush
+ * writebehind data than the SMB timeout for the SetPathInfo
+ * request would allow
+ */
+ open_file = find_writable_file(cifsInode);
+ if (open_file) {
+ __u16 nfid = open_file->netfid;
+ __u32 npid = open_file->pid;
+ rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
+ npid, false);
+ atomic_dec(&open_file->wrtPending);
+ cFYI(1, ("SetFSize for attrs rc = %d", rc));
+ if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+ unsigned int bytes_written;
+ rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size,
+ &bytes_written, NULL, NULL, 1);
+ cFYI(1, ("Wrt seteof rc %d", rc));
+ }
+ } else
+ rc = -EINVAL;
+
+ if (rc != 0) {
+ /* Set file size by pathname rather than by handle
+ either because no valid, writeable file handle for
+ it was found or because there was an error setting
+ it by handle */
+ rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
+ false, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
+ if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+ __u16 netfid;
+ int oplock = 0;
+
+ rc = SMBLegacyOpen(xid, pTcon, full_path,
+ FILE_OPEN, GENERIC_WRITE,
+ CREATE_NOT_DIR, &netfid, &oplock, NULL,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (rc == 0) {
+ unsigned int bytes_written;
+ rc = CIFSSMBWrite(xid, pTcon, netfid, 0,
+ attrs->ia_size,
+ &bytes_written, NULL,
+ NULL, 1);
+ cFYI(1, ("wrt seteof rc %d", rc));
+ CIFSSMBClose(xid, pTcon, netfid);
+ }
+ }
+ }
+
+ if (rc == 0) {
+ rc = cifs_vmtruncate(inode, attrs->ia_size);
+ cifs_truncate_page(inode->i_mapping, inode->i_size);
+ }
+
+ 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;
- struct cifsFileInfo *open_file = NULL;
- 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);
@@ -1453,7 +1777,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)) {
/*
@@ -1472,78 +1795,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
}
if (attrs->ia_valid & ATTR_SIZE) {
- /* To avoid spurious oplock breaks from server, in the case of
- inodes that we already have open, avoid doing path based
- setting of file size if we can do it by handle.
- This keeps our caching token (oplock) and avoids timeouts
- when the local oplock break takes longer to flush
- writebehind data than the SMB timeout for the SetPathInfo
- request would allow */
-
- open_file = find_writable_file(cifsInode);
- if (open_file) {
- __u16 nfid = open_file->netfid;
- __u32 npid = open_file->pid;
- rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
- nfid, npid, false);
- atomic_dec(&open_file->wrtPending);
- cFYI(1, ("SetFSize for attrs rc = %d", rc));
- if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
- unsigned int bytes_written;
- rc = CIFSSMBWrite(xid, pTcon,
- nfid, 0, attrs->ia_size,
- &bytes_written, NULL, NULL,
- 1 /* 45 seconds */);
- cFYI(1, ("Wrt seteof rc %d", rc));
- }
- } else
- rc = -EINVAL;
-
- if (rc != 0) {
- /* Set file size by pathname rather than by handle
- either because no valid, writeable file handle for
- it was found or because there was an error setting
- it by handle */
- rc = CIFSSMBSetEOF(xid, pTcon, full_path,
- attrs->ia_size, false,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
- if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
- __u16 netfid;
- int oplock = 0;
-
- rc = SMBLegacyOpen(xid, pTcon, full_path,
- FILE_OPEN, GENERIC_WRITE,
- CREATE_NOT_DIR, &netfid, &oplock,
- NULL, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc == 0) {
- unsigned int bytes_written;
- rc = CIFSSMBWrite(xid, pTcon,
- netfid, 0,
- attrs->ia_size,
- &bytes_written, NULL,
- NULL, 1 /* 45 sec */);
- cFYI(1, ("wrt seteof rc %d", rc));
- CIFSSMBClose(xid, pTcon, netfid);
- }
-
- }
- }
-
- /* Server is ok setting allocation size implicitly - no need
- to call:
- CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, true,
- cifs_sb->local_nls);
- */
-
- if (rc == 0) {
- rc = cifs_vmtruncate(inode, attrs->ia_size);
- cifs_truncate_page(inode->i_mapping, inode->i_size);
- } else
+ rc = cifs_set_file_size(inode, attrs, xid, full_path);
+ if (rc != 0)
goto cifs_setattr_exit;
}
@@ -1554,21 +1807,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))
@@ -1579,13 +1819,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)
@@ -1594,24 +1828,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)) {
@@ -1629,82 +1858,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;
}
@@ -1718,6 +1883,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)
{
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 4b17f8fe315..88786ba02d2 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -150,8 +150,7 @@ cifs_buf_get(void)
but it may be more efficient to always alloc same size
albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */
- ret_buf = (struct smb_hdr *) mempool_alloc(cifs_req_poolp,
- GFP_KERNEL | GFP_NOFS);
+ ret_buf = mempool_alloc(cifs_req_poolp, GFP_NOFS);
/* clear the first few header bytes */
/* for most paths, more is cleared in header_assemble */
@@ -188,8 +187,7 @@ cifs_small_buf_get(void)
but it may be more efficient to always alloc same size
albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */
- ret_buf = (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp,
- GFP_KERNEL | GFP_NOFS);
+ ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS);
if (ret_buf) {
/* No need to clear memory here, cleared in header assemble */
/* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
@@ -313,8 +311,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
buffer->Pid = cpu_to_le16((__u16)current->tgid);
buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
- spin_lock(&GlobalMid_Lock);
- spin_unlock(&GlobalMid_Lock);
if (treeCon) {
buffer->Tid = treeCon->tid;
if (treeCon->ses) {
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 83f30695488..765adf12d54 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -640,6 +640,70 @@ static int is_dir_changed(struct file *file)
}
+static int cifs_save_resume_key(const char *current_entry,
+ struct cifsFileInfo *cifsFile)
+{
+ int rc = 0;
+ unsigned int len = 0;
+ __u16 level;
+ char *filename;
+
+ if ((cifsFile == NULL) || (current_entry == NULL))
+ return -EINVAL;
+
+ level = cifsFile->srch_inf.info_level;
+
+ if (level == SMB_FIND_FILE_UNIX) {
+ FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
+
+ filename = &pFindData->FileName[0];
+ if (cifsFile->srch_inf.unicode) {
+ len = cifs_unicode_bytelen(filename);
+ } else {
+ /* BB should we make this strnlen of PATH_MAX? */
+ len = strnlen(filename, PATH_MAX);
+ }
+ cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
+ } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
+ FILE_DIRECTORY_INFO *pFindData =
+ (FILE_DIRECTORY_INFO *)current_entry;
+ filename = &pFindData->FileName[0];
+ len = le32_to_cpu(pFindData->FileNameLength);
+ cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+ } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
+ FILE_FULL_DIRECTORY_INFO *pFindData =
+ (FILE_FULL_DIRECTORY_INFO *)current_entry;
+ filename = &pFindData->FileName[0];
+ len = le32_to_cpu(pFindData->FileNameLength);
+ cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+ } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
+ SEARCH_ID_FULL_DIR_INFO *pFindData =
+ (SEARCH_ID_FULL_DIR_INFO *)current_entry;
+ filename = &pFindData->FileName[0];
+ len = le32_to_cpu(pFindData->FileNameLength);
+ cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+ } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+ FILE_BOTH_DIRECTORY_INFO *pFindData =
+ (FILE_BOTH_DIRECTORY_INFO *)current_entry;
+ filename = &pFindData->FileName[0];
+ len = le32_to_cpu(pFindData->FileNameLength);
+ cifsFile->srch_inf.resume_key = pFindData->FileIndex;
+ } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
+ FIND_FILE_STANDARD_INFO *pFindData =
+ (FIND_FILE_STANDARD_INFO *)current_entry;
+ filename = &pFindData->FileName[0];
+ /* one byte length, no name conversion */
+ len = (unsigned int)pFindData->FileNameLength;
+ cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
+ } else {
+ cFYI(1, ("Unknown findfirst level %d", level));
+ return -EINVAL;
+ }
+ cifsFile->srch_inf.resume_name_len = len;
+ cifsFile->srch_inf.presume_name = filename;
+ return rc;
+}
+
/* find the corresponding entry in the search */
/* Note that the SMB server returns search entries for . and .. which
complicates logic here if we choose to parse for them and we do not
@@ -690,6 +754,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
else
cifs_buf_release(cifsFile->srch_inf.
ntwrk_buf_start);
+ cifsFile->srch_inf.ntwrk_buf_start = NULL;
}
rc = initiate_cifs_search(xid, file);
if (rc) {
@@ -702,6 +767,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
(rc == 0) && !cifsFile->srch_inf.endOfSearch) {
cFYI(1, ("calling findnext2"));
+ cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
&cifsFile->srch_inf);
if (rc)
@@ -918,69 +984,6 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
return rc;
}
-static int cifs_save_resume_key(const char *current_entry,
- struct cifsFileInfo *cifsFile)
-{
- int rc = 0;
- unsigned int len = 0;
- __u16 level;
- char *filename;
-
- if ((cifsFile == NULL) || (current_entry == NULL))
- return -EINVAL;
-
- level = cifsFile->srch_inf.info_level;
-
- if (level == SMB_FIND_FILE_UNIX) {
- FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
-
- filename = &pFindData->FileName[0];
- if (cifsFile->srch_inf.unicode) {
- len = cifs_unicode_bytelen(filename);
- } else {
- /* BB should we make this strnlen of PATH_MAX? */
- len = strnlen(filename, PATH_MAX);
- }
- cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
- } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
- FILE_DIRECTORY_INFO *pFindData =
- (FILE_DIRECTORY_INFO *)current_entry;
- filename = &pFindData->FileName[0];
- len = le32_to_cpu(pFindData->FileNameLength);
- cifsFile->srch_inf.resume_key = pFindData->FileIndex;
- } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
- FILE_FULL_DIRECTORY_INFO *pFindData =
- (FILE_FULL_DIRECTORY_INFO *)current_entry;
- filename = &pFindData->FileName[0];
- len = le32_to_cpu(pFindData->FileNameLength);
- cifsFile->srch_inf.resume_key = pFindData->FileIndex;
- } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
- SEARCH_ID_FULL_DIR_INFO *pFindData =
- (SEARCH_ID_FULL_DIR_INFO *)current_entry;
- filename = &pFindData->FileName[0];
- len = le32_to_cpu(pFindData->FileNameLength);
- cifsFile->srch_inf.resume_key = pFindData->FileIndex;
- } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
- FILE_BOTH_DIRECTORY_INFO *pFindData =
- (FILE_BOTH_DIRECTORY_INFO *)current_entry;
- filename = &pFindData->FileName[0];
- len = le32_to_cpu(pFindData->FileNameLength);
- cifsFile->srch_inf.resume_key = pFindData->FileIndex;
- } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
- FIND_FILE_STANDARD_INFO *pFindData =
- (FIND_FILE_STANDARD_INFO *)current_entry;
- filename = &pFindData->FileName[0];
- /* one byte length, no name conversion */
- len = (unsigned int)pFindData->FileNameLength;
- cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
- } else {
- cFYI(1, ("Unknown findfirst level %d", level));
- return -EINVAL;
- }
- cifsFile->srch_inf.resume_name_len = len;
- cifsFile->srch_inf.presume_name = filename;
- return rc;
-}
int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
{
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index ed150efbe27..2851d5da0c8 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -409,6 +409,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
#ifdef CONFIG_CIFS_WEAK_PW_HASH
char lnm_session_key[CIFS_SESS_KEY_SIZE];
+ pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE;
+
/* no capabilities flags in old lanman negotiation */
pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
@@ -505,7 +507,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
} else
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
- } else if (type == Kerberos) {
+ } else if (type == Kerberos || type == MSKerberos) {
#ifdef CONFIG_CIFS_UPCALL
struct cifs_spnego_msg *msg;
spnego_key = cifs_get_spnego_key(ses);
@@ -516,6 +518,15 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
}
msg = spnego_key->payload.data;
+ /* check version field to make sure that cifs.upcall is
+ sending us a response in an expected form */
+ if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) {
+ cERROR(1, ("incorrect version of cifs.upcall (expected"
+ " %d but got %d)",
+ CIFS_SPNEGO_UPCALL_VERSION, msg->version));
+ rc = -EKEYREJECTED;
+ goto ssetup_exit;
+ }
/* bail out if key is too long */
if (msg->sesskey_len >
sizeof(ses->server->mac_signing_key.data.krb5)) {
@@ -613,8 +624,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
ses, nls_cp);
ssetup_exit:
- if (spnego_key)
+ if (spnego_key) {
+ key_revoke(spnego_key);
key_put(spnego_key);
+ }
kfree(str_area);
if (resp_buf_type == CIFS_SMALL_BUFFER) {
cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base));
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 000ac509c98..bf0e6d8e382 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -50,8 +50,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
return NULL;
}
- temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
- GFP_KERNEL | GFP_NOFS);
+ temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS);
if (temp == NULL)
return temp;
else {
@@ -265,6 +264,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);