diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cache.c | 16 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.c | 22 | ||||
-rw-r--r-- | fs/cifs/cifs_spnego.c | 10 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 6 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 17 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 9 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 5 | ||||
-rw-r--r-- | fs/cifs/connect.c | 462 | ||||
-rw-r--r-- | fs/cifs/dir.c | 6 | ||||
-rw-r--r-- | fs/cifs/file.c | 233 | ||||
-rw-r--r-- | fs/cifs/inode.c | 6 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 1 | ||||
-rw-r--r-- | fs/cifs/sess.c | 135 | ||||
-rw-r--r-- | fs/cifs/transport.c | 2 | ||||
-rw-r--r-- | fs/dlm/lowcomms.c | 63 | ||||
-rw-r--r-- | fs/fuse/dev.c | 156 | ||||
-rw-r--r-- | fs/fuse/dir.c | 53 | ||||
-rw-r--r-- | fs/fuse/file.c | 66 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 27 | ||||
-rw-r--r-- | fs/fuse/inode.c | 30 | ||||
-rw-r--r-- | fs/namei.c | 8 |
21 files changed, 727 insertions, 606 deletions
diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index 224d7bbd1fcc..e654dfd092c3 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c | |||
@@ -64,7 +64,9 @@ static uint16_t cifs_server_get_key(const void *cookie_netfs_data, | |||
64 | void *buffer, uint16_t maxbuf) | 64 | void *buffer, uint16_t maxbuf) |
65 | { | 65 | { |
66 | const struct TCP_Server_Info *server = cookie_netfs_data; | 66 | const struct TCP_Server_Info *server = cookie_netfs_data; |
67 | const struct sockaddr *sa = (struct sockaddr *) &server->addr.sockAddr; | 67 | const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr; |
68 | const struct sockaddr_in *addr = (struct sockaddr_in *) sa; | ||
69 | const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa; | ||
68 | struct cifs_server_key *key = buffer; | 70 | struct cifs_server_key *key = buffer; |
69 | uint16_t key_len = sizeof(struct cifs_server_key); | 71 | uint16_t key_len = sizeof(struct cifs_server_key); |
70 | 72 | ||
@@ -76,16 +78,16 @@ static uint16_t cifs_server_get_key(const void *cookie_netfs_data, | |||
76 | */ | 78 | */ |
77 | switch (sa->sa_family) { | 79 | switch (sa->sa_family) { |
78 | case AF_INET: | 80 | case AF_INET: |
79 | key->family = server->addr.sockAddr.sin_family; | 81 | key->family = sa->sa_family; |
80 | key->port = server->addr.sockAddr.sin_port; | 82 | key->port = addr->sin_port; |
81 | key->addr[0].ipv4_addr = server->addr.sockAddr.sin_addr; | 83 | key->addr[0].ipv4_addr = addr->sin_addr; |
82 | key_len += sizeof(key->addr[0].ipv4_addr); | 84 | key_len += sizeof(key->addr[0].ipv4_addr); |
83 | break; | 85 | break; |
84 | 86 | ||
85 | case AF_INET6: | 87 | case AF_INET6: |
86 | key->family = server->addr.sockAddr6.sin6_family; | 88 | key->family = sa->sa_family; |
87 | key->port = server->addr.sockAddr6.sin6_port; | 89 | key->port = addr6->sin6_port; |
88 | key->addr[0].ipv6_addr = server->addr.sockAddr6.sin6_addr; | 90 | key->addr[0].ipv6_addr = addr6->sin6_addr; |
89 | key_len += sizeof(key->addr[0].ipv6_addr); | 91 | key_len += sizeof(key->addr[0].ipv6_addr); |
90 | break; | 92 | break; |
91 | 93 | ||
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 103ab8b605b0..ede98300a8cd 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -119,29 +119,27 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
119 | "Display Internal CIFS Data Structures for Debugging\n" | 119 | "Display Internal CIFS Data Structures for Debugging\n" |
120 | "---------------------------------------------------\n"); | 120 | "---------------------------------------------------\n"); |
121 | seq_printf(m, "CIFS Version %s\n", CIFS_VERSION); | 121 | seq_printf(m, "CIFS Version %s\n", CIFS_VERSION); |
122 | seq_printf(m, "Features: "); | 122 | seq_printf(m, "Features:"); |
123 | #ifdef CONFIG_CIFS_DFS_UPCALL | 123 | #ifdef CONFIG_CIFS_DFS_UPCALL |
124 | seq_printf(m, "dfs"); | 124 | seq_printf(m, " dfs"); |
125 | seq_putc(m, ' '); | ||
126 | #endif | 125 | #endif |
127 | #ifdef CONFIG_CIFS_FSCACHE | 126 | #ifdef CONFIG_CIFS_FSCACHE |
128 | seq_printf(m, "fscache"); | 127 | seq_printf(m, " fscache"); |
129 | seq_putc(m, ' '); | ||
130 | #endif | 128 | #endif |
131 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 129 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
132 | seq_printf(m, "lanman"); | 130 | seq_printf(m, " lanman"); |
133 | seq_putc(m, ' '); | ||
134 | #endif | 131 | #endif |
135 | #ifdef CONFIG_CIFS_POSIX | 132 | #ifdef CONFIG_CIFS_POSIX |
136 | seq_printf(m, "posix"); | 133 | seq_printf(m, " posix"); |
137 | seq_putc(m, ' '); | ||
138 | #endif | 134 | #endif |
139 | #ifdef CONFIG_CIFS_UPCALL | 135 | #ifdef CONFIG_CIFS_UPCALL |
140 | seq_printf(m, "spnego"); | 136 | seq_printf(m, " spnego"); |
141 | seq_putc(m, ' '); | ||
142 | #endif | 137 | #endif |
143 | #ifdef CONFIG_CIFS_XATTR | 138 | #ifdef CONFIG_CIFS_XATTR |
144 | seq_printf(m, "xattr"); | 139 | seq_printf(m, " xattr"); |
140 | #endif | ||
141 | #ifdef CONFIG_CIFS_ACL | ||
142 | seq_printf(m, " acl"); | ||
145 | #endif | 143 | #endif |
146 | seq_putc(m, '\n'); | 144 | seq_putc(m, '\n'); |
147 | seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); | 145 | seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 87044906cd1f..4dfba8283165 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
@@ -98,6 +98,8 @@ struct key * | |||
98 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | 98 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo) |
99 | { | 99 | { |
100 | struct TCP_Server_Info *server = sesInfo->server; | 100 | struct TCP_Server_Info *server = sesInfo->server; |
101 | struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr; | ||
102 | struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr; | ||
101 | char *description, *dp; | 103 | char *description, *dp; |
102 | size_t desc_len; | 104 | size_t desc_len; |
103 | struct key *spnego_key; | 105 | struct key *spnego_key; |
@@ -127,10 +129,10 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
127 | dp = description + strlen(description); | 129 | dp = description + strlen(description); |
128 | 130 | ||
129 | /* add the server address */ | 131 | /* add the server address */ |
130 | if (server->addr.sockAddr.sin_family == AF_INET) | 132 | if (server->dstaddr.ss_family == AF_INET) |
131 | sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr); | 133 | sprintf(dp, "ip4=%pI4", &sa->sin_addr); |
132 | else if (server->addr.sockAddr.sin_family == AF_INET6) | 134 | else if (server->dstaddr.ss_family == AF_INET6) |
133 | sprintf(dp, "ip6=%pI6", &server->addr.sockAddr6.sin6_addr); | 135 | sprintf(dp, "ip6=%pI6", &sa6->sin6_addr); |
134 | else | 136 | else |
135 | goto out; | 137 | goto out; |
136 | 138 | ||
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index f856732161ab..66f3d50d0676 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -72,6 +72,7 @@ static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, | |||
72 | return 0; | 72 | return 0; |
73 | } | 73 | } |
74 | 74 | ||
75 | /* must be called with server->srv_mutex held */ | ||
75 | int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | 76 | int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, |
76 | __u32 *pexpected_response_sequence_number) | 77 | __u32 *pexpected_response_sequence_number) |
77 | { | 78 | { |
@@ -84,14 +85,12 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
84 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | 85 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) |
85 | return rc; | 86 | return rc; |
86 | 87 | ||
87 | spin_lock(&GlobalMid_Lock); | ||
88 | cifs_pdu->Signature.Sequence.SequenceNumber = | 88 | cifs_pdu->Signature.Sequence.SequenceNumber = |
89 | cpu_to_le32(server->sequence_number); | 89 | cpu_to_le32(server->sequence_number); |
90 | cifs_pdu->Signature.Sequence.Reserved = 0; | 90 | cifs_pdu->Signature.Sequence.Reserved = 0; |
91 | 91 | ||
92 | *pexpected_response_sequence_number = server->sequence_number++; | 92 | *pexpected_response_sequence_number = server->sequence_number++; |
93 | server->sequence_number++; | 93 | server->sequence_number++; |
94 | spin_unlock(&GlobalMid_Lock); | ||
95 | 94 | ||
96 | rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); | 95 | rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); |
97 | if (rc) | 96 | if (rc) |
@@ -149,6 +148,7 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | |||
149 | return rc; | 148 | return rc; |
150 | } | 149 | } |
151 | 150 | ||
151 | /* must be called with server->srv_mutex held */ | ||
152 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | 152 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, |
153 | __u32 *pexpected_response_sequence_number) | 153 | __u32 *pexpected_response_sequence_number) |
154 | { | 154 | { |
@@ -162,14 +162,12 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
162 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | 162 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) |
163 | return rc; | 163 | return rc; |
164 | 164 | ||
165 | spin_lock(&GlobalMid_Lock); | ||
166 | cifs_pdu->Signature.Sequence.SequenceNumber = | 165 | cifs_pdu->Signature.Sequence.SequenceNumber = |
167 | cpu_to_le32(server->sequence_number); | 166 | cpu_to_le32(server->sequence_number); |
168 | cifs_pdu->Signature.Sequence.Reserved = 0; | 167 | cifs_pdu->Signature.Sequence.Reserved = 0; |
169 | 168 | ||
170 | *pexpected_response_sequence_number = server->sequence_number++; | 169 | *pexpected_response_sequence_number = server->sequence_number++; |
171 | server->sequence_number++; | 170 | server->sequence_number++; |
172 | spin_unlock(&GlobalMid_Lock); | ||
173 | 171 | ||
174 | rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); | 172 | rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); |
175 | if (rc) | 173 | if (rc) |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8e21e0fe65d5..5e7075d5f139 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -329,6 +329,8 @@ cifs_alloc_inode(struct super_block *sb) | |||
329 | cifs_inode->invalid_mapping = false; | 329 | cifs_inode->invalid_mapping = false; |
330 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 330 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
331 | cifs_inode->server_eof = 0; | 331 | cifs_inode->server_eof = 0; |
332 | cifs_inode->uniqueid = 0; | ||
333 | cifs_inode->createtime = 0; | ||
332 | 334 | ||
333 | /* Can not set i_flags here - they get immediately overwritten | 335 | /* Can not set i_flags here - they get immediately overwritten |
334 | to zero by the VFS */ | 336 | to zero by the VFS */ |
@@ -361,18 +363,19 @@ cifs_evict_inode(struct inode *inode) | |||
361 | static void | 363 | static void |
362 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | 364 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) |
363 | { | 365 | { |
366 | struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr; | ||
367 | struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr; | ||
368 | |||
364 | seq_printf(s, ",addr="); | 369 | seq_printf(s, ",addr="); |
365 | 370 | ||
366 | switch (server->addr.sockAddr.sin_family) { | 371 | switch (server->dstaddr.ss_family) { |
367 | case AF_INET: | 372 | case AF_INET: |
368 | seq_printf(s, "%pI4", &server->addr.sockAddr.sin_addr.s_addr); | 373 | seq_printf(s, "%pI4", &sa->sin_addr.s_addr); |
369 | break; | 374 | break; |
370 | case AF_INET6: | 375 | case AF_INET6: |
371 | seq_printf(s, "%pI6", | 376 | seq_printf(s, "%pI6", &sa6->sin6_addr.s6_addr); |
372 | &server->addr.sockAddr6.sin6_addr.s6_addr); | 377 | if (sa6->sin6_scope_id) |
373 | if (server->addr.sockAddr6.sin6_scope_id) | 378 | seq_printf(s, "%%%u", sa6->sin6_scope_id); |
374 | seq_printf(s, "%%%u", | ||
375 | server->addr.sockAddr6.sin6_scope_id); | ||
376 | break; | 379 | break; |
377 | default: | 380 | default: |
378 | seq_printf(s, "(unknown)"); | 381 | seq_printf(s, "(unknown)"); |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 7136c0c3e2f9..606ca8bb7102 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -163,10 +163,7 @@ struct TCP_Server_Info { | |||
163 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; | 163 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; |
164 | char *hostname; /* hostname portion of UNC string */ | 164 | char *hostname; /* hostname portion of UNC string */ |
165 | struct socket *ssocket; | 165 | struct socket *ssocket; |
166 | union { | 166 | struct sockaddr_storage dstaddr; |
167 | struct sockaddr_in sockAddr; | ||
168 | struct sockaddr_in6 sockAddr6; | ||
169 | } addr; | ||
170 | struct sockaddr_storage srcaddr; /* locally bind to this IP */ | 167 | struct sockaddr_storage srcaddr; /* locally bind to this IP */ |
171 | wait_queue_head_t response_q; | 168 | wait_queue_head_t response_q; |
172 | wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ | 169 | wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ |
@@ -210,7 +207,7 @@ struct TCP_Server_Info { | |||
210 | char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ | 207 | char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ |
211 | /* 16th byte of RFC1001 workstation name is always null */ | 208 | /* 16th byte of RFC1001 workstation name is always null */ |
212 | char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; | 209 | char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; |
213 | __u32 sequence_number; /* needed for CIFS PDU signature */ | 210 | __u32 sequence_number; /* for signing, protected by srv_mutex */ |
214 | struct session_key session_key; | 211 | struct session_key session_key; |
215 | unsigned long lstrp; /* when we got last response from this server */ | 212 | unsigned long lstrp; /* when we got last response from this server */ |
216 | u16 dialect; /* dialect index that server chose */ | 213 | u16 dialect; /* dialect index that server chose */ |
@@ -456,6 +453,7 @@ struct cifsInodeInfo { | |||
456 | bool invalid_mapping:1; /* pagecache is invalid */ | 453 | bool invalid_mapping:1; /* pagecache is invalid */ |
457 | u64 server_eof; /* current file size on server */ | 454 | u64 server_eof; /* current file size on server */ |
458 | u64 uniqueid; /* server inode number */ | 455 | u64 uniqueid; /* server inode number */ |
456 | u64 createtime; /* creation time on server */ | ||
459 | #ifdef CONFIG_CIFS_FSCACHE | 457 | #ifdef CONFIG_CIFS_FSCACHE |
460 | struct fscache_cookie *fscache; | 458 | struct fscache_cookie *fscache; |
461 | #endif | 459 | #endif |
@@ -576,6 +574,7 @@ struct cifs_fattr { | |||
576 | u64 cf_uniqueid; | 574 | u64 cf_uniqueid; |
577 | u64 cf_eof; | 575 | u64 cf_eof; |
578 | u64 cf_bytes; | 576 | u64 cf_bytes; |
577 | u64 cf_createtime; | ||
579 | uid_t cf_uid; | 578 | uid_t cf_uid; |
580 | gid_t cf_gid; | 579 | gid_t cf_gid; |
581 | umode_t cf_mode; | 580 | umode_t cf_mode; |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 67acfb3acad2..2f6795e524d3 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -401,15 +401,12 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
401 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { | 401 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { |
402 | cFYI(1, "Kerberos only mechanism, enable extended security"); | 402 | cFYI(1, "Kerberos only mechanism, enable extended security"); |
403 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 403 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
404 | } | 404 | } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP) |
405 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
406 | else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP) | ||
407 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 405 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
408 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) { | 406 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) { |
409 | cFYI(1, "NTLMSSP only mechanism, enable extended security"); | 407 | cFYI(1, "NTLMSSP only mechanism, enable extended security"); |
410 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 408 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
411 | } | 409 | } |
412 | #endif | ||
413 | 410 | ||
414 | count = 0; | 411 | count = 0; |
415 | for (i = 0; i < CIFS_NUM_PROT; i++) { | 412 | for (i = 0; i < CIFS_NUM_PROT; i++) { |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index cc1a8604a790..a65d311d163a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -64,8 +64,8 @@ struct smb_vol { | |||
64 | char *UNC; | 64 | char *UNC; |
65 | char *UNCip; | 65 | char *UNCip; |
66 | char *iocharset; /* local code page for mapping to and from Unicode */ | 66 | char *iocharset; /* local code page for mapping to and from Unicode */ |
67 | char source_rfc1001_name[16]; /* netbios name of client */ | 67 | char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ |
68 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ | 68 | char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ |
69 | uid_t cred_uid; | 69 | uid_t cred_uid; |
70 | uid_t linux_uid; | 70 | uid_t linux_uid; |
71 | gid_t linux_gid; | 71 | gid_t linux_gid; |
@@ -115,8 +115,8 @@ struct smb_vol { | |||
115 | #define TLINK_ERROR_EXPIRE (1 * HZ) | 115 | #define TLINK_ERROR_EXPIRE (1 * HZ) |
116 | #define TLINK_IDLE_EXPIRE (600 * HZ) | 116 | #define TLINK_IDLE_EXPIRE (600 * HZ) |
117 | 117 | ||
118 | static int ipv4_connect(struct TCP_Server_Info *server); | 118 | static int ip_connect(struct TCP_Server_Info *server); |
119 | static int ipv6_connect(struct TCP_Server_Info *server); | 119 | static int generic_ip_connect(struct TCP_Server_Info *server); |
120 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); | 120 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); |
121 | static void cifs_prune_tlinks(struct work_struct *work); | 121 | static void cifs_prune_tlinks(struct work_struct *work); |
122 | 122 | ||
@@ -200,10 +200,9 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
200 | while ((server->tcpStatus != CifsExiting) && | 200 | while ((server->tcpStatus != CifsExiting) && |
201 | (server->tcpStatus != CifsGood)) { | 201 | (server->tcpStatus != CifsGood)) { |
202 | try_to_freeze(); | 202 | try_to_freeze(); |
203 | if (server->addr.sockAddr6.sin6_family == AF_INET6) | 203 | |
204 | rc = ipv6_connect(server); | 204 | /* we should try only the port we connected to before */ |
205 | else | 205 | rc = generic_ip_connect(server); |
206 | rc = ipv4_connect(server); | ||
207 | if (rc) { | 206 | if (rc) { |
208 | cFYI(1, "reconnect error %d", rc); | 207 | cFYI(1, "reconnect error %d", rc); |
209 | msleep(3000); | 208 | msleep(3000); |
@@ -477,7 +476,7 @@ incomplete_rcv: | |||
477 | * initialize frame) | 476 | * initialize frame) |
478 | */ | 477 | */ |
479 | cifs_set_port((struct sockaddr *) | 478 | cifs_set_port((struct sockaddr *) |
480 | &server->addr.sockAddr, CIFS_PORT); | 479 | &server->dstaddr, CIFS_PORT); |
481 | cifs_reconnect(server); | 480 | cifs_reconnect(server); |
482 | csocket = server->ssocket; | 481 | csocket = server->ssocket; |
483 | wake_up(&server->response_q); | 482 | wake_up(&server->response_q); |
@@ -817,11 +816,11 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
817 | * informational, only used for servers that do not support | 816 | * informational, only used for servers that do not support |
818 | * port 445 and it can be overridden at mount time | 817 | * port 445 and it can be overridden at mount time |
819 | */ | 818 | */ |
820 | memset(vol->source_rfc1001_name, 0x20, 15); | 819 | memset(vol->source_rfc1001_name, 0x20, RFC1001_NAME_LEN); |
821 | for (i = 0; i < strnlen(nodename, 15); i++) | 820 | for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++) |
822 | vol->source_rfc1001_name[i] = toupper(nodename[i]); | 821 | vol->source_rfc1001_name[i] = toupper(nodename[i]); |
823 | 822 | ||
824 | vol->source_rfc1001_name[15] = 0; | 823 | vol->source_rfc1001_name[RFC1001_NAME_LEN] = 0; |
825 | /* null target name indicates to use *SMBSERVR default called name | 824 | /* null target name indicates to use *SMBSERVR default called name |
826 | if we end up sending RFC1001 session initialize */ | 825 | if we end up sending RFC1001 session initialize */ |
827 | vol->target_rfc1001_name[0] = 0; | 826 | vol->target_rfc1001_name[0] = 0; |
@@ -985,13 +984,11 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
985 | return 1; | 984 | return 1; |
986 | } else if (strnicmp(value, "krb5", 4) == 0) { | 985 | } else if (strnicmp(value, "krb5", 4) == 0) { |
987 | vol->secFlg |= CIFSSEC_MAY_KRB5; | 986 | vol->secFlg |= CIFSSEC_MAY_KRB5; |
988 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
989 | } else if (strnicmp(value, "ntlmsspi", 8) == 0) { | 987 | } else if (strnicmp(value, "ntlmsspi", 8) == 0) { |
990 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP | | 988 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP | |
991 | CIFSSEC_MUST_SIGN; | 989 | CIFSSEC_MUST_SIGN; |
992 | } else if (strnicmp(value, "ntlmssp", 7) == 0) { | 990 | } else if (strnicmp(value, "ntlmssp", 7) == 0) { |
993 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP; | 991 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP; |
994 | #endif | ||
995 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { | 992 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { |
996 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | | 993 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | |
997 | CIFSSEC_MUST_SIGN; | 994 | CIFSSEC_MUST_SIGN; |
@@ -1168,22 +1165,22 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1168 | if (!value || !*value || (*value == ' ')) { | 1165 | if (!value || !*value || (*value == ' ')) { |
1169 | cFYI(1, "invalid (empty) netbiosname"); | 1166 | cFYI(1, "invalid (empty) netbiosname"); |
1170 | } else { | 1167 | } else { |
1171 | memset(vol->source_rfc1001_name, 0x20, 15); | 1168 | memset(vol->source_rfc1001_name, 0x20, |
1172 | for (i = 0; i < 15; i++) { | 1169 | RFC1001_NAME_LEN); |
1173 | /* BB are there cases in which a comma can be | 1170 | /* |
1174 | valid in this workstation netbios name (and need | 1171 | * FIXME: are there cases in which a comma can |
1175 | special handling)? */ | 1172 | * be valid in workstation netbios name (and |
1176 | 1173 | * need special handling)? | |
1177 | /* We do not uppercase netbiosname for user */ | 1174 | */ |
1175 | for (i = 0; i < RFC1001_NAME_LEN; i++) { | ||
1176 | /* don't ucase netbiosname for user */ | ||
1178 | if (value[i] == 0) | 1177 | if (value[i] == 0) |
1179 | break; | 1178 | break; |
1180 | else | 1179 | vol->source_rfc1001_name[i] = value[i]; |
1181 | vol->source_rfc1001_name[i] = | ||
1182 | value[i]; | ||
1183 | } | 1180 | } |
1184 | /* The string has 16th byte zero still from | 1181 | /* The string has 16th byte zero still from |
1185 | set at top of the function */ | 1182 | set at top of the function */ |
1186 | if ((i == 15) && (value[i] != 0)) | 1183 | if (i == RFC1001_NAME_LEN && value[i] != 0) |
1187 | printk(KERN_WARNING "CIFS: netbiosname" | 1184 | printk(KERN_WARNING "CIFS: netbiosname" |
1188 | " longer than 15 truncated.\n"); | 1185 | " longer than 15 truncated.\n"); |
1189 | } | 1186 | } |
@@ -1193,7 +1190,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1193 | cFYI(1, "empty server netbiosname specified"); | 1190 | cFYI(1, "empty server netbiosname specified"); |
1194 | } else { | 1191 | } else { |
1195 | /* last byte, type, is 0x20 for servr type */ | 1192 | /* last byte, type, is 0x20 for servr type */ |
1196 | memset(vol->target_rfc1001_name, 0x20, 16); | 1193 | memset(vol->target_rfc1001_name, 0x20, |
1194 | RFC1001_NAME_LEN_WITH_NULL); | ||
1197 | 1195 | ||
1198 | for (i = 0; i < 15; i++) { | 1196 | for (i = 0; i < 15; i++) { |
1199 | /* BB are there cases in which a comma can be | 1197 | /* BB are there cases in which a comma can be |
@@ -1210,7 +1208,7 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1210 | } | 1208 | } |
1211 | /* The string has 16th byte zero still from | 1209 | /* The string has 16th byte zero still from |
1212 | set at top of the function */ | 1210 | set at top of the function */ |
1213 | if ((i == 15) && (value[i] != 0)) | 1211 | if (i == RFC1001_NAME_LEN && value[i] != 0) |
1214 | printk(KERN_WARNING "CIFS: server net" | 1212 | printk(KERN_WARNING "CIFS: server net" |
1215 | "biosname longer than 15 truncated.\n"); | 1213 | "biosname longer than 15 truncated.\n"); |
1216 | } | 1214 | } |
@@ -1341,10 +1339,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1341 | vol->no_psx_acl = 0; | 1339 | vol->no_psx_acl = 0; |
1342 | } else if (strnicmp(data, "noacl", 5) == 0) { | 1340 | } else if (strnicmp(data, "noacl", 5) == 0) { |
1343 | vol->no_psx_acl = 1; | 1341 | vol->no_psx_acl = 1; |
1344 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1345 | } else if (strnicmp(data, "locallease", 6) == 0) { | 1342 | } else if (strnicmp(data, "locallease", 6) == 0) { |
1346 | vol->local_lease = 1; | 1343 | vol->local_lease = 1; |
1347 | #endif | ||
1348 | } else if (strnicmp(data, "sign", 4) == 0) { | 1344 | } else if (strnicmp(data, "sign", 4) == 0) { |
1349 | vol->secFlg |= CIFSSEC_MUST_SIGN; | 1345 | vol->secFlg |= CIFSSEC_MUST_SIGN; |
1350 | } else if (strnicmp(data, "seal", 4) == 0) { | 1346 | } else if (strnicmp(data, "seal", 4) == 0) { |
@@ -1454,35 +1450,71 @@ srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs) | |||
1454 | } | 1450 | } |
1455 | } | 1451 | } |
1456 | 1452 | ||
1453 | /* | ||
1454 | * If no port is specified in addr structure, we try to match with 445 port | ||
1455 | * and if it fails - with 139 ports. It should be called only if address | ||
1456 | * families of server and addr are equal. | ||
1457 | */ | ||
1458 | static bool | ||
1459 | match_port(struct TCP_Server_Info *server, struct sockaddr *addr) | ||
1460 | { | ||
1461 | unsigned short int port, *sport; | ||
1462 | |||
1463 | switch (addr->sa_family) { | ||
1464 | case AF_INET: | ||
1465 | sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port; | ||
1466 | port = ((struct sockaddr_in *) addr)->sin_port; | ||
1467 | break; | ||
1468 | case AF_INET6: | ||
1469 | sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port; | ||
1470 | port = ((struct sockaddr_in6 *) addr)->sin6_port; | ||
1471 | break; | ||
1472 | default: | ||
1473 | WARN_ON(1); | ||
1474 | return false; | ||
1475 | } | ||
1476 | |||
1477 | if (!port) { | ||
1478 | port = htons(CIFS_PORT); | ||
1479 | if (port == *sport) | ||
1480 | return true; | ||
1481 | |||
1482 | port = htons(RFC1001_PORT); | ||
1483 | } | ||
1484 | |||
1485 | return port == *sport; | ||
1486 | } | ||
1457 | 1487 | ||
1458 | static bool | 1488 | static bool |
1459 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr, | 1489 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr, |
1460 | struct sockaddr *srcaddr) | 1490 | struct sockaddr *srcaddr) |
1461 | { | 1491 | { |
1462 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; | ||
1463 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | ||
1464 | |||
1465 | switch (addr->sa_family) { | 1492 | switch (addr->sa_family) { |
1466 | case AF_INET: | 1493 | case AF_INET: { |
1467 | if (addr4->sin_addr.s_addr != | 1494 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; |
1468 | server->addr.sockAddr.sin_addr.s_addr) | 1495 | struct sockaddr_in *srv_addr4 = |
1469 | return false; | 1496 | (struct sockaddr_in *)&server->dstaddr; |
1470 | if (addr4->sin_port && | 1497 | |
1471 | addr4->sin_port != server->addr.sockAddr.sin_port) | 1498 | if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr) |
1472 | return false; | 1499 | return false; |
1473 | break; | 1500 | break; |
1474 | case AF_INET6: | 1501 | } |
1502 | case AF_INET6: { | ||
1503 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | ||
1504 | struct sockaddr_in6 *srv_addr6 = | ||
1505 | (struct sockaddr_in6 *)&server->dstaddr; | ||
1506 | |||
1475 | if (!ipv6_addr_equal(&addr6->sin6_addr, | 1507 | if (!ipv6_addr_equal(&addr6->sin6_addr, |
1476 | &server->addr.sockAddr6.sin6_addr)) | 1508 | &srv_addr6->sin6_addr)) |
1477 | return false; | 1509 | return false; |
1478 | if (addr6->sin6_scope_id != | 1510 | if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id) |
1479 | server->addr.sockAddr6.sin6_scope_id) | ||
1480 | return false; | ||
1481 | if (addr6->sin6_port && | ||
1482 | addr6->sin6_port != server->addr.sockAddr6.sin6_port) | ||
1483 | return false; | 1511 | return false; |
1484 | break; | 1512 | break; |
1485 | } | 1513 | } |
1514 | default: | ||
1515 | WARN_ON(1); | ||
1516 | return false; /* don't expect to be here */ | ||
1517 | } | ||
1486 | 1518 | ||
1487 | if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr)) | 1519 | if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr)) |
1488 | return false; | 1520 | return false; |
@@ -1549,6 +1581,9 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) | |||
1549 | (struct sockaddr *)&vol->srcaddr)) | 1581 | (struct sockaddr *)&vol->srcaddr)) |
1550 | continue; | 1582 | continue; |
1551 | 1583 | ||
1584 | if (!match_port(server, addr)) | ||
1585 | continue; | ||
1586 | |||
1552 | if (!match_security(server, vol)) | 1587 | if (!match_security(server, vol)) |
1553 | continue; | 1588 | continue; |
1554 | 1589 | ||
@@ -1681,14 +1716,13 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1681 | cFYI(1, "attempting ipv6 connect"); | 1716 | cFYI(1, "attempting ipv6 connect"); |
1682 | /* BB should we allow ipv6 on port 139? */ | 1717 | /* BB should we allow ipv6 on port 139? */ |
1683 | /* other OS never observed in Wild doing 139 with v6 */ | 1718 | /* other OS never observed in Wild doing 139 with v6 */ |
1684 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, | 1719 | memcpy(&tcp_ses->dstaddr, sin_server6, |
1685 | sizeof(struct sockaddr_in6)); | 1720 | sizeof(struct sockaddr_in6)); |
1686 | rc = ipv6_connect(tcp_ses); | 1721 | } else |
1687 | } else { | 1722 | memcpy(&tcp_ses->dstaddr, sin_server, |
1688 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | 1723 | sizeof(struct sockaddr_in)); |
1689 | sizeof(struct sockaddr_in)); | 1724 | |
1690 | rc = ipv4_connect(tcp_ses); | 1725 | rc = ip_connect(tcp_ses); |
1691 | } | ||
1692 | if (rc < 0) { | 1726 | if (rc < 0) { |
1693 | cERROR(1, "Error connecting to socket. Aborting operation"); | 1727 | cERROR(1, "Error connecting to socket. Aborting operation"); |
1694 | goto out_err_crypto_release; | 1728 | goto out_err_crypto_release; |
@@ -1793,6 +1827,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1793 | { | 1827 | { |
1794 | int rc = -ENOMEM, xid; | 1828 | int rc = -ENOMEM, xid; |
1795 | struct cifsSesInfo *ses; | 1829 | struct cifsSesInfo *ses; |
1830 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; | ||
1831 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; | ||
1796 | 1832 | ||
1797 | xid = GetXid(); | 1833 | xid = GetXid(); |
1798 | 1834 | ||
@@ -1836,12 +1872,10 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1836 | 1872 | ||
1837 | /* new SMB session uses our server ref */ | 1873 | /* new SMB session uses our server ref */ |
1838 | ses->server = server; | 1874 | ses->server = server; |
1839 | if (server->addr.sockAddr6.sin6_family == AF_INET6) | 1875 | if (server->dstaddr.ss_family == AF_INET6) |
1840 | sprintf(ses->serverName, "%pI6", | 1876 | sprintf(ses->serverName, "%pI6", &addr6->sin6_addr); |
1841 | &server->addr.sockAddr6.sin6_addr); | ||
1842 | else | 1877 | else |
1843 | sprintf(ses->serverName, "%pI4", | 1878 | sprintf(ses->serverName, "%pI4", &addr->sin_addr); |
1844 | &server->addr.sockAddr.sin_addr.s_addr); | ||
1845 | 1879 | ||
1846 | if (volume_info->username) | 1880 | if (volume_info->username) |
1847 | strncpy(ses->userName, volume_info->username, | 1881 | strncpy(ses->userName, volume_info->username, |
@@ -2136,19 +2170,106 @@ bind_socket(struct TCP_Server_Info *server) | |||
2136 | } | 2170 | } |
2137 | 2171 | ||
2138 | static int | 2172 | static int |
2139 | ipv4_connect(struct TCP_Server_Info *server) | 2173 | ip_rfc1001_connect(struct TCP_Server_Info *server) |
2174 | { | ||
2175 | int rc = 0; | ||
2176 | /* | ||
2177 | * some servers require RFC1001 sessinit before sending | ||
2178 | * negprot - BB check reconnection in case where second | ||
2179 | * sessinit is sent but no second negprot | ||
2180 | */ | ||
2181 | struct rfc1002_session_packet *ses_init_buf; | ||
2182 | struct smb_hdr *smb_buf; | ||
2183 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), | ||
2184 | GFP_KERNEL); | ||
2185 | if (ses_init_buf) { | ||
2186 | ses_init_buf->trailer.session_req.called_len = 32; | ||
2187 | |||
2188 | if (server->server_RFC1001_name && | ||
2189 | server->server_RFC1001_name[0] != 0) | ||
2190 | rfc1002mangle(ses_init_buf->trailer. | ||
2191 | session_req.called_name, | ||
2192 | server->server_RFC1001_name, | ||
2193 | RFC1001_NAME_LEN_WITH_NULL); | ||
2194 | else | ||
2195 | rfc1002mangle(ses_init_buf->trailer. | ||
2196 | session_req.called_name, | ||
2197 | DEFAULT_CIFS_CALLED_NAME, | ||
2198 | RFC1001_NAME_LEN_WITH_NULL); | ||
2199 | |||
2200 | ses_init_buf->trailer.session_req.calling_len = 32; | ||
2201 | |||
2202 | /* | ||
2203 | * calling name ends in null (byte 16) from old smb | ||
2204 | * convention. | ||
2205 | */ | ||
2206 | if (server->workstation_RFC1001_name && | ||
2207 | server->workstation_RFC1001_name[0] != 0) | ||
2208 | rfc1002mangle(ses_init_buf->trailer. | ||
2209 | session_req.calling_name, | ||
2210 | server->workstation_RFC1001_name, | ||
2211 | RFC1001_NAME_LEN_WITH_NULL); | ||
2212 | else | ||
2213 | rfc1002mangle(ses_init_buf->trailer. | ||
2214 | session_req.calling_name, | ||
2215 | "LINUX_CIFS_CLNT", | ||
2216 | RFC1001_NAME_LEN_WITH_NULL); | ||
2217 | |||
2218 | ses_init_buf->trailer.session_req.scope1 = 0; | ||
2219 | ses_init_buf->trailer.session_req.scope2 = 0; | ||
2220 | smb_buf = (struct smb_hdr *)ses_init_buf; | ||
2221 | |||
2222 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | ||
2223 | smb_buf->smb_buf_length = 0x81000044; | ||
2224 | rc = smb_send(server, smb_buf, 0x44); | ||
2225 | kfree(ses_init_buf); | ||
2226 | /* | ||
2227 | * RFC1001 layer in at least one server | ||
2228 | * requires very short break before negprot | ||
2229 | * presumably because not expecting negprot | ||
2230 | * to follow so fast. This is a simple | ||
2231 | * solution that works without | ||
2232 | * complicating the code and causes no | ||
2233 | * significant slowing down on mount | ||
2234 | * for everyone else | ||
2235 | */ | ||
2236 | usleep_range(1000, 2000); | ||
2237 | } | ||
2238 | /* | ||
2239 | * else the negprot may still work without this | ||
2240 | * even though malloc failed | ||
2241 | */ | ||
2242 | |||
2243 | return rc; | ||
2244 | } | ||
2245 | |||
2246 | static int | ||
2247 | generic_ip_connect(struct TCP_Server_Info *server) | ||
2140 | { | 2248 | { |
2141 | int rc = 0; | 2249 | int rc = 0; |
2142 | int val; | 2250 | unsigned short int sport; |
2143 | bool connected = false; | 2251 | int slen, sfamily; |
2144 | __be16 orig_port = 0; | ||
2145 | struct socket *socket = server->ssocket; | 2252 | struct socket *socket = server->ssocket; |
2253 | struct sockaddr *saddr; | ||
2254 | |||
2255 | saddr = (struct sockaddr *) &server->dstaddr; | ||
2256 | |||
2257 | if (server->dstaddr.ss_family == AF_INET6) { | ||
2258 | sport = ((struct sockaddr_in6 *) saddr)->sin6_port; | ||
2259 | slen = sizeof(struct sockaddr_in6); | ||
2260 | sfamily = AF_INET6; | ||
2261 | } else { | ||
2262 | sport = ((struct sockaddr_in *) saddr)->sin_port; | ||
2263 | slen = sizeof(struct sockaddr_in); | ||
2264 | sfamily = AF_INET; | ||
2265 | } | ||
2146 | 2266 | ||
2147 | if (socket == NULL) { | 2267 | if (socket == NULL) { |
2148 | rc = sock_create_kern(PF_INET, SOCK_STREAM, | 2268 | rc = sock_create_kern(sfamily, SOCK_STREAM, |
2149 | IPPROTO_TCP, &socket); | 2269 | IPPROTO_TCP, &socket); |
2150 | if (rc < 0) { | 2270 | if (rc < 0) { |
2151 | cERROR(1, "Error %d creating socket", rc); | 2271 | cERROR(1, "Error %d creating socket", rc); |
2272 | server->ssocket = NULL; | ||
2152 | return rc; | 2273 | return rc; |
2153 | } | 2274 | } |
2154 | 2275 | ||
@@ -2156,63 +2277,28 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2156 | cFYI(1, "Socket created"); | 2277 | cFYI(1, "Socket created"); |
2157 | server->ssocket = socket; | 2278 | server->ssocket = socket; |
2158 | socket->sk->sk_allocation = GFP_NOFS; | 2279 | socket->sk->sk_allocation = GFP_NOFS; |
2159 | cifs_reclassify_socket4(socket); | 2280 | if (sfamily == AF_INET6) |
2281 | cifs_reclassify_socket6(socket); | ||
2282 | else | ||
2283 | cifs_reclassify_socket4(socket); | ||
2160 | } | 2284 | } |
2161 | 2285 | ||
2162 | rc = bind_socket(server); | 2286 | rc = bind_socket(server); |
2163 | if (rc < 0) | 2287 | if (rc < 0) |
2164 | return rc; | 2288 | return rc; |
2165 | 2289 | ||
2166 | /* user overrode default port */ | 2290 | rc = socket->ops->connect(socket, saddr, slen, 0); |
2167 | if (server->addr.sockAddr.sin_port) { | 2291 | if (rc < 0) { |
2168 | rc = socket->ops->connect(socket, (struct sockaddr *) | 2292 | cFYI(1, "Error %d connecting to server", rc); |
2169 | &server->addr.sockAddr, | ||
2170 | sizeof(struct sockaddr_in), 0); | ||
2171 | if (rc >= 0) | ||
2172 | connected = true; | ||
2173 | } | ||
2174 | |||
2175 | if (!connected) { | ||
2176 | /* save original port so we can retry user specified port | ||
2177 | later if fall back ports fail this time */ | ||
2178 | orig_port = server->addr.sockAddr.sin_port; | ||
2179 | |||
2180 | /* do not retry on the same port we just failed on */ | ||
2181 | if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) { | ||
2182 | server->addr.sockAddr.sin_port = htons(CIFS_PORT); | ||
2183 | rc = socket->ops->connect(socket, | ||
2184 | (struct sockaddr *) | ||
2185 | &server->addr.sockAddr, | ||
2186 | sizeof(struct sockaddr_in), 0); | ||
2187 | if (rc >= 0) | ||
2188 | connected = true; | ||
2189 | } | ||
2190 | } | ||
2191 | if (!connected) { | ||
2192 | server->addr.sockAddr.sin_port = htons(RFC1001_PORT); | ||
2193 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2194 | &server->addr.sockAddr, | ||
2195 | sizeof(struct sockaddr_in), 0); | ||
2196 | if (rc >= 0) | ||
2197 | connected = true; | ||
2198 | } | ||
2199 | |||
2200 | /* give up here - unless we want to retry on different | ||
2201 | protocol families some day */ | ||
2202 | if (!connected) { | ||
2203 | if (orig_port) | ||
2204 | server->addr.sockAddr.sin_port = orig_port; | ||
2205 | cFYI(1, "Error %d connecting to server via ipv4", rc); | ||
2206 | sock_release(socket); | 2293 | sock_release(socket); |
2207 | server->ssocket = NULL; | 2294 | server->ssocket = NULL; |
2208 | return rc; | 2295 | return rc; |
2209 | } | 2296 | } |
2210 | 2297 | ||
2211 | |||
2212 | /* | 2298 | /* |
2213 | * Eventually check for other socket options to change from | 2299 | * Eventually check for other socket options to change from |
2214 | * the default. sock_setsockopt not used because it expects | 2300 | * the default. sock_setsockopt not used because it expects |
2215 | * user space buffer | 2301 | * user space buffer |
2216 | */ | 2302 | */ |
2217 | socket->sk->sk_rcvtimeo = 7 * HZ; | 2303 | socket->sk->sk_rcvtimeo = 7 * HZ; |
2218 | socket->sk->sk_sndtimeo = 5 * HZ; | 2304 | socket->sk->sk_sndtimeo = 5 * HZ; |
@@ -2226,7 +2312,7 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2226 | } | 2312 | } |
2227 | 2313 | ||
2228 | if (server->tcp_nodelay) { | 2314 | if (server->tcp_nodelay) { |
2229 | val = 1; | 2315 | int val = 1; |
2230 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, | 2316 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, |
2231 | (char *)&val, sizeof(val)); | 2317 | (char *)&val, sizeof(val)); |
2232 | if (rc) | 2318 | if (rc) |
@@ -2237,161 +2323,39 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2237 | socket->sk->sk_sndbuf, | 2323 | socket->sk->sk_sndbuf, |
2238 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); | 2324 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); |
2239 | 2325 | ||
2240 | /* send RFC1001 sessinit */ | 2326 | if (sport == htons(RFC1001_PORT)) |
2241 | if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) { | 2327 | rc = ip_rfc1001_connect(server); |
2242 | /* some servers require RFC1001 sessinit before sending | ||
2243 | negprot - BB check reconnection in case where second | ||
2244 | sessinit is sent but no second negprot */ | ||
2245 | struct rfc1002_session_packet *ses_init_buf; | ||
2246 | struct smb_hdr *smb_buf; | ||
2247 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), | ||
2248 | GFP_KERNEL); | ||
2249 | if (ses_init_buf) { | ||
2250 | ses_init_buf->trailer.session_req.called_len = 32; | ||
2251 | if (server->server_RFC1001_name && | ||
2252 | server->server_RFC1001_name[0] != 0) | ||
2253 | rfc1002mangle(ses_init_buf->trailer. | ||
2254 | session_req.called_name, | ||
2255 | server->server_RFC1001_name, | ||
2256 | RFC1001_NAME_LEN_WITH_NULL); | ||
2257 | else | ||
2258 | rfc1002mangle(ses_init_buf->trailer. | ||
2259 | session_req.called_name, | ||
2260 | DEFAULT_CIFS_CALLED_NAME, | ||
2261 | RFC1001_NAME_LEN_WITH_NULL); | ||
2262 | |||
2263 | ses_init_buf->trailer.session_req.calling_len = 32; | ||
2264 | |||
2265 | /* calling name ends in null (byte 16) from old smb | ||
2266 | convention. */ | ||
2267 | if (server->workstation_RFC1001_name && | ||
2268 | server->workstation_RFC1001_name[0] != 0) | ||
2269 | rfc1002mangle(ses_init_buf->trailer. | ||
2270 | session_req.calling_name, | ||
2271 | server->workstation_RFC1001_name, | ||
2272 | RFC1001_NAME_LEN_WITH_NULL); | ||
2273 | else | ||
2274 | rfc1002mangle(ses_init_buf->trailer. | ||
2275 | session_req.calling_name, | ||
2276 | "LINUX_CIFS_CLNT", | ||
2277 | RFC1001_NAME_LEN_WITH_NULL); | ||
2278 | |||
2279 | ses_init_buf->trailer.session_req.scope1 = 0; | ||
2280 | ses_init_buf->trailer.session_req.scope2 = 0; | ||
2281 | smb_buf = (struct smb_hdr *)ses_init_buf; | ||
2282 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | ||
2283 | smb_buf->smb_buf_length = 0x81000044; | ||
2284 | rc = smb_send(server, smb_buf, 0x44); | ||
2285 | kfree(ses_init_buf); | ||
2286 | msleep(1); /* RFC1001 layer in at least one server | ||
2287 | requires very short break before negprot | ||
2288 | presumably because not expecting negprot | ||
2289 | to follow so fast. This is a simple | ||
2290 | solution that works without | ||
2291 | complicating the code and causes no | ||
2292 | significant slowing down on mount | ||
2293 | for everyone else */ | ||
2294 | } | ||
2295 | /* else the negprot may still work without this | ||
2296 | even though malloc failed */ | ||
2297 | |||
2298 | } | ||
2299 | 2328 | ||
2300 | return rc; | 2329 | return rc; |
2301 | } | 2330 | } |
2302 | 2331 | ||
2303 | static int | 2332 | static int |
2304 | ipv6_connect(struct TCP_Server_Info *server) | 2333 | ip_connect(struct TCP_Server_Info *server) |
2305 | { | 2334 | { |
2306 | int rc = 0; | 2335 | unsigned short int *sport; |
2307 | int val; | 2336 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; |
2308 | bool connected = false; | 2337 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; |
2309 | __be16 orig_port = 0; | ||
2310 | struct socket *socket = server->ssocket; | ||
2311 | 2338 | ||
2312 | if (socket == NULL) { | 2339 | if (server->dstaddr.ss_family == AF_INET6) |
2313 | rc = sock_create_kern(PF_INET6, SOCK_STREAM, | 2340 | sport = &addr6->sin6_port; |
2314 | IPPROTO_TCP, &socket); | 2341 | else |
2315 | if (rc < 0) { | 2342 | sport = &addr->sin_port; |
2316 | cERROR(1, "Error %d creating ipv6 socket", rc); | ||
2317 | socket = NULL; | ||
2318 | return rc; | ||
2319 | } | ||
2320 | 2343 | ||
2321 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | 2344 | if (*sport == 0) { |
2322 | cFYI(1, "ipv6 Socket created"); | 2345 | int rc; |
2323 | server->ssocket = socket; | ||
2324 | socket->sk->sk_allocation = GFP_NOFS; | ||
2325 | cifs_reclassify_socket6(socket); | ||
2326 | } | ||
2327 | 2346 | ||
2328 | rc = bind_socket(server); | 2347 | /* try with 445 port at first */ |
2329 | if (rc < 0) | 2348 | *sport = htons(CIFS_PORT); |
2330 | return rc; | ||
2331 | 2349 | ||
2332 | /* user overrode default port */ | 2350 | rc = generic_ip_connect(server); |
2333 | if (server->addr.sockAddr6.sin6_port) { | ||
2334 | rc = socket->ops->connect(socket, | ||
2335 | (struct sockaddr *) &server->addr.sockAddr6, | ||
2336 | sizeof(struct sockaddr_in6), 0); | ||
2337 | if (rc >= 0) | ||
2338 | connected = true; | ||
2339 | } | ||
2340 | |||
2341 | if (!connected) { | ||
2342 | /* save original port so we can retry user specified port | ||
2343 | later if fall back ports fail this time */ | ||
2344 | |||
2345 | orig_port = server->addr.sockAddr6.sin6_port; | ||
2346 | /* do not retry on the same port we just failed on */ | ||
2347 | if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) { | ||
2348 | server->addr.sockAddr6.sin6_port = htons(CIFS_PORT); | ||
2349 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2350 | &server->addr.sockAddr6, | ||
2351 | sizeof(struct sockaddr_in6), 0); | ||
2352 | if (rc >= 0) | ||
2353 | connected = true; | ||
2354 | } | ||
2355 | } | ||
2356 | if (!connected) { | ||
2357 | server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT); | ||
2358 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2359 | &server->addr.sockAddr6, | ||
2360 | sizeof(struct sockaddr_in6), 0); | ||
2361 | if (rc >= 0) | 2351 | if (rc >= 0) |
2362 | connected = true; | 2352 | return rc; |
2363 | } | ||
2364 | |||
2365 | /* give up here - unless we want to retry on different | ||
2366 | protocol families some day */ | ||
2367 | if (!connected) { | ||
2368 | if (orig_port) | ||
2369 | server->addr.sockAddr6.sin6_port = orig_port; | ||
2370 | cFYI(1, "Error %d connecting to server via ipv6", rc); | ||
2371 | sock_release(socket); | ||
2372 | server->ssocket = NULL; | ||
2373 | return rc; | ||
2374 | } | ||
2375 | |||
2376 | /* | ||
2377 | * Eventually check for other socket options to change from | ||
2378 | * the default. sock_setsockopt not used because it expects | ||
2379 | * user space buffer | ||
2380 | */ | ||
2381 | socket->sk->sk_rcvtimeo = 7 * HZ; | ||
2382 | socket->sk->sk_sndtimeo = 5 * HZ; | ||
2383 | 2353 | ||
2384 | if (server->tcp_nodelay) { | 2354 | /* if it failed, try with 139 port */ |
2385 | val = 1; | 2355 | *sport = htons(RFC1001_PORT); |
2386 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, | ||
2387 | (char *)&val, sizeof(val)); | ||
2388 | if (rc) | ||
2389 | cFYI(1, "set TCP_NODELAY socket option error %d", rc); | ||
2390 | } | 2356 | } |
2391 | 2357 | ||
2392 | server->ssocket = socket; | 2358 | return generic_ip_connect(server); |
2393 | |||
2394 | return rc; | ||
2395 | } | 2359 | } |
2396 | 2360 | ||
2397 | void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, | 2361 | void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index db2a58c00f7b..2e773825835e 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -293,10 +293,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
293 | args.uid = NO_CHANGE_64; | 293 | args.uid = NO_CHANGE_64; |
294 | args.gid = NO_CHANGE_64; | 294 | args.gid = NO_CHANGE_64; |
295 | } | 295 | } |
296 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, | 296 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle, |
297 | cifs_sb->local_nls, | 297 | current->tgid); |
298 | cifs_sb->mnt_cifs_flags & | ||
299 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
300 | } else { | 298 | } else { |
301 | /* BB implement mode setting via Windows security | 299 | /* BB implement mode setting via Windows security |
302 | descriptors e.g. */ | 300 | descriptors e.g. */ |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5a28660ca2b5..d843631c028d 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -104,53 +104,6 @@ static inline int cifs_get_disposition(unsigned int flags) | |||
104 | return FILE_OPEN; | 104 | return FILE_OPEN; |
105 | } | 105 | } |
106 | 106 | ||
107 | static inline int cifs_open_inode_helper(struct inode *inode, | ||
108 | struct cifsTconInfo *pTcon, __u32 oplock, FILE_ALL_INFO *buf, | ||
109 | char *full_path, int xid) | ||
110 | { | ||
111 | struct cifsInodeInfo *pCifsInode = CIFS_I(inode); | ||
112 | struct timespec temp; | ||
113 | int rc; | ||
114 | |||
115 | if (pCifsInode->clientCanCacheRead) { | ||
116 | /* we have the inode open somewhere else | ||
117 | no need to discard cache data */ | ||
118 | goto client_can_cache; | ||
119 | } | ||
120 | |||
121 | /* BB need same check in cifs_create too? */ | ||
122 | /* if not oplocked, invalidate inode pages if mtime or file | ||
123 | size changed */ | ||
124 | temp = cifs_NTtimeToUnix(buf->LastWriteTime); | ||
125 | if (timespec_equal(&inode->i_mtime, &temp) && | ||
126 | (inode->i_size == | ||
127 | (loff_t)le64_to_cpu(buf->EndOfFile))) { | ||
128 | cFYI(1, "inode unchanged on server"); | ||
129 | } else { | ||
130 | if (inode->i_mapping) { | ||
131 | /* BB no need to lock inode until after invalidate | ||
132 | since namei code should already have it locked? */ | ||
133 | rc = filemap_write_and_wait(inode->i_mapping); | ||
134 | mapping_set_error(inode->i_mapping, rc); | ||
135 | } | ||
136 | cFYI(1, "invalidating remote inode since open detected it " | ||
137 | "changed"); | ||
138 | invalidate_remote_inode(inode); | ||
139 | } | ||
140 | |||
141 | client_can_cache: | ||
142 | if (pTcon->unix_ext) | ||
143 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, | ||
144 | xid); | ||
145 | else | ||
146 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, | ||
147 | xid, NULL); | ||
148 | |||
149 | cifs_set_oplock_level(pCifsInode, oplock); | ||
150 | |||
151 | return rc; | ||
152 | } | ||
153 | |||
154 | int cifs_posix_open(char *full_path, struct inode **pinode, | 107 | int cifs_posix_open(char *full_path, struct inode **pinode, |
155 | struct super_block *sb, int mode, unsigned int f_flags, | 108 | struct super_block *sb, int mode, unsigned int f_flags, |
156 | __u32 *poplock, __u16 *pnetfid, int xid) | 109 | __u32 *poplock, __u16 *pnetfid, int xid) |
@@ -213,6 +166,76 @@ posix_open_ret: | |||
213 | return rc; | 166 | return rc; |
214 | } | 167 | } |
215 | 168 | ||
169 | static int | ||
170 | cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, | ||
171 | struct cifsTconInfo *tcon, unsigned int f_flags, __u32 *poplock, | ||
172 | __u16 *pnetfid, int xid) | ||
173 | { | ||
174 | int rc; | ||
175 | int desiredAccess; | ||
176 | int disposition; | ||
177 | FILE_ALL_INFO *buf; | ||
178 | |||
179 | desiredAccess = cifs_convert_flags(f_flags); | ||
180 | |||
181 | /********************************************************************* | ||
182 | * open flag mapping table: | ||
183 | * | ||
184 | * POSIX Flag CIFS Disposition | ||
185 | * ---------- ---------------- | ||
186 | * O_CREAT FILE_OPEN_IF | ||
187 | * O_CREAT | O_EXCL FILE_CREATE | ||
188 | * O_CREAT | O_TRUNC FILE_OVERWRITE_IF | ||
189 | * O_TRUNC FILE_OVERWRITE | ||
190 | * none of the above FILE_OPEN | ||
191 | * | ||
192 | * Note that there is not a direct match between disposition | ||
193 | * FILE_SUPERSEDE (ie create whether or not file exists although | ||
194 | * O_CREAT | O_TRUNC is similar but truncates the existing | ||
195 | * file rather than creating a new file as FILE_SUPERSEDE does | ||
196 | * (which uses the attributes / metadata passed in on open call) | ||
197 | *? | ||
198 | *? O_SYNC is a reasonable match to CIFS writethrough flag | ||
199 | *? and the read write flags match reasonably. O_LARGEFILE | ||
200 | *? is irrelevant because largefile support is always used | ||
201 | *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, | ||
202 | * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation | ||
203 | *********************************************************************/ | ||
204 | |||
205 | disposition = cifs_get_disposition(f_flags); | ||
206 | |||
207 | /* BB pass O_SYNC flag through on file attributes .. BB */ | ||
208 | |||
209 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
210 | if (!buf) | ||
211 | return -ENOMEM; | ||
212 | |||
213 | if (tcon->ses->capabilities & CAP_NT_SMBS) | ||
214 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | ||
215 | desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf, | ||
216 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
217 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
218 | else | ||
219 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, | ||
220 | desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf, | ||
221 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
222 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
223 | |||
224 | if (rc) | ||
225 | goto out; | ||
226 | |||
227 | if (tcon->unix_ext) | ||
228 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, | ||
229 | xid); | ||
230 | else | ||
231 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, | ||
232 | xid, pnetfid); | ||
233 | |||
234 | out: | ||
235 | kfree(buf); | ||
236 | return rc; | ||
237 | } | ||
238 | |||
216 | struct cifsFileInfo * | 239 | struct cifsFileInfo * |
217 | cifs_new_fileinfo(__u16 fileHandle, struct file *file, | 240 | cifs_new_fileinfo(__u16 fileHandle, struct file *file, |
218 | struct tcon_link *tlink, __u32 oplock) | 241 | struct tcon_link *tlink, __u32 oplock) |
@@ -317,10 +340,8 @@ int cifs_open(struct inode *inode, struct file *file) | |||
317 | struct cifsFileInfo *pCifsFile = NULL; | 340 | struct cifsFileInfo *pCifsFile = NULL; |
318 | struct cifsInodeInfo *pCifsInode; | 341 | struct cifsInodeInfo *pCifsInode; |
319 | char *full_path = NULL; | 342 | char *full_path = NULL; |
320 | int desiredAccess; | 343 | bool posix_open_ok = false; |
321 | int disposition; | ||
322 | __u16 netfid; | 344 | __u16 netfid; |
323 | FILE_ALL_INFO *buf = NULL; | ||
324 | 345 | ||
325 | xid = GetXid(); | 346 | xid = GetXid(); |
326 | 347 | ||
@@ -358,17 +379,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
358 | file->f_flags, &oplock, &netfid, xid); | 379 | file->f_flags, &oplock, &netfid, xid); |
359 | if (rc == 0) { | 380 | if (rc == 0) { |
360 | cFYI(1, "posix open succeeded"); | 381 | cFYI(1, "posix open succeeded"); |
361 | 382 | posix_open_ok = true; | |
362 | pCifsFile = cifs_new_fileinfo(netfid, file, tlink, | ||
363 | oplock); | ||
364 | if (pCifsFile == NULL) { | ||
365 | CIFSSMBClose(xid, tcon, netfid); | ||
366 | rc = -ENOMEM; | ||
367 | } | ||
368 | |||
369 | cifs_fscache_set_inode_cookie(inode, file); | ||
370 | |||
371 | goto out; | ||
372 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | 383 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { |
373 | if (tcon->ses->serverNOS) | 384 | if (tcon->ses->serverNOS) |
374 | cERROR(1, "server %s of type %s returned" | 385 | cERROR(1, "server %s of type %s returned" |
@@ -385,103 +396,39 @@ int cifs_open(struct inode *inode, struct file *file) | |||
385 | or DFS errors */ | 396 | or DFS errors */ |
386 | } | 397 | } |
387 | 398 | ||
388 | desiredAccess = cifs_convert_flags(file->f_flags); | 399 | if (!posix_open_ok) { |
389 | 400 | rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, | |
390 | /********************************************************************* | 401 | file->f_flags, &oplock, &netfid, xid); |
391 | * open flag mapping table: | 402 | if (rc) |
392 | * | 403 | goto out; |
393 | * POSIX Flag CIFS Disposition | ||
394 | * ---------- ---------------- | ||
395 | * O_CREAT FILE_OPEN_IF | ||
396 | * O_CREAT | O_EXCL FILE_CREATE | ||
397 | * O_CREAT | O_TRUNC FILE_OVERWRITE_IF | ||
398 | * O_TRUNC FILE_OVERWRITE | ||
399 | * none of the above FILE_OPEN | ||
400 | * | ||
401 | * Note that there is not a direct match between disposition | ||
402 | * FILE_SUPERSEDE (ie create whether or not file exists although | ||
403 | * O_CREAT | O_TRUNC is similar but truncates the existing | ||
404 | * file rather than creating a new file as FILE_SUPERSEDE does | ||
405 | * (which uses the attributes / metadata passed in on open call) | ||
406 | *? | ||
407 | *? O_SYNC is a reasonable match to CIFS writethrough flag | ||
408 | *? and the read write flags match reasonably. O_LARGEFILE | ||
409 | *? is irrelevant because largefile support is always used | ||
410 | *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, | ||
411 | * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation | ||
412 | *********************************************************************/ | ||
413 | |||
414 | disposition = cifs_get_disposition(file->f_flags); | ||
415 | |||
416 | /* BB pass O_SYNC flag through on file attributes .. BB */ | ||
417 | |||
418 | /* Also refresh inode by passing in file_info buf returned by SMBOpen | ||
419 | and calling get_inode_info with returned buf (at least helps | ||
420 | non-Unix server case) */ | ||
421 | |||
422 | /* BB we can not do this if this is the second open of a file | ||
423 | and the first handle has writebehind data, we might be | ||
424 | able to simply do a filemap_fdatawrite/filemap_fdatawait first */ | ||
425 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
426 | if (!buf) { | ||
427 | rc = -ENOMEM; | ||
428 | goto out; | ||
429 | } | ||
430 | |||
431 | if (tcon->ses->capabilities & CAP_NT_SMBS) | ||
432 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | ||
433 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
434 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
435 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
436 | else | ||
437 | rc = -EIO; /* no NT SMB support fall into legacy open below */ | ||
438 | |||
439 | if (rc == -EIO) { | ||
440 | /* Old server, try legacy style OpenX */ | ||
441 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, | ||
442 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
443 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
444 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
445 | } | ||
446 | if (rc) { | ||
447 | cFYI(1, "cifs_open returned 0x%x", rc); | ||
448 | goto out; | ||
449 | } | 404 | } |
450 | 405 | ||
451 | rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid); | ||
452 | if (rc != 0) | ||
453 | goto out; | ||
454 | |||
455 | pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock); | 406 | pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock); |
456 | if (pCifsFile == NULL) { | 407 | if (pCifsFile == NULL) { |
408 | CIFSSMBClose(xid, tcon, netfid); | ||
457 | rc = -ENOMEM; | 409 | rc = -ENOMEM; |
458 | goto out; | 410 | goto out; |
459 | } | 411 | } |
460 | 412 | ||
461 | cifs_fscache_set_inode_cookie(inode, file); | 413 | cifs_fscache_set_inode_cookie(inode, file); |
462 | 414 | ||
463 | if (oplock & CIFS_CREATE_ACTION) { | 415 | if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) { |
464 | /* time to set mode which we can not set earlier due to | 416 | /* time to set mode which we can not set earlier due to |
465 | problems creating new read-only files */ | 417 | problems creating new read-only files */ |
466 | if (tcon->unix_ext) { | 418 | struct cifs_unix_set_info_args args = { |
467 | struct cifs_unix_set_info_args args = { | 419 | .mode = inode->i_mode, |
468 | .mode = inode->i_mode, | 420 | .uid = NO_CHANGE_64, |
469 | .uid = NO_CHANGE_64, | 421 | .gid = NO_CHANGE_64, |
470 | .gid = NO_CHANGE_64, | 422 | .ctime = NO_CHANGE_64, |
471 | .ctime = NO_CHANGE_64, | 423 | .atime = NO_CHANGE_64, |
472 | .atime = NO_CHANGE_64, | 424 | .mtime = NO_CHANGE_64, |
473 | .mtime = NO_CHANGE_64, | 425 | .device = 0, |
474 | .device = 0, | 426 | }; |
475 | }; | 427 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid, |
476 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, | 428 | pCifsFile->pid); |
477 | cifs_sb->local_nls, | ||
478 | cifs_sb->mnt_cifs_flags & | ||
479 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
480 | } | ||
481 | } | 429 | } |
482 | 430 | ||
483 | out: | 431 | out: |
484 | kfree(buf); | ||
485 | kfree(full_path); | 432 | kfree(full_path); |
486 | FreeXid(xid); | 433 | FreeXid(xid); |
487 | cifs_put_tlink(tlink); | 434 | cifs_put_tlink(tlink); |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a853a89857a5..0c7e36910e31 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -518,6 +518,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, | |||
518 | 518 | ||
519 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); | 519 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
520 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | 520 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
521 | fattr->cf_createtime = le64_to_cpu(info->CreationTime); | ||
521 | 522 | ||
522 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { | 523 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { |
523 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; | 524 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; |
@@ -779,6 +780,10 @@ cifs_find_inode(struct inode *inode, void *opaque) | |||
779 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) | 780 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) |
780 | return 0; | 781 | return 0; |
781 | 782 | ||
783 | /* use createtime like an i_generation field */ | ||
784 | if (CIFS_I(inode)->createtime != fattr->cf_createtime) | ||
785 | return 0; | ||
786 | |||
782 | /* don't match inode of different type */ | 787 | /* don't match inode of different type */ |
783 | if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) | 788 | if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) |
784 | return 0; | 789 | return 0; |
@@ -796,6 +801,7 @@ cifs_init_inode(struct inode *inode, void *opaque) | |||
796 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; | 801 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; |
797 | 802 | ||
798 | CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; | 803 | CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; |
804 | CIFS_I(inode)->createtime = fattr->cf_createtime; | ||
799 | return 0; | 805 | return 0; |
800 | } | 806 | } |
801 | 807 | ||
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index ec5b68e3b928..76b1b37c9e6b 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -160,6 +160,7 @@ cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info, | |||
160 | fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); | 160 | fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); |
161 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); | 161 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
162 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | 162 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
163 | fattr->cf_createtime = le64_to_cpu(info->CreationTime); | ||
163 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); | 164 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
164 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); | 165 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
165 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); | 166 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 7b01d3f6eed6..eb746486e49e 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -420,7 +420,6 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | |||
420 | return 0; | 420 | return 0; |
421 | } | 421 | } |
422 | 422 | ||
423 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
424 | /* BB Move to ntlmssp.c eventually */ | 423 | /* BB Move to ntlmssp.c eventually */ |
425 | 424 | ||
426 | /* We do not malloc the blob, it is passed in pbuffer, because | 425 | /* We do not malloc the blob, it is passed in pbuffer, because |
@@ -431,13 +430,14 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | |||
431 | NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer; | 430 | NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer; |
432 | __u32 flags; | 431 | __u32 flags; |
433 | 432 | ||
433 | memset(pbuffer, 0, sizeof(NEGOTIATE_MESSAGE)); | ||
434 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | 434 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); |
435 | sec_blob->MessageType = NtLmNegotiate; | 435 | sec_blob->MessageType = NtLmNegotiate; |
436 | 436 | ||
437 | /* BB is NTLMV2 session security format easier to use here? */ | 437 | /* BB is NTLMV2 session security format easier to use here? */ |
438 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | | 438 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | |
439 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | 439 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | |
440 | NTLMSSP_NEGOTIATE_NTLM; | 440 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; |
441 | if (ses->server->secMode & | 441 | if (ses->server->secMode & |
442 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { | 442 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { |
443 | flags |= NTLMSSP_NEGOTIATE_SIGN; | 443 | flags |= NTLMSSP_NEGOTIATE_SIGN; |
@@ -446,7 +446,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | |||
446 | NTLMSSP_NEGOTIATE_EXTENDED_SEC; | 446 | NTLMSSP_NEGOTIATE_EXTENDED_SEC; |
447 | } | 447 | } |
448 | 448 | ||
449 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | 449 | sec_blob->NegotiateFlags = cpu_to_le32(flags); |
450 | 450 | ||
451 | sec_blob->WorkstationName.BufferOffset = 0; | 451 | sec_blob->WorkstationName.BufferOffset = 0; |
452 | sec_blob->WorkstationName.Length = 0; | 452 | sec_blob->WorkstationName.Length = 0; |
@@ -477,7 +477,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
477 | flags = NTLMSSP_NEGOTIATE_56 | | 477 | flags = NTLMSSP_NEGOTIATE_56 | |
478 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | | 478 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | |
479 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | 479 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | |
480 | NTLMSSP_NEGOTIATE_NTLM; | 480 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; |
481 | if (ses->server->secMode & | 481 | if (ses->server->secMode & |
482 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 482 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
483 | flags |= NTLMSSP_NEGOTIATE_SIGN; | 483 | flags |= NTLMSSP_NEGOTIATE_SIGN; |
@@ -485,7 +485,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
485 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; | 485 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; |
486 | 486 | ||
487 | tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); | 487 | tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); |
488 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | 488 | sec_blob->NegotiateFlags = cpu_to_le32(flags); |
489 | 489 | ||
490 | sec_blob->LmChallengeResponse.BufferOffset = | 490 | sec_blob->LmChallengeResponse.BufferOffset = |
491 | cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE)); | 491 | cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE)); |
@@ -544,8 +544,9 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
544 | sec_blob->WorkstationName.MaximumLength = 0; | 544 | sec_blob->WorkstationName.MaximumLength = 0; |
545 | tmp += 2; | 545 | tmp += 2; |
546 | 546 | ||
547 | if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && | 547 | if (((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) || |
548 | !calc_seckey(ses)) { | 548 | (ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC)) |
549 | && !calc_seckey(ses)) { | ||
549 | memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); | 550 | memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); |
550 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | 551 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); |
551 | sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); | 552 | sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); |
@@ -563,17 +564,6 @@ setup_ntlmv2_ret: | |||
563 | return rc; | 564 | return rc; |
564 | } | 565 | } |
565 | 566 | ||
566 | |||
567 | static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, | ||
568 | struct cifsSesInfo *ses) | ||
569 | { | ||
570 | build_ntlmssp_negotiate_blob(&pSMB->req.SecurityBlob[0], ses); | ||
571 | pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
572 | |||
573 | return; | ||
574 | } | ||
575 | #endif | ||
576 | |||
577 | int | 567 | int |
578 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | 568 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, |
579 | const struct nls_table *nls_cp) | 569 | const struct nls_table *nls_cp) |
@@ -814,71 +804,70 @@ ssetup_ntlmssp_authenticate: | |||
814 | rc = -ENOSYS; | 804 | rc = -ENOSYS; |
815 | goto ssetup_exit; | 805 | goto ssetup_exit; |
816 | #endif /* CONFIG_CIFS_UPCALL */ | 806 | #endif /* CONFIG_CIFS_UPCALL */ |
817 | } else { | 807 | } else if (type == RawNTLMSSP) { |
818 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 808 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { |
819 | if (type == RawNTLMSSP) { | 809 | cERROR(1, "NTLMSSP requires Unicode support"); |
820 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | 810 | rc = -ENOSYS; |
821 | cERROR(1, "NTLMSSP requires Unicode support"); | 811 | goto ssetup_exit; |
822 | rc = -ENOSYS; | 812 | } |
813 | |||
814 | cFYI(1, "ntlmssp session setup phase %d", phase); | ||
815 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
816 | capabilities |= CAP_EXTENDED_SECURITY; | ||
817 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); | ||
818 | switch(phase) { | ||
819 | case NtLmNegotiate: | ||
820 | build_ntlmssp_negotiate_blob( | ||
821 | pSMB->req.SecurityBlob, ses); | ||
822 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
823 | iov[1].iov_base = pSMB->req.SecurityBlob; | ||
824 | pSMB->req.SecurityBlobLength = | ||
825 | cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
826 | break; | ||
827 | case NtLmAuthenticate: | ||
828 | /* | ||
829 | * 5 is an empirical value, large enough to hold | ||
830 | * authenticate message plus max 10 of av paris, | ||
831 | * domain, user, workstation names, flags, etc. | ||
832 | */ | ||
833 | ntlmsspblob = kzalloc( | ||
834 | 5*sizeof(struct _AUTHENTICATE_MESSAGE), | ||
835 | GFP_KERNEL); | ||
836 | if (!ntlmsspblob) { | ||
837 | cERROR(1, "Can't allocate NTLMSSP blob"); | ||
838 | rc = -ENOMEM; | ||
823 | goto ssetup_exit; | 839 | goto ssetup_exit; |
824 | } | 840 | } |
825 | 841 | ||
826 | cFYI(1, "ntlmssp session setup phase %d", phase); | 842 | rc = build_ntlmssp_auth_blob(ntlmsspblob, |
827 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 843 | &blob_len, ses, nls_cp); |
828 | capabilities |= CAP_EXTENDED_SECURITY; | 844 | if (rc) |
829 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); | ||
830 | if (phase == NtLmNegotiate) { | ||
831 | setup_ntlmssp_neg_req(pSMB, ses); | ||
832 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
833 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | ||
834 | } else if (phase == NtLmAuthenticate) { | ||
835 | /* 5 is an empirical value, large enought to | ||
836 | * hold authenticate message, max 10 of | ||
837 | * av paris, doamin,user,workstation mames, | ||
838 | * flags etc.. | ||
839 | */ | ||
840 | ntlmsspblob = kmalloc( | ||
841 | 5*sizeof(struct _AUTHENTICATE_MESSAGE), | ||
842 | GFP_KERNEL); | ||
843 | if (!ntlmsspblob) { | ||
844 | cERROR(1, "Can't allocate NTLMSSP"); | ||
845 | rc = -ENOMEM; | ||
846 | goto ssetup_exit; | ||
847 | } | ||
848 | |||
849 | rc = build_ntlmssp_auth_blob(ntlmsspblob, | ||
850 | &blob_len, ses, nls_cp); | ||
851 | if (rc) | ||
852 | goto ssetup_exit; | ||
853 | iov[1].iov_len = blob_len; | ||
854 | iov[1].iov_base = ntlmsspblob; | ||
855 | pSMB->req.SecurityBlobLength = | ||
856 | cpu_to_le16(blob_len); | ||
857 | /* Make sure that we tell the server that we | ||
858 | are using the uid that it just gave us back | ||
859 | on the response (challenge) */ | ||
860 | smb_buf->Uid = ses->Suid; | ||
861 | } else { | ||
862 | cERROR(1, "invalid phase %d", phase); | ||
863 | rc = -ENOSYS; | ||
864 | goto ssetup_exit; | 845 | goto ssetup_exit; |
865 | } | 846 | iov[1].iov_len = blob_len; |
866 | /* unicode strings must be word aligned */ | 847 | iov[1].iov_base = ntlmsspblob; |
867 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | 848 | pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len); |
868 | *bcc_ptr = 0; | 849 | /* |
869 | bcc_ptr++; | 850 | * Make sure that we tell the server that we are using |
870 | } | 851 | * the uid that it just gave us back on the response |
871 | unicode_oslm_strings(&bcc_ptr, nls_cp); | 852 | * (challenge) |
872 | } else { | 853 | */ |
873 | cERROR(1, "secType %d not supported!", type); | 854 | smb_buf->Uid = ses->Suid; |
855 | break; | ||
856 | default: | ||
857 | cERROR(1, "invalid phase %d", phase); | ||
874 | rc = -ENOSYS; | 858 | rc = -ENOSYS; |
875 | goto ssetup_exit; | 859 | goto ssetup_exit; |
876 | } | 860 | } |
877 | #else | 861 | /* unicode strings must be word aligned */ |
862 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | ||
863 | *bcc_ptr = 0; | ||
864 | bcc_ptr++; | ||
865 | } | ||
866 | unicode_oslm_strings(&bcc_ptr, nls_cp); | ||
867 | } else { | ||
878 | cERROR(1, "secType %d not supported!", type); | 868 | cERROR(1, "secType %d not supported!", type); |
879 | rc = -ENOSYS; | 869 | rc = -ENOSYS; |
880 | goto ssetup_exit; | 870 | goto ssetup_exit; |
881 | #endif | ||
882 | } | 871 | } |
883 | 872 | ||
884 | iov[2].iov_base = str_area; | 873 | iov[2].iov_base = str_area; |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index e0588cdf4cc5..59ca81b16919 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -119,7 +119,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | |||
119 | if (ssocket == NULL) | 119 | if (ssocket == NULL) |
120 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 120 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
121 | 121 | ||
122 | smb_msg.msg_name = (struct sockaddr *) &server->addr.sockAddr; | 122 | smb_msg.msg_name = (struct sockaddr *) &server->dstaddr; |
123 | smb_msg.msg_namelen = sizeof(struct sockaddr); | 123 | smb_msg.msg_namelen = sizeof(struct sockaddr); |
124 | smb_msg.msg_control = NULL; | 124 | smb_msg.msg_control = NULL; |
125 | smb_msg.msg_controllen = 0; | 125 | smb_msg.msg_controllen = 0; |
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 37a34c2c622a..9c64ae9e4c1a 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c | |||
@@ -63,6 +63,9 @@ | |||
63 | #define NEEDED_RMEM (4*1024*1024) | 63 | #define NEEDED_RMEM (4*1024*1024) |
64 | #define CONN_HASH_SIZE 32 | 64 | #define CONN_HASH_SIZE 32 |
65 | 65 | ||
66 | /* Number of messages to send before rescheduling */ | ||
67 | #define MAX_SEND_MSG_COUNT 25 | ||
68 | |||
66 | struct cbuf { | 69 | struct cbuf { |
67 | unsigned int base; | 70 | unsigned int base; |
68 | unsigned int len; | 71 | unsigned int len; |
@@ -108,6 +111,7 @@ struct connection { | |||
108 | #define CF_INIT_PENDING 4 | 111 | #define CF_INIT_PENDING 4 |
109 | #define CF_IS_OTHERCON 5 | 112 | #define CF_IS_OTHERCON 5 |
110 | #define CF_CLOSE 6 | 113 | #define CF_CLOSE 6 |
114 | #define CF_APP_LIMITED 7 | ||
111 | struct list_head writequeue; /* List of outgoing writequeue_entries */ | 115 | struct list_head writequeue; /* List of outgoing writequeue_entries */ |
112 | spinlock_t writequeue_lock; | 116 | spinlock_t writequeue_lock; |
113 | int (*rx_action) (struct connection *); /* What to do when active */ | 117 | int (*rx_action) (struct connection *); /* What to do when active */ |
@@ -295,7 +299,17 @@ static void lowcomms_write_space(struct sock *sk) | |||
295 | { | 299 | { |
296 | struct connection *con = sock2con(sk); | 300 | struct connection *con = sock2con(sk); |
297 | 301 | ||
298 | if (con && !test_and_set_bit(CF_WRITE_PENDING, &con->flags)) | 302 | if (!con) |
303 | return; | ||
304 | |||
305 | clear_bit(SOCK_NOSPACE, &con->sock->flags); | ||
306 | |||
307 | if (test_and_clear_bit(CF_APP_LIMITED, &con->flags)) { | ||
308 | con->sock->sk->sk_write_pending--; | ||
309 | clear_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags); | ||
310 | } | ||
311 | |||
312 | if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) | ||
299 | queue_work(send_workqueue, &con->swork); | 313 | queue_work(send_workqueue, &con->swork); |
300 | } | 314 | } |
301 | 315 | ||
@@ -915,6 +929,7 @@ static void tcp_connect_to_sock(struct connection *con) | |||
915 | struct sockaddr_storage saddr, src_addr; | 929 | struct sockaddr_storage saddr, src_addr; |
916 | int addr_len; | 930 | int addr_len; |
917 | struct socket *sock = NULL; | 931 | struct socket *sock = NULL; |
932 | int one = 1; | ||
918 | 933 | ||
919 | if (con->nodeid == 0) { | 934 | if (con->nodeid == 0) { |
920 | log_print("attempt to connect sock 0 foiled"); | 935 | log_print("attempt to connect sock 0 foiled"); |
@@ -960,6 +975,11 @@ static void tcp_connect_to_sock(struct connection *con) | |||
960 | make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len); | 975 | make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len); |
961 | 976 | ||
962 | log_print("connecting to %d", con->nodeid); | 977 | log_print("connecting to %d", con->nodeid); |
978 | |||
979 | /* Turn off Nagle's algorithm */ | ||
980 | kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one, | ||
981 | sizeof(one)); | ||
982 | |||
963 | result = | 983 | result = |
964 | sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len, | 984 | sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len, |
965 | O_NONBLOCK); | 985 | O_NONBLOCK); |
@@ -1011,6 +1031,10 @@ static struct socket *tcp_create_listen_sock(struct connection *con, | |||
1011 | goto create_out; | 1031 | goto create_out; |
1012 | } | 1032 | } |
1013 | 1033 | ||
1034 | /* Turn off Nagle's algorithm */ | ||
1035 | kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one, | ||
1036 | sizeof(one)); | ||
1037 | |||
1014 | result = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, | 1038 | result = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, |
1015 | (char *)&one, sizeof(one)); | 1039 | (char *)&one, sizeof(one)); |
1016 | 1040 | ||
@@ -1297,6 +1321,7 @@ static void send_to_sock(struct connection *con) | |||
1297 | const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; | 1321 | const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; |
1298 | struct writequeue_entry *e; | 1322 | struct writequeue_entry *e; |
1299 | int len, offset; | 1323 | int len, offset; |
1324 | int count = 0; | ||
1300 | 1325 | ||
1301 | mutex_lock(&con->sock_mutex); | 1326 | mutex_lock(&con->sock_mutex); |
1302 | if (con->sock == NULL) | 1327 | if (con->sock == NULL) |
@@ -1319,14 +1344,27 @@ static void send_to_sock(struct connection *con) | |||
1319 | ret = kernel_sendpage(con->sock, e->page, offset, len, | 1344 | ret = kernel_sendpage(con->sock, e->page, offset, len, |
1320 | msg_flags); | 1345 | msg_flags); |
1321 | if (ret == -EAGAIN || ret == 0) { | 1346 | if (ret == -EAGAIN || ret == 0) { |
1347 | if (ret == -EAGAIN && | ||
1348 | test_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags) && | ||
1349 | !test_and_set_bit(CF_APP_LIMITED, &con->flags)) { | ||
1350 | /* Notify TCP that we're limited by the | ||
1351 | * application window size. | ||
1352 | */ | ||
1353 | set_bit(SOCK_NOSPACE, &con->sock->flags); | ||
1354 | con->sock->sk->sk_write_pending++; | ||
1355 | } | ||
1322 | cond_resched(); | 1356 | cond_resched(); |
1323 | goto out; | 1357 | goto out; |
1324 | } | 1358 | } |
1325 | if (ret <= 0) | 1359 | if (ret <= 0) |
1326 | goto send_error; | 1360 | goto send_error; |
1327 | } | 1361 | } |
1328 | /* Don't starve people filling buffers */ | 1362 | |
1363 | /* Don't starve people filling buffers */ | ||
1364 | if (++count >= MAX_SEND_MSG_COUNT) { | ||
1329 | cond_resched(); | 1365 | cond_resched(); |
1366 | count = 0; | ||
1367 | } | ||
1330 | 1368 | ||
1331 | spin_lock(&con->writequeue_lock); | 1369 | spin_lock(&con->writequeue_lock); |
1332 | e->offset += ret; | 1370 | e->offset += ret; |
@@ -1430,20 +1468,19 @@ static void work_stop(void) | |||
1430 | 1468 | ||
1431 | static int work_start(void) | 1469 | static int work_start(void) |
1432 | { | 1470 | { |
1433 | int error; | 1471 | recv_workqueue = alloc_workqueue("dlm_recv", WQ_MEM_RECLAIM | |
1434 | recv_workqueue = create_workqueue("dlm_recv"); | 1472 | WQ_HIGHPRI | WQ_FREEZEABLE, 0); |
1435 | error = IS_ERR(recv_workqueue); | 1473 | if (!recv_workqueue) { |
1436 | if (error) { | 1474 | log_print("can't start dlm_recv"); |
1437 | log_print("can't start dlm_recv %d", error); | 1475 | return -ENOMEM; |
1438 | return error; | ||
1439 | } | 1476 | } |
1440 | 1477 | ||
1441 | send_workqueue = create_singlethread_workqueue("dlm_send"); | 1478 | send_workqueue = alloc_workqueue("dlm_send", WQ_MEM_RECLAIM | |
1442 | error = IS_ERR(send_workqueue); | 1479 | WQ_HIGHPRI | WQ_FREEZEABLE, 0); |
1443 | if (error) { | 1480 | if (!send_workqueue) { |
1444 | log_print("can't start dlm_send %d", error); | 1481 | log_print("can't start dlm_send"); |
1445 | destroy_workqueue(recv_workqueue); | 1482 | destroy_workqueue(recv_workqueue); |
1446 | return error; | 1483 | return -ENOMEM; |
1447 | } | 1484 | } |
1448 | 1485 | ||
1449 | return 0; | 1486 | return 0; |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 6e07696308dc..cf8d28d1fbad 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -251,6 +251,20 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req) | |||
251 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | 251 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); |
252 | } | 252 | } |
253 | 253 | ||
254 | void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, | ||
255 | u64 nodeid, u64 nlookup) | ||
256 | { | ||
257 | forget->forget_one.nodeid = nodeid; | ||
258 | forget->forget_one.nlookup = nlookup; | ||
259 | |||
260 | spin_lock(&fc->lock); | ||
261 | fc->forget_list_tail->next = forget; | ||
262 | fc->forget_list_tail = forget; | ||
263 | wake_up(&fc->waitq); | ||
264 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | ||
265 | spin_unlock(&fc->lock); | ||
266 | } | ||
267 | |||
254 | static void flush_bg_queue(struct fuse_conn *fc) | 268 | static void flush_bg_queue(struct fuse_conn *fc) |
255 | { | 269 | { |
256 | while (fc->active_background < fc->max_background && | 270 | while (fc->active_background < fc->max_background && |
@@ -438,12 +452,6 @@ static void fuse_request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) | |||
438 | } | 452 | } |
439 | } | 453 | } |
440 | 454 | ||
441 | void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) | ||
442 | { | ||
443 | req->isreply = 0; | ||
444 | fuse_request_send_nowait(fc, req); | ||
445 | } | ||
446 | |||
447 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) | 455 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) |
448 | { | 456 | { |
449 | req->isreply = 1; | 457 | req->isreply = 1; |
@@ -896,9 +904,15 @@ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs, | |||
896 | return err; | 904 | return err; |
897 | } | 905 | } |
898 | 906 | ||
907 | static int forget_pending(struct fuse_conn *fc) | ||
908 | { | ||
909 | return fc->forget_list_head.next != NULL; | ||
910 | } | ||
911 | |||
899 | static int request_pending(struct fuse_conn *fc) | 912 | static int request_pending(struct fuse_conn *fc) |
900 | { | 913 | { |
901 | return !list_empty(&fc->pending) || !list_empty(&fc->interrupts); | 914 | return !list_empty(&fc->pending) || !list_empty(&fc->interrupts) || |
915 | forget_pending(fc); | ||
902 | } | 916 | } |
903 | 917 | ||
904 | /* Wait until a request is available on the pending list */ | 918 | /* Wait until a request is available on the pending list */ |
@@ -960,6 +974,120 @@ __releases(fc->lock) | |||
960 | return err ? err : reqsize; | 974 | return err ? err : reqsize; |
961 | } | 975 | } |
962 | 976 | ||
977 | static struct fuse_forget_link *dequeue_forget(struct fuse_conn *fc, | ||
978 | unsigned max, | ||
979 | unsigned *countp) | ||
980 | { | ||
981 | struct fuse_forget_link *head = fc->forget_list_head.next; | ||
982 | struct fuse_forget_link **newhead = &head; | ||
983 | unsigned count; | ||
984 | |||
985 | for (count = 0; *newhead != NULL && count < max; count++) | ||
986 | newhead = &(*newhead)->next; | ||
987 | |||
988 | fc->forget_list_head.next = *newhead; | ||
989 | *newhead = NULL; | ||
990 | if (fc->forget_list_head.next == NULL) | ||
991 | fc->forget_list_tail = &fc->forget_list_head; | ||
992 | |||
993 | if (countp != NULL) | ||
994 | *countp = count; | ||
995 | |||
996 | return head; | ||
997 | } | ||
998 | |||
999 | static int fuse_read_single_forget(struct fuse_conn *fc, | ||
1000 | struct fuse_copy_state *cs, | ||
1001 | size_t nbytes) | ||
1002 | __releases(fc->lock) | ||
1003 | { | ||
1004 | int err; | ||
1005 | struct fuse_forget_link *forget = dequeue_forget(fc, 1, NULL); | ||
1006 | struct fuse_forget_in arg = { | ||
1007 | .nlookup = forget->forget_one.nlookup, | ||
1008 | }; | ||
1009 | struct fuse_in_header ih = { | ||
1010 | .opcode = FUSE_FORGET, | ||
1011 | .nodeid = forget->forget_one.nodeid, | ||
1012 | .unique = fuse_get_unique(fc), | ||
1013 | .len = sizeof(ih) + sizeof(arg), | ||
1014 | }; | ||
1015 | |||
1016 | spin_unlock(&fc->lock); | ||
1017 | kfree(forget); | ||
1018 | if (nbytes < ih.len) | ||
1019 | return -EINVAL; | ||
1020 | |||
1021 | err = fuse_copy_one(cs, &ih, sizeof(ih)); | ||
1022 | if (!err) | ||
1023 | err = fuse_copy_one(cs, &arg, sizeof(arg)); | ||
1024 | fuse_copy_finish(cs); | ||
1025 | |||
1026 | if (err) | ||
1027 | return err; | ||
1028 | |||
1029 | return ih.len; | ||
1030 | } | ||
1031 | |||
1032 | static int fuse_read_batch_forget(struct fuse_conn *fc, | ||
1033 | struct fuse_copy_state *cs, size_t nbytes) | ||
1034 | __releases(fc->lock) | ||
1035 | { | ||
1036 | int err; | ||
1037 | unsigned max_forgets; | ||
1038 | unsigned count; | ||
1039 | struct fuse_forget_link *head; | ||
1040 | struct fuse_batch_forget_in arg = { .count = 0 }; | ||
1041 | struct fuse_in_header ih = { | ||
1042 | .opcode = FUSE_BATCH_FORGET, | ||
1043 | .unique = fuse_get_unique(fc), | ||
1044 | .len = sizeof(ih) + sizeof(arg), | ||
1045 | }; | ||
1046 | |||
1047 | if (nbytes < ih.len) { | ||
1048 | spin_unlock(&fc->lock); | ||
1049 | return -EINVAL; | ||
1050 | } | ||
1051 | |||
1052 | max_forgets = (nbytes - ih.len) / sizeof(struct fuse_forget_one); | ||
1053 | head = dequeue_forget(fc, max_forgets, &count); | ||
1054 | spin_unlock(&fc->lock); | ||
1055 | |||
1056 | arg.count = count; | ||
1057 | ih.len += count * sizeof(struct fuse_forget_one); | ||
1058 | err = fuse_copy_one(cs, &ih, sizeof(ih)); | ||
1059 | if (!err) | ||
1060 | err = fuse_copy_one(cs, &arg, sizeof(arg)); | ||
1061 | |||
1062 | while (head) { | ||
1063 | struct fuse_forget_link *forget = head; | ||
1064 | |||
1065 | if (!err) { | ||
1066 | err = fuse_copy_one(cs, &forget->forget_one, | ||
1067 | sizeof(forget->forget_one)); | ||
1068 | } | ||
1069 | head = forget->next; | ||
1070 | kfree(forget); | ||
1071 | } | ||
1072 | |||
1073 | fuse_copy_finish(cs); | ||
1074 | |||
1075 | if (err) | ||
1076 | return err; | ||
1077 | |||
1078 | return ih.len; | ||
1079 | } | ||
1080 | |||
1081 | static int fuse_read_forget(struct fuse_conn *fc, struct fuse_copy_state *cs, | ||
1082 | size_t nbytes) | ||
1083 | __releases(fc->lock) | ||
1084 | { | ||
1085 | if (fc->minor < 16 || fc->forget_list_head.next->next == NULL) | ||
1086 | return fuse_read_single_forget(fc, cs, nbytes); | ||
1087 | else | ||
1088 | return fuse_read_batch_forget(fc, cs, nbytes); | ||
1089 | } | ||
1090 | |||
963 | /* | 1091 | /* |
964 | * Read a single request into the userspace filesystem's buffer. This | 1092 | * Read a single request into the userspace filesystem's buffer. This |
965 | * function waits until a request is available, then removes it from | 1093 | * function waits until a request is available, then removes it from |
@@ -998,6 +1126,14 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file, | |||
998 | return fuse_read_interrupt(fc, cs, nbytes, req); | 1126 | return fuse_read_interrupt(fc, cs, nbytes, req); |
999 | } | 1127 | } |
1000 | 1128 | ||
1129 | if (forget_pending(fc)) { | ||
1130 | if (list_empty(&fc->pending) || fc->forget_batch-- > 0) | ||
1131 | return fuse_read_forget(fc, cs, nbytes); | ||
1132 | |||
1133 | if (fc->forget_batch <= -8) | ||
1134 | fc->forget_batch = 16; | ||
1135 | } | ||
1136 | |||
1001 | req = list_entry(fc->pending.next, struct fuse_req, list); | 1137 | req = list_entry(fc->pending.next, struct fuse_req, list); |
1002 | req->state = FUSE_REQ_READING; | 1138 | req->state = FUSE_REQ_READING; |
1003 | list_move(&req->list, &fc->io); | 1139 | list_move(&req->list, &fc->io); |
@@ -1090,7 +1226,7 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos, | |||
1090 | if (!fc) | 1226 | if (!fc) |
1091 | return -EPERM; | 1227 | return -EPERM; |
1092 | 1228 | ||
1093 | bufs = kmalloc(pipe->buffers * sizeof (struct pipe_buffer), GFP_KERNEL); | 1229 | bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL); |
1094 | if (!bufs) | 1230 | if (!bufs) |
1095 | return -ENOMEM; | 1231 | return -ENOMEM; |
1096 | 1232 | ||
@@ -1626,7 +1762,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, | |||
1626 | if (!fc) | 1762 | if (!fc) |
1627 | return -EPERM; | 1763 | return -EPERM; |
1628 | 1764 | ||
1629 | bufs = kmalloc(pipe->buffers * sizeof (struct pipe_buffer), GFP_KERNEL); | 1765 | bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL); |
1630 | if (!bufs) | 1766 | if (!bufs) |
1631 | return -ENOMEM; | 1767 | return -ENOMEM; |
1632 | 1768 | ||
@@ -1770,6 +1906,8 @@ __acquires(fc->lock) | |||
1770 | flush_bg_queue(fc); | 1906 | flush_bg_queue(fc); |
1771 | end_requests(fc, &fc->pending); | 1907 | end_requests(fc, &fc->pending); |
1772 | end_requests(fc, &fc->processing); | 1908 | end_requests(fc, &fc->processing); |
1909 | while (forget_pending(fc)) | ||
1910 | kfree(dequeue_forget(fc, 1, NULL)); | ||
1773 | } | 1911 | } |
1774 | 1912 | ||
1775 | /* | 1913 | /* |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index f738599fd8cd..042af7346ec1 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -10,9 +10,9 @@ | |||
10 | 10 | ||
11 | #include <linux/pagemap.h> | 11 | #include <linux/pagemap.h> |
12 | #include <linux/file.h> | 12 | #include <linux/file.h> |
13 | #include <linux/gfp.h> | ||
14 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
15 | #include <linux/namei.h> | 14 | #include <linux/namei.h> |
15 | #include <linux/slab.h> | ||
16 | 16 | ||
17 | #if BITS_PER_LONG >= 64 | 17 | #if BITS_PER_LONG >= 64 |
18 | static inline void fuse_dentry_settime(struct dentry *entry, u64 time) | 18 | static inline void fuse_dentry_settime(struct dentry *entry, u64 time) |
@@ -169,7 +169,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
169 | struct fuse_entry_out outarg; | 169 | struct fuse_entry_out outarg; |
170 | struct fuse_conn *fc; | 170 | struct fuse_conn *fc; |
171 | struct fuse_req *req; | 171 | struct fuse_req *req; |
172 | struct fuse_req *forget_req; | 172 | struct fuse_forget_link *forget; |
173 | struct dentry *parent; | 173 | struct dentry *parent; |
174 | u64 attr_version; | 174 | u64 attr_version; |
175 | 175 | ||
@@ -182,8 +182,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
182 | if (IS_ERR(req)) | 182 | if (IS_ERR(req)) |
183 | return 0; | 183 | return 0; |
184 | 184 | ||
185 | forget_req = fuse_get_req(fc); | 185 | forget = fuse_alloc_forget(); |
186 | if (IS_ERR(forget_req)) { | 186 | if (!forget) { |
187 | fuse_put_request(fc, req); | 187 | fuse_put_request(fc, req); |
188 | return 0; | 188 | return 0; |
189 | } | 189 | } |
@@ -203,15 +203,14 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
203 | if (!err) { | 203 | if (!err) { |
204 | struct fuse_inode *fi = get_fuse_inode(inode); | 204 | struct fuse_inode *fi = get_fuse_inode(inode); |
205 | if (outarg.nodeid != get_node_id(inode)) { | 205 | if (outarg.nodeid != get_node_id(inode)) { |
206 | fuse_send_forget(fc, forget_req, | 206 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); |
207 | outarg.nodeid, 1); | ||
208 | return 0; | 207 | return 0; |
209 | } | 208 | } |
210 | spin_lock(&fc->lock); | 209 | spin_lock(&fc->lock); |
211 | fi->nlookup++; | 210 | fi->nlookup++; |
212 | spin_unlock(&fc->lock); | 211 | spin_unlock(&fc->lock); |
213 | } | 212 | } |
214 | fuse_put_request(fc, forget_req); | 213 | kfree(forget); |
215 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) | 214 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) |
216 | return 0; | 215 | return 0; |
217 | 216 | ||
@@ -263,7 +262,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
263 | { | 262 | { |
264 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 263 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
265 | struct fuse_req *req; | 264 | struct fuse_req *req; |
266 | struct fuse_req *forget_req; | 265 | struct fuse_forget_link *forget; |
267 | u64 attr_version; | 266 | u64 attr_version; |
268 | int err; | 267 | int err; |
269 | 268 | ||
@@ -277,9 +276,9 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
277 | if (IS_ERR(req)) | 276 | if (IS_ERR(req)) |
278 | goto out; | 277 | goto out; |
279 | 278 | ||
280 | forget_req = fuse_get_req(fc); | 279 | forget = fuse_alloc_forget(); |
281 | err = PTR_ERR(forget_req); | 280 | err = -ENOMEM; |
282 | if (IS_ERR(forget_req)) { | 281 | if (!forget) { |
283 | fuse_put_request(fc, req); | 282 | fuse_put_request(fc, req); |
284 | goto out; | 283 | goto out; |
285 | } | 284 | } |
@@ -305,13 +304,13 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
305 | attr_version); | 304 | attr_version); |
306 | err = -ENOMEM; | 305 | err = -ENOMEM; |
307 | if (!*inode) { | 306 | if (!*inode) { |
308 | fuse_send_forget(fc, forget_req, outarg->nodeid, 1); | 307 | fuse_queue_forget(fc, forget, outarg->nodeid, 1); |
309 | goto out; | 308 | goto out; |
310 | } | 309 | } |
311 | err = 0; | 310 | err = 0; |
312 | 311 | ||
313 | out_put_forget: | 312 | out_put_forget: |
314 | fuse_put_request(fc, forget_req); | 313 | kfree(forget); |
315 | out: | 314 | out: |
316 | return err; | 315 | return err; |
317 | } | 316 | } |
@@ -378,7 +377,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
378 | struct inode *inode; | 377 | struct inode *inode; |
379 | struct fuse_conn *fc = get_fuse_conn(dir); | 378 | struct fuse_conn *fc = get_fuse_conn(dir); |
380 | struct fuse_req *req; | 379 | struct fuse_req *req; |
381 | struct fuse_req *forget_req; | 380 | struct fuse_forget_link *forget; |
382 | struct fuse_create_in inarg; | 381 | struct fuse_create_in inarg; |
383 | struct fuse_open_out outopen; | 382 | struct fuse_open_out outopen; |
384 | struct fuse_entry_out outentry; | 383 | struct fuse_entry_out outentry; |
@@ -392,9 +391,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
392 | if (flags & O_DIRECT) | 391 | if (flags & O_DIRECT) |
393 | return -EINVAL; | 392 | return -EINVAL; |
394 | 393 | ||
395 | forget_req = fuse_get_req(fc); | 394 | forget = fuse_alloc_forget(); |
396 | if (IS_ERR(forget_req)) | 395 | if (!forget) |
397 | return PTR_ERR(forget_req); | 396 | return -ENOMEM; |
398 | 397 | ||
399 | req = fuse_get_req(fc); | 398 | req = fuse_get_req(fc); |
400 | err = PTR_ERR(req); | 399 | err = PTR_ERR(req); |
@@ -452,10 +451,10 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
452 | if (!inode) { | 451 | if (!inode) { |
453 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); | 452 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); |
454 | fuse_sync_release(ff, flags); | 453 | fuse_sync_release(ff, flags); |
455 | fuse_send_forget(fc, forget_req, outentry.nodeid, 1); | 454 | fuse_queue_forget(fc, forget, outentry.nodeid, 1); |
456 | return -ENOMEM; | 455 | return -ENOMEM; |
457 | } | 456 | } |
458 | fuse_put_request(fc, forget_req); | 457 | kfree(forget); |
459 | d_instantiate(entry, inode); | 458 | d_instantiate(entry, inode); |
460 | fuse_change_entry_timeout(entry, &outentry); | 459 | fuse_change_entry_timeout(entry, &outentry); |
461 | fuse_invalidate_attr(dir); | 460 | fuse_invalidate_attr(dir); |
@@ -473,7 +472,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
473 | out_put_request: | 472 | out_put_request: |
474 | fuse_put_request(fc, req); | 473 | fuse_put_request(fc, req); |
475 | out_put_forget_req: | 474 | out_put_forget_req: |
476 | fuse_put_request(fc, forget_req); | 475 | kfree(forget); |
477 | return err; | 476 | return err; |
478 | } | 477 | } |
479 | 478 | ||
@@ -487,12 +486,12 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
487 | struct fuse_entry_out outarg; | 486 | struct fuse_entry_out outarg; |
488 | struct inode *inode; | 487 | struct inode *inode; |
489 | int err; | 488 | int err; |
490 | struct fuse_req *forget_req; | 489 | struct fuse_forget_link *forget; |
491 | 490 | ||
492 | forget_req = fuse_get_req(fc); | 491 | forget = fuse_alloc_forget(); |
493 | if (IS_ERR(forget_req)) { | 492 | if (!forget) { |
494 | fuse_put_request(fc, req); | 493 | fuse_put_request(fc, req); |
495 | return PTR_ERR(forget_req); | 494 | return -ENOMEM; |
496 | } | 495 | } |
497 | 496 | ||
498 | memset(&outarg, 0, sizeof(outarg)); | 497 | memset(&outarg, 0, sizeof(outarg)); |
@@ -519,10 +518,10 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
519 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 518 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
520 | &outarg.attr, entry_attr_timeout(&outarg), 0); | 519 | &outarg.attr, entry_attr_timeout(&outarg), 0); |
521 | if (!inode) { | 520 | if (!inode) { |
522 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); | 521 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); |
523 | return -ENOMEM; | 522 | return -ENOMEM; |
524 | } | 523 | } |
525 | fuse_put_request(fc, forget_req); | 524 | kfree(forget); |
526 | 525 | ||
527 | if (S_ISDIR(inode->i_mode)) { | 526 | if (S_ISDIR(inode->i_mode)) { |
528 | struct dentry *alias; | 527 | struct dentry *alias; |
@@ -545,7 +544,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
545 | return 0; | 544 | return 0; |
546 | 545 | ||
547 | out_put_forget_req: | 546 | out_put_forget_req: |
548 | fuse_put_request(fc, forget_req); | 547 | kfree(forget); |
549 | return err; | 548 | return err; |
550 | } | 549 | } |
551 | 550 | ||
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 8b984a2cebbd..95da1bc1c826 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -1634,9 +1634,9 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov, | |||
1634 | * and 64bit. Fortunately we can determine which structure the server | 1634 | * and 64bit. Fortunately we can determine which structure the server |
1635 | * used from the size of the reply. | 1635 | * used from the size of the reply. |
1636 | */ | 1636 | */ |
1637 | static int fuse_copy_ioctl_iovec(struct iovec *dst, void *src, | 1637 | static int fuse_copy_ioctl_iovec_old(struct iovec *dst, void *src, |
1638 | size_t transferred, unsigned count, | 1638 | size_t transferred, unsigned count, |
1639 | bool is_compat) | 1639 | bool is_compat) |
1640 | { | 1640 | { |
1641 | #ifdef CONFIG_COMPAT | 1641 | #ifdef CONFIG_COMPAT |
1642 | if (count * sizeof(struct compat_iovec) == transferred) { | 1642 | if (count * sizeof(struct compat_iovec) == transferred) { |
@@ -1680,6 +1680,42 @@ static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count) | |||
1680 | return 0; | 1680 | return 0; |
1681 | } | 1681 | } |
1682 | 1682 | ||
1683 | static int fuse_copy_ioctl_iovec(struct fuse_conn *fc, struct iovec *dst, | ||
1684 | void *src, size_t transferred, unsigned count, | ||
1685 | bool is_compat) | ||
1686 | { | ||
1687 | unsigned i; | ||
1688 | struct fuse_ioctl_iovec *fiov = src; | ||
1689 | |||
1690 | if (fc->minor < 16) { | ||
1691 | return fuse_copy_ioctl_iovec_old(dst, src, transferred, | ||
1692 | count, is_compat); | ||
1693 | } | ||
1694 | |||
1695 | if (count * sizeof(struct fuse_ioctl_iovec) != transferred) | ||
1696 | return -EIO; | ||
1697 | |||
1698 | for (i = 0; i < count; i++) { | ||
1699 | /* Did the server supply an inappropriate value? */ | ||
1700 | if (fiov[i].base != (unsigned long) fiov[i].base || | ||
1701 | fiov[i].len != (unsigned long) fiov[i].len) | ||
1702 | return -EIO; | ||
1703 | |||
1704 | dst[i].iov_base = (void __user *) (unsigned long) fiov[i].base; | ||
1705 | dst[i].iov_len = (size_t) fiov[i].len; | ||
1706 | |||
1707 | #ifdef CONFIG_COMPAT | ||
1708 | if (is_compat && | ||
1709 | (ptr_to_compat(dst[i].iov_base) != fiov[i].base || | ||
1710 | (compat_size_t) dst[i].iov_len != fiov[i].len)) | ||
1711 | return -EIO; | ||
1712 | #endif | ||
1713 | } | ||
1714 | |||
1715 | return 0; | ||
1716 | } | ||
1717 | |||
1718 | |||
1683 | /* | 1719 | /* |
1684 | * For ioctls, there is no generic way to determine how much memory | 1720 | * For ioctls, there is no generic way to determine how much memory |
1685 | * needs to be read and/or written. Furthermore, ioctls are allowed | 1721 | * needs to be read and/or written. Furthermore, ioctls are allowed |
@@ -1740,18 +1776,25 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1740 | struct fuse_ioctl_out outarg; | 1776 | struct fuse_ioctl_out outarg; |
1741 | struct fuse_req *req = NULL; | 1777 | struct fuse_req *req = NULL; |
1742 | struct page **pages = NULL; | 1778 | struct page **pages = NULL; |
1743 | struct page *iov_page = NULL; | 1779 | struct iovec *iov_page = NULL; |
1744 | struct iovec *in_iov = NULL, *out_iov = NULL; | 1780 | struct iovec *in_iov = NULL, *out_iov = NULL; |
1745 | unsigned int in_iovs = 0, out_iovs = 0, num_pages = 0, max_pages; | 1781 | unsigned int in_iovs = 0, out_iovs = 0, num_pages = 0, max_pages; |
1746 | size_t in_size, out_size, transferred; | 1782 | size_t in_size, out_size, transferred; |
1747 | int err; | 1783 | int err; |
1748 | 1784 | ||
1785 | #if BITS_PER_LONG == 32 | ||
1786 | inarg.flags |= FUSE_IOCTL_32BIT; | ||
1787 | #else | ||
1788 | if (flags & FUSE_IOCTL_COMPAT) | ||
1789 | inarg.flags |= FUSE_IOCTL_32BIT; | ||
1790 | #endif | ||
1791 | |||
1749 | /* assume all the iovs returned by client always fits in a page */ | 1792 | /* assume all the iovs returned by client always fits in a page */ |
1750 | BUILD_BUG_ON(sizeof(struct iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE); | 1793 | BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE); |
1751 | 1794 | ||
1752 | err = -ENOMEM; | 1795 | err = -ENOMEM; |
1753 | pages = kzalloc(sizeof(pages[0]) * FUSE_MAX_PAGES_PER_REQ, GFP_KERNEL); | 1796 | pages = kzalloc(sizeof(pages[0]) * FUSE_MAX_PAGES_PER_REQ, GFP_KERNEL); |
1754 | iov_page = alloc_page(GFP_KERNEL); | 1797 | iov_page = (struct iovec *) __get_free_page(GFP_KERNEL); |
1755 | if (!pages || !iov_page) | 1798 | if (!pages || !iov_page) |
1756 | goto out; | 1799 | goto out; |
1757 | 1800 | ||
@@ -1760,7 +1803,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1760 | * RETRY from server is not allowed. | 1803 | * RETRY from server is not allowed. |
1761 | */ | 1804 | */ |
1762 | if (!(flags & FUSE_IOCTL_UNRESTRICTED)) { | 1805 | if (!(flags & FUSE_IOCTL_UNRESTRICTED)) { |
1763 | struct iovec *iov = page_address(iov_page); | 1806 | struct iovec *iov = iov_page; |
1764 | 1807 | ||
1765 | iov->iov_base = (void __user *)arg; | 1808 | iov->iov_base = (void __user *)arg; |
1766 | iov->iov_len = _IOC_SIZE(cmd); | 1809 | iov->iov_len = _IOC_SIZE(cmd); |
@@ -1841,7 +1884,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1841 | 1884 | ||
1842 | /* did it ask for retry? */ | 1885 | /* did it ask for retry? */ |
1843 | if (outarg.flags & FUSE_IOCTL_RETRY) { | 1886 | if (outarg.flags & FUSE_IOCTL_RETRY) { |
1844 | char *vaddr; | 1887 | void *vaddr; |
1845 | 1888 | ||
1846 | /* no retry if in restricted mode */ | 1889 | /* no retry if in restricted mode */ |
1847 | err = -EIO; | 1890 | err = -EIO; |
@@ -1862,14 +1905,14 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1862 | goto out; | 1905 | goto out; |
1863 | 1906 | ||
1864 | vaddr = kmap_atomic(pages[0], KM_USER0); | 1907 | vaddr = kmap_atomic(pages[0], KM_USER0); |
1865 | err = fuse_copy_ioctl_iovec(page_address(iov_page), vaddr, | 1908 | err = fuse_copy_ioctl_iovec(fc, iov_page, vaddr, |
1866 | transferred, in_iovs + out_iovs, | 1909 | transferred, in_iovs + out_iovs, |
1867 | (flags & FUSE_IOCTL_COMPAT) != 0); | 1910 | (flags & FUSE_IOCTL_COMPAT) != 0); |
1868 | kunmap_atomic(vaddr, KM_USER0); | 1911 | kunmap_atomic(vaddr, KM_USER0); |
1869 | if (err) | 1912 | if (err) |
1870 | goto out; | 1913 | goto out; |
1871 | 1914 | ||
1872 | in_iov = page_address(iov_page); | 1915 | in_iov = iov_page; |
1873 | out_iov = in_iov + in_iovs; | 1916 | out_iov = in_iov + in_iovs; |
1874 | 1917 | ||
1875 | err = fuse_verify_ioctl_iov(in_iov, in_iovs); | 1918 | err = fuse_verify_ioctl_iov(in_iov, in_iovs); |
@@ -1891,8 +1934,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1891 | out: | 1934 | out: |
1892 | if (req) | 1935 | if (req) |
1893 | fuse_put_request(fc, req); | 1936 | fuse_put_request(fc, req); |
1894 | if (iov_page) | 1937 | free_page((unsigned long) iov_page); |
1895 | __free_page(iov_page); | ||
1896 | while (num_pages) | 1938 | while (num_pages) |
1897 | __free_page(pages[--num_pages]); | 1939 | __free_page(pages[--num_pages]); |
1898 | kfree(pages); | 1940 | kfree(pages); |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 57d4a3a0f102..ae5744a2f9e9 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -53,6 +53,12 @@ extern struct mutex fuse_mutex; | |||
53 | extern unsigned max_user_bgreq; | 53 | extern unsigned max_user_bgreq; |
54 | extern unsigned max_user_congthresh; | 54 | extern unsigned max_user_congthresh; |
55 | 55 | ||
56 | /* One forget request */ | ||
57 | struct fuse_forget_link { | ||
58 | struct fuse_forget_one forget_one; | ||
59 | struct fuse_forget_link *next; | ||
60 | }; | ||
61 | |||
56 | /** FUSE inode */ | 62 | /** FUSE inode */ |
57 | struct fuse_inode { | 63 | struct fuse_inode { |
58 | /** Inode data */ | 64 | /** Inode data */ |
@@ -66,7 +72,7 @@ struct fuse_inode { | |||
66 | u64 nlookup; | 72 | u64 nlookup; |
67 | 73 | ||
68 | /** The request used for sending the FORGET message */ | 74 | /** The request used for sending the FORGET message */ |
69 | struct fuse_req *forget_req; | 75 | struct fuse_forget_link *forget; |
70 | 76 | ||
71 | /** Time in jiffies until the file attributes are valid */ | 77 | /** Time in jiffies until the file attributes are valid */ |
72 | u64 i_time; | 78 | u64 i_time; |
@@ -255,7 +261,6 @@ struct fuse_req { | |||
255 | 261 | ||
256 | /** Data for asynchronous requests */ | 262 | /** Data for asynchronous requests */ |
257 | union { | 263 | union { |
258 | struct fuse_forget_in forget_in; | ||
259 | struct { | 264 | struct { |
260 | struct fuse_release_in in; | 265 | struct fuse_release_in in; |
261 | struct path path; | 266 | struct path path; |
@@ -369,6 +374,13 @@ struct fuse_conn { | |||
369 | /** Pending interrupts */ | 374 | /** Pending interrupts */ |
370 | struct list_head interrupts; | 375 | struct list_head interrupts; |
371 | 376 | ||
377 | /** Queue of pending forgets */ | ||
378 | struct fuse_forget_link forget_list_head; | ||
379 | struct fuse_forget_link *forget_list_tail; | ||
380 | |||
381 | /** Batching of FORGET requests (positive indicates FORGET batch) */ | ||
382 | int forget_batch; | ||
383 | |||
372 | /** Flag indicating if connection is blocked. This will be | 384 | /** Flag indicating if connection is blocked. This will be |
373 | the case before the INIT reply is received, and if there | 385 | the case before the INIT reply is received, and if there |
374 | are too many outstading backgrounds requests */ | 386 | are too many outstading backgrounds requests */ |
@@ -543,8 +555,10 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
543 | /** | 555 | /** |
544 | * Send FORGET command | 556 | * Send FORGET command |
545 | */ | 557 | */ |
546 | void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, | 558 | void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, |
547 | u64 nodeid, u64 nlookup); | 559 | u64 nodeid, u64 nlookup); |
560 | |||
561 | struct fuse_forget_link *fuse_alloc_forget(void); | ||
548 | 562 | ||
549 | /** | 563 | /** |
550 | * Initialize READ or READDIR request | 564 | * Initialize READ or READDIR request |
@@ -656,11 +670,6 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req); | |||
656 | void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req); | 670 | void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req); |
657 | 671 | ||
658 | /** | 672 | /** |
659 | * Send a request with no reply | ||
660 | */ | ||
661 | void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); | ||
662 | |||
663 | /** | ||
664 | * Send a request in the background | 673 | * Send a request in the background |
665 | */ | 674 | */ |
666 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req); | 675 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req); |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index a8b31da19b93..f62b32cffea9 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -71,6 +71,11 @@ struct fuse_mount_data { | |||
71 | unsigned blksize; | 71 | unsigned blksize; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | struct fuse_forget_link *fuse_alloc_forget() | ||
75 | { | ||
76 | return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL); | ||
77 | } | ||
78 | |||
74 | static struct inode *fuse_alloc_inode(struct super_block *sb) | 79 | static struct inode *fuse_alloc_inode(struct super_block *sb) |
75 | { | 80 | { |
76 | struct inode *inode; | 81 | struct inode *inode; |
@@ -90,8 +95,8 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
90 | INIT_LIST_HEAD(&fi->queued_writes); | 95 | INIT_LIST_HEAD(&fi->queued_writes); |
91 | INIT_LIST_HEAD(&fi->writepages); | 96 | INIT_LIST_HEAD(&fi->writepages); |
92 | init_waitqueue_head(&fi->page_waitq); | 97 | init_waitqueue_head(&fi->page_waitq); |
93 | fi->forget_req = fuse_request_alloc(); | 98 | fi->forget = fuse_alloc_forget(); |
94 | if (!fi->forget_req) { | 99 | if (!fi->forget) { |
95 | kmem_cache_free(fuse_inode_cachep, inode); | 100 | kmem_cache_free(fuse_inode_cachep, inode); |
96 | return NULL; | 101 | return NULL; |
97 | } | 102 | } |
@@ -111,24 +116,10 @@ static void fuse_destroy_inode(struct inode *inode) | |||
111 | struct fuse_inode *fi = get_fuse_inode(inode); | 116 | struct fuse_inode *fi = get_fuse_inode(inode); |
112 | BUG_ON(!list_empty(&fi->write_files)); | 117 | BUG_ON(!list_empty(&fi->write_files)); |
113 | BUG_ON(!list_empty(&fi->queued_writes)); | 118 | BUG_ON(!list_empty(&fi->queued_writes)); |
114 | if (fi->forget_req) | 119 | kfree(fi->forget); |
115 | fuse_request_free(fi->forget_req); | ||
116 | call_rcu(&inode->i_rcu, fuse_i_callback); | 120 | call_rcu(&inode->i_rcu, fuse_i_callback); |
117 | } | 121 | } |
118 | 122 | ||
119 | void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, | ||
120 | u64 nodeid, u64 nlookup) | ||
121 | { | ||
122 | struct fuse_forget_in *inarg = &req->misc.forget_in; | ||
123 | inarg->nlookup = nlookup; | ||
124 | req->in.h.opcode = FUSE_FORGET; | ||
125 | req->in.h.nodeid = nodeid; | ||
126 | req->in.numargs = 1; | ||
127 | req->in.args[0].size = sizeof(struct fuse_forget_in); | ||
128 | req->in.args[0].value = inarg; | ||
129 | fuse_request_send_noreply(fc, req); | ||
130 | } | ||
131 | |||
132 | static void fuse_evict_inode(struct inode *inode) | 123 | static void fuse_evict_inode(struct inode *inode) |
133 | { | 124 | { |
134 | truncate_inode_pages(&inode->i_data, 0); | 125 | truncate_inode_pages(&inode->i_data, 0); |
@@ -136,8 +127,8 @@ static void fuse_evict_inode(struct inode *inode) | |||
136 | if (inode->i_sb->s_flags & MS_ACTIVE) { | 127 | if (inode->i_sb->s_flags & MS_ACTIVE) { |
137 | struct fuse_conn *fc = get_fuse_conn(inode); | 128 | struct fuse_conn *fc = get_fuse_conn(inode); |
138 | struct fuse_inode *fi = get_fuse_inode(inode); | 129 | struct fuse_inode *fi = get_fuse_inode(inode); |
139 | fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup); | 130 | fuse_queue_forget(fc, fi->forget, fi->nodeid, fi->nlookup); |
140 | fi->forget_req = NULL; | 131 | fi->forget = NULL; |
141 | } | 132 | } |
142 | } | 133 | } |
143 | 134 | ||
@@ -541,6 +532,7 @@ void fuse_conn_init(struct fuse_conn *fc) | |||
541 | INIT_LIST_HEAD(&fc->interrupts); | 532 | INIT_LIST_HEAD(&fc->interrupts); |
542 | INIT_LIST_HEAD(&fc->bg_queue); | 533 | INIT_LIST_HEAD(&fc->bg_queue); |
543 | INIT_LIST_HEAD(&fc->entry); | 534 | INIT_LIST_HEAD(&fc->entry); |
535 | fc->forget_list_tail = &fc->forget_list_head; | ||
544 | atomic_set(&fc->num_waiting, 0); | 536 | atomic_set(&fc->num_waiting, 0); |
545 | fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; | 537 | fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; |
546 | fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; | 538 | fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; |
diff --git a/fs/namei.c b/fs/namei.c index 19433cdba011..24ece10470b6 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -202,7 +202,7 @@ static int acl_permission_check(struct inode *inode, int mask, unsigned int flag | |||
202 | * @inode: inode to check access rights for | 202 | * @inode: inode to check access rights for |
203 | * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) | 203 | * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) |
204 | * @check_acl: optional callback to check for Posix ACLs | 204 | * @check_acl: optional callback to check for Posix ACLs |
205 | * @flags IPERM_FLAG_ flags. | 205 | * @flags: IPERM_FLAG_ flags. |
206 | * | 206 | * |
207 | * Used to check for read/write/execute permissions on a file. | 207 | * Used to check for read/write/execute permissions on a file. |
208 | * We use "fsuid" for this, letting us set arbitrary permissions | 208 | * We use "fsuid" for this, letting us set arbitrary permissions |
@@ -407,7 +407,7 @@ void path_put_long(struct path *path) | |||
407 | /** | 407 | /** |
408 | * nameidata_drop_rcu - drop this nameidata out of rcu-walk | 408 | * nameidata_drop_rcu - drop this nameidata out of rcu-walk |
409 | * @nd: nameidata pathwalk data to drop | 409 | * @nd: nameidata pathwalk data to drop |
410 | * @Returns: 0 on success, -ECHLID on failure | 410 | * Returns: 0 on success, -ECHILD on failure |
411 | * | 411 | * |
412 | * Path walking has 2 modes, rcu-walk and ref-walk (see | 412 | * Path walking has 2 modes, rcu-walk and ref-walk (see |
413 | * Documentation/filesystems/path-lookup.txt). __drop_rcu* functions attempt | 413 | * Documentation/filesystems/path-lookup.txt). __drop_rcu* functions attempt |
@@ -468,7 +468,7 @@ static inline int nameidata_drop_rcu_maybe(struct nameidata *nd) | |||
468 | * nameidata_dentry_drop_rcu - drop nameidata and dentry out of rcu-walk | 468 | * nameidata_dentry_drop_rcu - drop nameidata and dentry out of rcu-walk |
469 | * @nd: nameidata pathwalk data to drop | 469 | * @nd: nameidata pathwalk data to drop |
470 | * @dentry: dentry to drop | 470 | * @dentry: dentry to drop |
471 | * @Returns: 0 on success, -ECHLID on failure | 471 | * Returns: 0 on success, -ECHILD on failure |
472 | * | 472 | * |
473 | * nameidata_dentry_drop_rcu attempts to drop the current nd->path and nd->root, | 473 | * nameidata_dentry_drop_rcu attempts to drop the current nd->path and nd->root, |
474 | * and dentry into ref-walk. @dentry must be a path found by a do_lookup call on | 474 | * and dentry into ref-walk. @dentry must be a path found by a do_lookup call on |
@@ -530,7 +530,7 @@ static inline int nameidata_dentry_drop_rcu_maybe(struct nameidata *nd, struct d | |||
530 | /** | 530 | /** |
531 | * nameidata_drop_rcu_last - drop nameidata ending path walk out of rcu-walk | 531 | * nameidata_drop_rcu_last - drop nameidata ending path walk out of rcu-walk |
532 | * @nd: nameidata pathwalk data to drop | 532 | * @nd: nameidata pathwalk data to drop |
533 | * @Returns: 0 on success, -ECHLID on failure | 533 | * Returns: 0 on success, -ECHILD on failure |
534 | * | 534 | * |
535 | * nameidata_drop_rcu_last attempts to drop the current nd->path into ref-walk. | 535 | * nameidata_drop_rcu_last attempts to drop the current nd->path into ref-walk. |
536 | * nd->path should be the final element of the lookup, so nd->root is discarded. | 536 | * nd->path should be the final element of the lookup, so nd->root is discarded. |