diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/Kconfig | 2 | ||||
| -rw-r--r-- | fs/cifs/cifs_debug.c | 10 | ||||
| -rw-r--r-- | fs/cifs/cifs_fs_sb.h | 1 | ||||
| -rw-r--r-- | fs/cifs/cifs_unicode.c | 127 | ||||
| -rw-r--r-- | fs/cifs/cifsacl.c | 13 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 44 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.h | 15 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 64 | ||||
| -rw-r--r-- | fs/cifs/cifspdu.h | 62 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 9 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 113 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 190 | ||||
| -rw-r--r-- | fs/cifs/file.c | 289 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 8 | ||||
| -rw-r--r-- | fs/cifs/misc.c | 73 | ||||
| -rw-r--r-- | fs/cifs/netmisc.c | 4 | ||||
| -rw-r--r-- | fs/cifs/sess.c | 15 | ||||
| -rw-r--r-- | fs/cifs/transport.c | 434 | ||||
| -rw-r--r-- | fs/direct-io.c | 10 | ||||
| -rw-r--r-- | fs/ext3/super.c | 25 | ||||
| -rw-r--r-- | fs/ext4/super.c | 25 | ||||
| -rw-r--r-- | fs/gfs2/inode.c | 72 | ||||
| -rw-r--r-- | fs/gfs2/inode.h | 1 | ||||
| -rw-r--r-- | fs/gfs2/super.c | 1 | ||||
| -rw-r--r-- | fs/ocfs2/super.c | 5 | ||||
| -rw-r--r-- | fs/pipe.c | 10 | ||||
| -rw-r--r-- | fs/proc/Kconfig | 6 | ||||
| -rw-r--r-- | fs/quota/dquot.c | 18 | ||||
| -rw-r--r-- | fs/quota/quota.c | 41 | ||||
| -rw-r--r-- | fs/reiserfs/super.c | 17 | ||||
| -rw-r--r-- | fs/sysfs/Kconfig | 2 |
31 files changed, 946 insertions, 760 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 9a7921ae4763..3db9caa57edc 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
| @@ -50,7 +50,7 @@ config EXPORTFS | |||
| 50 | tristate | 50 | tristate |
| 51 | 51 | ||
| 52 | config FILE_LOCKING | 52 | config FILE_LOCKING |
| 53 | bool "Enable POSIX file locking API" if EMBEDDED | 53 | bool "Enable POSIX file locking API" if EXPERT |
| 54 | default y | 54 | default y |
| 55 | help | 55 | help |
| 56 | This option enables standard file locking support, required | 56 | This option enables standard file locking support, required |
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index ede98300a8cd..65829d32128c 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
| @@ -79,11 +79,11 @@ void cifs_dump_mids(struct TCP_Server_Info *server) | |||
| 79 | spin_lock(&GlobalMid_Lock); | 79 | spin_lock(&GlobalMid_Lock); |
| 80 | list_for_each(tmp, &server->pending_mid_q) { | 80 | list_for_each(tmp, &server->pending_mid_q) { |
| 81 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 81 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
| 82 | cERROR(1, "State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", | 82 | cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %d", |
| 83 | mid_entry->midState, | 83 | mid_entry->midState, |
| 84 | (int)mid_entry->command, | 84 | (int)mid_entry->command, |
| 85 | mid_entry->pid, | 85 | mid_entry->pid, |
| 86 | mid_entry->tsk, | 86 | mid_entry->callback_data, |
| 87 | mid_entry->mid); | 87 | mid_entry->mid); |
| 88 | #ifdef CONFIG_CIFS_STATS2 | 88 | #ifdef CONFIG_CIFS_STATS2 |
| 89 | cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld", | 89 | cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld", |
| @@ -218,11 +218,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
| 218 | mid_entry = list_entry(tmp3, struct mid_q_entry, | 218 | mid_entry = list_entry(tmp3, struct mid_q_entry, |
| 219 | qhead); | 219 | qhead); |
| 220 | seq_printf(m, "\tState: %d com: %d pid:" | 220 | seq_printf(m, "\tState: %d com: %d pid:" |
| 221 | " %d tsk: %p mid %d\n", | 221 | " %d cbdata: %p mid %d\n", |
| 222 | mid_entry->midState, | 222 | mid_entry->midState, |
| 223 | (int)mid_entry->command, | 223 | (int)mid_entry->command, |
| 224 | mid_entry->pid, | 224 | mid_entry->pid, |
| 225 | mid_entry->tsk, | 225 | mid_entry->callback_data, |
| 226 | mid_entry->mid); | 226 | mid_entry->mid); |
| 227 | } | 227 | } |
| 228 | spin_unlock(&GlobalMid_Lock); | 228 | spin_unlock(&GlobalMid_Lock); |
| @@ -331,7 +331,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) | |||
| 331 | atomic_read(&totSmBufAllocCount)); | 331 | atomic_read(&totSmBufAllocCount)); |
| 332 | #endif /* CONFIG_CIFS_STATS2 */ | 332 | #endif /* CONFIG_CIFS_STATS2 */ |
| 333 | 333 | ||
| 334 | seq_printf(m, "Operations (MIDs): %d\n", midCount.counter); | 334 | seq_printf(m, "Operations (MIDs): %d\n", atomic_read(&midCount)); |
| 335 | seq_printf(m, | 335 | seq_printf(m, |
| 336 | "\n%d session %d share reconnects\n", | 336 | "\n%d session %d share reconnects\n", |
| 337 | tcpSesReconnectCount.counter, tconInfoReconnectCount.counter); | 337 | tcpSesReconnectCount.counter, tconInfoReconnectCount.counter); |
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 7852cd677051..ac51cd2d33ae 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
| @@ -40,6 +40,7 @@ | |||
| 40 | #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ | 40 | #define CIFS_MOUNT_FSCACHE 0x8000 /* local caching enabled */ |
| 41 | #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */ | 41 | #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */ |
| 42 | #define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */ | 42 | #define CIFS_MOUNT_MULTIUSER 0x20000 /* multiuser mount */ |
| 43 | #define CIFS_MOUNT_STRICT_IO 0x40000 /* strict cache mode */ | ||
| 43 | 44 | ||
| 44 | struct cifs_sb_info { | 45 | struct cifs_sb_info { |
| 45 | struct rb_root tlink_tree; | 46 | struct rb_root tlink_tree; |
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 430f510a1720..fc0fd4fde306 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
| @@ -44,10 +44,14 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |||
| 44 | int charlen, outlen = 0; | 44 | int charlen, outlen = 0; |
| 45 | int maxwords = maxbytes / 2; | 45 | int maxwords = maxbytes / 2; |
| 46 | char tmp[NLS_MAX_CHARSET_SIZE]; | 46 | char tmp[NLS_MAX_CHARSET_SIZE]; |
| 47 | __u16 ftmp; | ||
| 47 | 48 | ||
| 48 | for (i = 0; i < maxwords && from[i]; i++) { | 49 | for (i = 0; i < maxwords; i++) { |
| 49 | charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp, | 50 | ftmp = get_unaligned_le16(&from[i]); |
| 50 | NLS_MAX_CHARSET_SIZE); | 51 | if (ftmp == 0) |
| 52 | break; | ||
| 53 | |||
| 54 | charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE); | ||
| 51 | if (charlen > 0) | 55 | if (charlen > 0) |
| 52 | outlen += charlen; | 56 | outlen += charlen; |
| 53 | else | 57 | else |
| @@ -58,9 +62,9 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |||
| 58 | } | 62 | } |
| 59 | 63 | ||
| 60 | /* | 64 | /* |
| 61 | * cifs_mapchar - convert a little-endian char to proper char in codepage | 65 | * cifs_mapchar - convert a host-endian char to proper char in codepage |
| 62 | * @target - where converted character should be copied | 66 | * @target - where converted character should be copied |
| 63 | * @src_char - 2 byte little-endian source character | 67 | * @src_char - 2 byte host-endian source character |
| 64 | * @cp - codepage to which character should be converted | 68 | * @cp - codepage to which character should be converted |
| 65 | * @mapchar - should character be mapped according to mapchars mount option? | 69 | * @mapchar - should character be mapped according to mapchars mount option? |
| 66 | * | 70 | * |
| @@ -69,7 +73,7 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |||
| 69 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). | 73 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). |
| 70 | */ | 74 | */ |
| 71 | static int | 75 | static int |
| 72 | cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, | 76 | cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, |
| 73 | bool mapchar) | 77 | bool mapchar) |
| 74 | { | 78 | { |
| 75 | int len = 1; | 79 | int len = 1; |
| @@ -82,7 +86,7 @@ cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, | |||
| 82 | * build_path_from_dentry are modified, as they use slash as | 86 | * build_path_from_dentry are modified, as they use slash as |
| 83 | * separator. | 87 | * separator. |
| 84 | */ | 88 | */ |
| 85 | switch (le16_to_cpu(src_char)) { | 89 | switch (src_char) { |
| 86 | case UNI_COLON: | 90 | case UNI_COLON: |
| 87 | *target = ':'; | 91 | *target = ':'; |
| 88 | break; | 92 | break; |
| @@ -109,8 +113,7 @@ out: | |||
| 109 | return len; | 113 | return len; |
| 110 | 114 | ||
| 111 | cp_convert: | 115 | cp_convert: |
| 112 | len = cp->uni2char(le16_to_cpu(src_char), target, | 116 | len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); |
| 113 | NLS_MAX_CHARSET_SIZE); | ||
| 114 | if (len <= 0) { | 117 | if (len <= 0) { |
| 115 | *target = '?'; | 118 | *target = '?'; |
| 116 | len = 1; | 119 | len = 1; |
| @@ -149,6 +152,7 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, | |||
| 149 | int nullsize = nls_nullsize(codepage); | 152 | int nullsize = nls_nullsize(codepage); |
| 150 | int fromwords = fromlen / 2; | 153 | int fromwords = fromlen / 2; |
| 151 | char tmp[NLS_MAX_CHARSET_SIZE]; | 154 | char tmp[NLS_MAX_CHARSET_SIZE]; |
| 155 | __u16 ftmp; | ||
| 152 | 156 | ||
| 153 | /* | 157 | /* |
| 154 | * because the chars can be of varying widths, we need to take care | 158 | * because the chars can be of varying widths, we need to take care |
| @@ -158,19 +162,23 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, | |||
| 158 | */ | 162 | */ |
| 159 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); | 163 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); |
| 160 | 164 | ||
| 161 | for (i = 0; i < fromwords && from[i]; i++) { | 165 | for (i = 0; i < fromwords; i++) { |
| 166 | ftmp = get_unaligned_le16(&from[i]); | ||
| 167 | if (ftmp == 0) | ||
| 168 | break; | ||
| 169 | |||
| 162 | /* | 170 | /* |
| 163 | * check to see if converting this character might make the | 171 | * check to see if converting this character might make the |
| 164 | * conversion bleed into the null terminator | 172 | * conversion bleed into the null terminator |
| 165 | */ | 173 | */ |
| 166 | if (outlen >= safelen) { | 174 | if (outlen >= safelen) { |
| 167 | charlen = cifs_mapchar(tmp, from[i], codepage, mapchar); | 175 | charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar); |
| 168 | if ((outlen + charlen) > (tolen - nullsize)) | 176 | if ((outlen + charlen) > (tolen - nullsize)) |
| 169 | break; | 177 | break; |
| 170 | } | 178 | } |
| 171 | 179 | ||
| 172 | /* put converted char into 'to' buffer */ | 180 | /* put converted char into 'to' buffer */ |
| 173 | charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar); | 181 | charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar); |
| 174 | outlen += charlen; | 182 | outlen += charlen; |
| 175 | } | 183 | } |
| 176 | 184 | ||
| @@ -193,24 +201,21 @@ cifs_strtoUCS(__le16 *to, const char *from, int len, | |||
| 193 | { | 201 | { |
| 194 | int charlen; | 202 | int charlen; |
| 195 | int i; | 203 | int i; |
| 196 | wchar_t *wchar_to = (wchar_t *)to; /* needed to quiet sparse */ | 204 | wchar_t wchar_to; /* needed to quiet sparse */ |
| 197 | 205 | ||
| 198 | for (i = 0; len && *from; i++, from += charlen, len -= charlen) { | 206 | for (i = 0; len && *from; i++, from += charlen, len -= charlen) { |
| 199 | 207 | charlen = codepage->char2uni(from, len, &wchar_to); | |
| 200 | /* works for 2.4.0 kernel or later */ | ||
| 201 | charlen = codepage->char2uni(from, len, &wchar_to[i]); | ||
| 202 | if (charlen < 1) { | 208 | if (charlen < 1) { |
| 203 | cERROR(1, "strtoUCS: char2uni of %d returned %d", | 209 | cERROR(1, "strtoUCS: char2uni of 0x%x returned %d", |
| 204 | (int)*from, charlen); | 210 | *from, charlen); |
| 205 | /* A question mark */ | 211 | /* A question mark */ |
| 206 | to[i] = cpu_to_le16(0x003f); | 212 | wchar_to = 0x003f; |
| 207 | charlen = 1; | 213 | charlen = 1; |
| 208 | } else | 214 | } |
| 209 | to[i] = cpu_to_le16(wchar_to[i]); | 215 | put_unaligned_le16(wchar_to, &to[i]); |
| 210 | |||
| 211 | } | 216 | } |
| 212 | 217 | ||
| 213 | to[i] = 0; | 218 | put_unaligned_le16(0, &to[i]); |
| 214 | return i; | 219 | return i; |
| 215 | } | 220 | } |
| 216 | 221 | ||
| @@ -252,3 +257,79 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, | |||
| 252 | return dst; | 257 | return dst; |
| 253 | } | 258 | } |
| 254 | 259 | ||
| 260 | /* | ||
| 261 | * Convert 16 bit Unicode pathname to wire format from string in current code | ||
| 262 | * page. Conversion may involve remapping up the six characters that are | ||
| 263 | * only legal in POSIX-like OS (if they are present in the string). Path | ||
| 264 | * names are little endian 16 bit Unicode on the wire | ||
| 265 | */ | ||
| 266 | int | ||
| 267 | cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | ||
| 268 | const struct nls_table *cp, int mapChars) | ||
| 269 | { | ||
| 270 | int i, j, charlen; | ||
| 271 | int len_remaining = maxlen; | ||
| 272 | char src_char; | ||
| 273 | __u16 temp; | ||
| 274 | |||
| 275 | if (!mapChars) | ||
| 276 | return cifs_strtoUCS(target, source, PATH_MAX, cp); | ||
| 277 | |||
| 278 | for (i = 0, j = 0; i < maxlen; j++) { | ||
| 279 | src_char = source[i]; | ||
| 280 | switch (src_char) { | ||
| 281 | case 0: | ||
| 282 | put_unaligned_le16(0, &target[j]); | ||
| 283 | goto ctoUCS_out; | ||
| 284 | case ':': | ||
| 285 | temp = UNI_COLON; | ||
| 286 | break; | ||
| 287 | case '*': | ||
| 288 | temp = UNI_ASTERIK; | ||
| 289 | break; | ||
| 290 | case '?': | ||
| 291 | temp = UNI_QUESTION; | ||
| 292 | break; | ||
| 293 | case '<': | ||
| 294 | temp = UNI_LESSTHAN; | ||
| 295 | break; | ||
| 296 | case '>': | ||
| 297 | temp = UNI_GRTRTHAN; | ||
| 298 | break; | ||
| 299 | case '|': | ||
| 300 | temp = UNI_PIPE; | ||
| 301 | break; | ||
| 302 | /* | ||
| 303 | * FIXME: We can not handle remapping backslash (UNI_SLASH) | ||
| 304 | * until all the calls to build_path_from_dentry are modified, | ||
| 305 | * as they use backslash as separator. | ||
| 306 | */ | ||
| 307 | default: | ||
| 308 | charlen = cp->char2uni(source+i, len_remaining, | ||
| 309 | &temp); | ||
| 310 | /* | ||
| 311 | * if no match, use question mark, which at least in | ||
| 312 | * some cases serves as wild card | ||
| 313 | */ | ||
| 314 | if (charlen < 1) { | ||
| 315 | temp = 0x003f; | ||
| 316 | charlen = 1; | ||
| 317 | } | ||
| 318 | len_remaining -= charlen; | ||
| 319 | /* | ||
| 320 | * character may take more than one byte in the source | ||
| 321 | * string, but will take exactly two bytes in the | ||
| 322 | * target string | ||
| 323 | */ | ||
| 324 | i += charlen; | ||
| 325 | continue; | ||
| 326 | } | ||
| 327 | put_unaligned_le16(temp, &target[j]); | ||
| 328 | i++; /* move to next char in source string */ | ||
| 329 | len_remaining--; | ||
| 330 | } | ||
| 331 | |||
| 332 | ctoUCS_out: | ||
| 333 | return i; | ||
| 334 | } | ||
| 335 | |||
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index a437ec391a01..1e7636b145a8 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
| @@ -41,9 +41,12 @@ static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { | |||
| 41 | ; | 41 | ; |
| 42 | 42 | ||
| 43 | 43 | ||
| 44 | /* security id for everyone */ | 44 | /* security id for everyone/world system group */ |
| 45 | static const struct cifs_sid sid_everyone = { | 45 | static const struct cifs_sid sid_everyone = { |
| 46 | 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; | 46 | 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; |
| 47 | /* security id for Authenticated Users system group */ | ||
| 48 | static const struct cifs_sid sid_authusers = { | ||
| 49 | 1, 1, {0, 0, 0, 0, 0, 5}, {11} }; | ||
| 47 | /* group users */ | 50 | /* group users */ |
| 48 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; | 51 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; |
| 49 | 52 | ||
| @@ -365,7 +368,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
| 365 | if (num_aces > 0) { | 368 | if (num_aces > 0) { |
| 366 | umode_t user_mask = S_IRWXU; | 369 | umode_t user_mask = S_IRWXU; |
| 367 | umode_t group_mask = S_IRWXG; | 370 | umode_t group_mask = S_IRWXG; |
| 368 | umode_t other_mask = S_IRWXO; | 371 | umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO; |
| 369 | 372 | ||
| 370 | ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), | 373 | ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), |
| 371 | GFP_KERNEL); | 374 | GFP_KERNEL); |
| @@ -390,6 +393,12 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
| 390 | ppace[i]->type, | 393 | ppace[i]->type, |
| 391 | &fattr->cf_mode, | 394 | &fattr->cf_mode, |
| 392 | &other_mask); | 395 | &other_mask); |
| 396 | if (compare_sids(&(ppace[i]->sid), &sid_authusers)) | ||
| 397 | access_flags_to_mode(ppace[i]->access_req, | ||
| 398 | ppace[i]->type, | ||
| 399 | &fattr->cf_mode, | ||
| 400 | &other_mask); | ||
| 401 | |||
| 393 | 402 | ||
| 394 | /* memcpy((void *)(&(cifscred->aces[i])), | 403 | /* memcpy((void *)(&(cifscred->aces[i])), |
| 395 | (void *)ppace[i], | 404 | (void *)ppace[i], |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d9f652a522a6..a8323f1dc1c4 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -77,7 +77,11 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ; | |||
| 77 | module_param(cifs_max_pending, int, 0); | 77 | module_param(cifs_max_pending, int, 0); |
| 78 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " | 78 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " |
| 79 | "Default: 50 Range: 2 to 256"); | 79 | "Default: 50 Range: 2 to 256"); |
| 80 | 80 | unsigned short echo_retries = 5; | |
| 81 | module_param(echo_retries, ushort, 0644); | ||
| 82 | MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " | ||
| 83 | "reconnecting server. Default: 5. 0 means " | ||
| 84 | "never reconnect."); | ||
| 81 | extern mempool_t *cifs_sm_req_poolp; | 85 | extern mempool_t *cifs_sm_req_poolp; |
| 82 | extern mempool_t *cifs_req_poolp; | 86 | extern mempool_t *cifs_req_poolp; |
| 83 | extern mempool_t *cifs_mid_poolp; | 87 | extern mempool_t *cifs_mid_poolp; |
| @@ -729,6 +733,25 @@ const struct file_operations cifs_file_ops = { | |||
| 729 | .setlease = cifs_setlease, | 733 | .setlease = cifs_setlease, |
| 730 | }; | 734 | }; |
| 731 | 735 | ||
| 736 | const struct file_operations cifs_file_strict_ops = { | ||
| 737 | .read = do_sync_read, | ||
| 738 | .write = do_sync_write, | ||
| 739 | .aio_read = cifs_strict_readv, | ||
| 740 | .aio_write = cifs_file_aio_write, | ||
| 741 | .open = cifs_open, | ||
| 742 | .release = cifs_close, | ||
| 743 | .lock = cifs_lock, | ||
| 744 | .fsync = cifs_strict_fsync, | ||
| 745 | .flush = cifs_flush, | ||
| 746 | .mmap = cifs_file_strict_mmap, | ||
| 747 | .splice_read = generic_file_splice_read, | ||
| 748 | .llseek = cifs_llseek, | ||
| 749 | #ifdef CONFIG_CIFS_POSIX | ||
| 750 | .unlocked_ioctl = cifs_ioctl, | ||
| 751 | #endif /* CONFIG_CIFS_POSIX */ | ||
| 752 | .setlease = cifs_setlease, | ||
| 753 | }; | ||
| 754 | |||
| 732 | const struct file_operations cifs_file_direct_ops = { | 755 | const struct file_operations cifs_file_direct_ops = { |
| 733 | /* no aio, no readv - | 756 | /* no aio, no readv - |
| 734 | BB reevaluate whether they can be done with directio, no cache */ | 757 | BB reevaluate whether they can be done with directio, no cache */ |
| @@ -747,6 +770,7 @@ const struct file_operations cifs_file_direct_ops = { | |||
| 747 | .llseek = cifs_llseek, | 770 | .llseek = cifs_llseek, |
| 748 | .setlease = cifs_setlease, | 771 | .setlease = cifs_setlease, |
| 749 | }; | 772 | }; |
| 773 | |||
| 750 | const struct file_operations cifs_file_nobrl_ops = { | 774 | const struct file_operations cifs_file_nobrl_ops = { |
| 751 | .read = do_sync_read, | 775 | .read = do_sync_read, |
| 752 | .write = do_sync_write, | 776 | .write = do_sync_write, |
| @@ -765,6 +789,24 @@ const struct file_operations cifs_file_nobrl_ops = { | |||
| 765 | .setlease = cifs_setlease, | 789 | .setlease = cifs_setlease, |
| 766 | }; | 790 | }; |
| 767 | 791 | ||
| 792 | const struct file_operations cifs_file_strict_nobrl_ops = { | ||
| 793 | .read = do_sync_read, | ||
| 794 | .write = do_sync_write, | ||
| 795 | .aio_read = cifs_strict_readv, | ||
| 796 | .aio_write = cifs_file_aio_write, | ||
| 797 | .open = cifs_open, | ||
| 798 | .release = cifs_close, | ||
| 799 | .fsync = cifs_strict_fsync, | ||
| 800 | .flush = cifs_flush, | ||
| 801 | .mmap = cifs_file_strict_mmap, | ||
| 802 | .splice_read = generic_file_splice_read, | ||
| 803 | .llseek = cifs_llseek, | ||
| 804 | #ifdef CONFIG_CIFS_POSIX | ||
| 805 | .unlocked_ioctl = cifs_ioctl, | ||
| 806 | #endif /* CONFIG_CIFS_POSIX */ | ||
| 807 | .setlease = cifs_setlease, | ||
| 808 | }; | ||
| 809 | |||
| 768 | const struct file_operations cifs_file_direct_nobrl_ops = { | 810 | const struct file_operations cifs_file_direct_nobrl_ops = { |
| 769 | /* no mmap, no aio, no readv - | 811 | /* no mmap, no aio, no readv - |
| 770 | BB reevaluate whether they can be done with directio, no cache */ | 812 | BB reevaluate whether they can be done with directio, no cache */ |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 851030f74939..f23206d46531 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
| @@ -61,6 +61,7 @@ extern int cifs_rename(struct inode *, struct dentry *, struct inode *, | |||
| 61 | struct dentry *); | 61 | struct dentry *); |
| 62 | extern int cifs_revalidate_file(struct file *filp); | 62 | extern int cifs_revalidate_file(struct file *filp); |
| 63 | extern int cifs_revalidate_dentry(struct dentry *); | 63 | extern int cifs_revalidate_dentry(struct dentry *); |
| 64 | extern void cifs_invalidate_mapping(struct inode *inode); | ||
| 64 | extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); | 65 | extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); |
| 65 | extern int cifs_setattr(struct dentry *, struct iattr *); | 66 | extern int cifs_setattr(struct dentry *, struct iattr *); |
| 66 | 67 | ||
| @@ -72,19 +73,25 @@ extern const struct inode_operations cifs_dfs_referral_inode_operations; | |||
| 72 | /* Functions related to files and directories */ | 73 | /* Functions related to files and directories */ |
| 73 | extern const struct file_operations cifs_file_ops; | 74 | extern const struct file_operations cifs_file_ops; |
| 74 | extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */ | 75 | extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */ |
| 75 | extern const struct file_operations cifs_file_nobrl_ops; | 76 | extern const struct file_operations cifs_file_strict_ops; /* if strictio mnt */ |
| 76 | extern const struct file_operations cifs_file_direct_nobrl_ops; /* no brlocks */ | 77 | extern const struct file_operations cifs_file_nobrl_ops; /* no brlocks */ |
| 78 | extern const struct file_operations cifs_file_direct_nobrl_ops; | ||
| 79 | extern const struct file_operations cifs_file_strict_nobrl_ops; | ||
| 77 | extern int cifs_open(struct inode *inode, struct file *file); | 80 | extern int cifs_open(struct inode *inode, struct file *file); |
| 78 | extern int cifs_close(struct inode *inode, struct file *file); | 81 | extern int cifs_close(struct inode *inode, struct file *file); |
| 79 | extern int cifs_closedir(struct inode *inode, struct file *file); | 82 | extern int cifs_closedir(struct inode *inode, struct file *file); |
| 80 | extern ssize_t cifs_user_read(struct file *file, char __user *read_data, | 83 | extern ssize_t cifs_user_read(struct file *file, char __user *read_data, |
| 81 | size_t read_size, loff_t *poffset); | 84 | size_t read_size, loff_t *poffset); |
| 85 | extern ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, | ||
| 86 | unsigned long nr_segs, loff_t pos); | ||
| 82 | extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, | 87 | extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, |
| 83 | size_t write_size, loff_t *poffset); | 88 | size_t write_size, loff_t *poffset); |
| 84 | extern int cifs_lock(struct file *, int, struct file_lock *); | 89 | extern int cifs_lock(struct file *, int, struct file_lock *); |
| 85 | extern int cifs_fsync(struct file *, int); | 90 | extern int cifs_fsync(struct file *, int); |
| 91 | extern int cifs_strict_fsync(struct file *, int); | ||
| 86 | extern int cifs_flush(struct file *, fl_owner_t id); | 92 | extern int cifs_flush(struct file *, fl_owner_t id); |
| 87 | extern int cifs_file_mmap(struct file * , struct vm_area_struct *); | 93 | extern int cifs_file_mmap(struct file * , struct vm_area_struct *); |
| 94 | extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *); | ||
| 88 | extern const struct file_operations cifs_dir_ops; | 95 | extern const struct file_operations cifs_dir_ops; |
| 89 | extern int cifs_dir_open(struct inode *inode, struct file *file); | 96 | extern int cifs_dir_open(struct inode *inode, struct file *file); |
| 90 | extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); | 97 | extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); |
| @@ -118,5 +125,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
| 118 | extern const struct export_operations cifs_export_ops; | 125 | extern const struct export_operations cifs_export_ops; |
| 119 | #endif /* EXPERIMENTAL */ | 126 | #endif /* EXPERIMENTAL */ |
| 120 | 127 | ||
| 121 | #define CIFS_VERSION "1.68" | 128 | #define CIFS_VERSION "1.69" |
| 122 | #endif /* _CIFSFS_H */ | 129 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 606ca8bb7102..5bfb75346cb0 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -161,6 +161,7 @@ struct TCP_Server_Info { | |||
| 161 | int srv_count; /* reference counter */ | 161 | int srv_count; /* reference counter */ |
| 162 | /* 15 character server name + 0x20 16th byte indicating type = srv */ | 162 | /* 15 character server name + 0x20 16th byte indicating type = srv */ |
| 163 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; | 163 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; |
| 164 | enum statusEnum tcpStatus; /* what we think the status is */ | ||
| 164 | char *hostname; /* hostname portion of UNC string */ | 165 | char *hostname; /* hostname portion of UNC string */ |
| 165 | struct socket *ssocket; | 166 | struct socket *ssocket; |
| 166 | struct sockaddr_storage dstaddr; | 167 | struct sockaddr_storage dstaddr; |
| @@ -168,25 +169,16 @@ struct TCP_Server_Info { | |||
| 168 | wait_queue_head_t response_q; | 169 | wait_queue_head_t response_q; |
| 169 | wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ | 170 | wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ |
| 170 | struct list_head pending_mid_q; | 171 | struct list_head pending_mid_q; |
| 171 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ | ||
| 172 | unsigned short server_codepage; /* codepage for the server */ | ||
| 173 | enum protocolEnum protocolType; | ||
| 174 | char versionMajor; | ||
| 175 | char versionMinor; | ||
| 176 | bool svlocal:1; /* local server or remote */ | ||
| 177 | bool noblocksnd; /* use blocking sendmsg */ | 172 | bool noblocksnd; /* use blocking sendmsg */ |
| 178 | bool noautotune; /* do not autotune send buf sizes */ | 173 | bool noautotune; /* do not autotune send buf sizes */ |
| 179 | bool tcp_nodelay; | 174 | bool tcp_nodelay; |
| 180 | atomic_t inFlight; /* number of requests on the wire to server */ | 175 | atomic_t inFlight; /* number of requests on the wire to server */ |
| 181 | #ifdef CONFIG_CIFS_STATS2 | ||
| 182 | atomic_t inSend; /* requests trying to send */ | ||
| 183 | atomic_t num_waiters; /* blocked waiting to get in sendrecv */ | ||
| 184 | #endif | ||
| 185 | enum statusEnum tcpStatus; /* what we think the status is */ | ||
| 186 | struct mutex srv_mutex; | 176 | struct mutex srv_mutex; |
| 187 | struct task_struct *tsk; | 177 | struct task_struct *tsk; |
| 188 | char server_GUID[16]; | 178 | char server_GUID[16]; |
| 189 | char secMode; | 179 | char secMode; |
| 180 | bool session_estab; /* mark when very first sess is established */ | ||
| 181 | u16 dialect; /* dialect index that server chose */ | ||
| 190 | enum securityEnum secType; | 182 | enum securityEnum secType; |
| 191 | unsigned int maxReq; /* Clients should submit no more */ | 183 | unsigned int maxReq; /* Clients should submit no more */ |
| 192 | /* than maxReq distinct unanswered SMBs to the server when using */ | 184 | /* than maxReq distinct unanswered SMBs to the server when using */ |
| @@ -199,8 +191,6 @@ struct TCP_Server_Info { | |||
| 199 | unsigned int max_vcs; /* maximum number of smb sessions, at least | 191 | unsigned int max_vcs; /* maximum number of smb sessions, at least |
| 200 | those that can be specified uniquely with | 192 | those that can be specified uniquely with |
| 201 | vcnumbers */ | 193 | vcnumbers */ |
| 202 | char sessid[4]; /* unique token id for this session */ | ||
| 203 | /* (returned on Negotiate */ | ||
| 204 | int capabilities; /* allow selective disabling of caps by smb sess */ | 194 | int capabilities; /* allow selective disabling of caps by smb sess */ |
| 205 | int timeAdj; /* Adjust for difference in server time zone in sec */ | 195 | int timeAdj; /* Adjust for difference in server time zone in sec */ |
| 206 | __u16 CurrentMid; /* multiplex id - rotating counter */ | 196 | __u16 CurrentMid; /* multiplex id - rotating counter */ |
| @@ -210,17 +200,20 @@ struct TCP_Server_Info { | |||
| 210 | __u32 sequence_number; /* for signing, protected by srv_mutex */ | 200 | __u32 sequence_number; /* for signing, protected by srv_mutex */ |
| 211 | struct session_key session_key; | 201 | struct session_key session_key; |
| 212 | unsigned long lstrp; /* when we got last response from this server */ | 202 | unsigned long lstrp; /* when we got last response from this server */ |
| 213 | u16 dialect; /* dialect index that server chose */ | ||
| 214 | struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */ | 203 | struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */ |
| 215 | /* extended security flavors that server supports */ | 204 | /* extended security flavors that server supports */ |
| 205 | bool sec_ntlmssp; /* supports NTLMSSP */ | ||
| 206 | bool sec_kerberosu2u; /* supports U2U Kerberos */ | ||
| 216 | bool sec_kerberos; /* supports plain Kerberos */ | 207 | bool sec_kerberos; /* supports plain Kerberos */ |
| 217 | bool sec_mskerberos; /* supports legacy MS Kerberos */ | 208 | bool sec_mskerberos; /* supports legacy MS Kerberos */ |
| 218 | bool sec_kerberosu2u; /* supports U2U Kerberos */ | 209 | struct delayed_work echo; /* echo ping workqueue job */ |
| 219 | bool sec_ntlmssp; /* supports NTLMSSP */ | ||
| 220 | bool session_estab; /* mark when very first sess is established */ | ||
| 221 | #ifdef CONFIG_CIFS_FSCACHE | 210 | #ifdef CONFIG_CIFS_FSCACHE |
| 222 | struct fscache_cookie *fscache; /* client index cache cookie */ | 211 | struct fscache_cookie *fscache; /* client index cache cookie */ |
| 223 | #endif | 212 | #endif |
| 213 | #ifdef CONFIG_CIFS_STATS2 | ||
| 214 | atomic_t inSend; /* requests trying to send */ | ||
| 215 | atomic_t num_waiters; /* blocked waiting to get in sendrecv */ | ||
| 216 | #endif | ||
| 224 | }; | 217 | }; |
| 225 | 218 | ||
| 226 | /* | 219 | /* |
| @@ -446,11 +439,11 @@ struct cifsInodeInfo { | |||
| 446 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ | 439 | /* BB add in lists for dirty pages i.e. write caching info for oplock */ |
| 447 | struct list_head openFileList; | 440 | struct list_head openFileList; |
| 448 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ | 441 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ |
| 449 | unsigned long time; /* jiffies of last update/check of inode */ | 442 | bool clientCanCacheRead; /* read oplock */ |
| 450 | bool clientCanCacheRead:1; /* read oplock */ | 443 | bool clientCanCacheAll; /* read and writebehind oplock */ |
| 451 | bool clientCanCacheAll:1; /* read and writebehind oplock */ | 444 | bool delete_pending; /* DELETE_ON_CLOSE is set */ |
| 452 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ | 445 | bool invalid_mapping; /* pagecache is invalid */ |
| 453 | bool invalid_mapping:1; /* pagecache is invalid */ | 446 | unsigned long time; /* jiffies of last update of inode */ |
| 454 | u64 server_eof; /* current file size on server */ | 447 | u64 server_eof; /* current file size on server */ |
| 455 | u64 uniqueid; /* server inode number */ | 448 | u64 uniqueid; /* server inode number */ |
| 456 | u64 createtime; /* creation time on server */ | 449 | u64 createtime; /* creation time on server */ |
| @@ -508,6 +501,18 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon, | |||
| 508 | 501 | ||
| 509 | #endif | 502 | #endif |
| 510 | 503 | ||
| 504 | struct mid_q_entry; | ||
| 505 | |||
| 506 | /* | ||
| 507 | * This is the prototype for the mid callback function. When creating one, | ||
| 508 | * take special care to avoid deadlocks. Things to bear in mind: | ||
| 509 | * | ||
| 510 | * - it will be called by cifsd | ||
| 511 | * - the GlobalMid_Lock will be held | ||
| 512 | * - the mid will be removed from the pending_mid_q list | ||
| 513 | */ | ||
| 514 | typedef void (mid_callback_t)(struct mid_q_entry *mid); | ||
| 515 | |||
| 511 | /* one of these for every pending CIFS request to the server */ | 516 | /* one of these for every pending CIFS request to the server */ |
| 512 | struct mid_q_entry { | 517 | struct mid_q_entry { |
| 513 | struct list_head qhead; /* mids waiting on reply from this server */ | 518 | struct list_head qhead; /* mids waiting on reply from this server */ |
| @@ -519,7 +524,8 @@ struct mid_q_entry { | |||
| 519 | unsigned long when_sent; /* time when smb send finished */ | 524 | unsigned long when_sent; /* time when smb send finished */ |
| 520 | unsigned long when_received; /* when demux complete (taken off wire) */ | 525 | unsigned long when_received; /* when demux complete (taken off wire) */ |
| 521 | #endif | 526 | #endif |
| 522 | struct task_struct *tsk; /* task waiting for response */ | 527 | mid_callback_t *callback; /* call completion callback */ |
| 528 | void *callback_data; /* general purpose pointer for callback */ | ||
| 523 | struct smb_hdr *resp_buf; /* response buffer */ | 529 | struct smb_hdr *resp_buf; /* response buffer */ |
| 524 | int midState; /* wish this were enum but can not pass to wait_event */ | 530 | int midState; /* wish this were enum but can not pass to wait_event */ |
| 525 | __u8 command; /* smb command code */ | 531 | __u8 command; /* smb command code */ |
| @@ -622,12 +628,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, | |||
| 622 | #define CIFS_IOVEC 4 /* array of response buffers */ | 628 | #define CIFS_IOVEC 4 /* array of response buffers */ |
| 623 | 629 | ||
| 624 | /* Type of Request to SendReceive2 */ | 630 | /* Type of Request to SendReceive2 */ |
| 625 | #define CIFS_STD_OP 0 /* normal request timeout */ | 631 | #define CIFS_BLOCKING_OP 1 /* operation can block */ |
| 626 | #define CIFS_LONG_OP 1 /* long op (up to 45 sec, oplock time) */ | 632 | #define CIFS_ASYNC_OP 2 /* do not wait for response */ |
| 627 | #define CIFS_VLONG_OP 2 /* sloow op - can take up to 180 seconds */ | 633 | #define CIFS_TIMEOUT_MASK 0x003 /* only one of above set in req */ |
| 628 | #define CIFS_BLOCKING_OP 4 /* operation can block */ | ||
| 629 | #define CIFS_ASYNC_OP 8 /* do not wait for response */ | ||
| 630 | #define CIFS_TIMEOUT_MASK 0x00F /* only one of 5 above set in req */ | ||
| 631 | #define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */ | 634 | #define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */ |
| 632 | #define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */ | 635 | #define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */ |
| 633 | #define CIFS_NO_RESP 0x040 /* no response buffer required */ | 636 | #define CIFS_NO_RESP 0x040 /* no response buffer required */ |
| @@ -790,6 +793,9 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ | |||
| 790 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ | 793 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ |
| 791 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ | 794 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ |
| 792 | 795 | ||
| 796 | /* reconnect after this many failed echo attempts */ | ||
| 797 | GLOBAL_EXTERN unsigned short echo_retries; | ||
| 798 | |||
| 793 | void cifs_oplock_break(struct work_struct *work); | 799 | void cifs_oplock_break(struct work_struct *work); |
| 794 | void cifs_oplock_break_get(struct cifsFileInfo *cfile); | 800 | void cifs_oplock_break_get(struct cifsFileInfo *cfile); |
| 795 | void cifs_oplock_break_put(struct cifsFileInfo *cfile); | 801 | void cifs_oplock_break_put(struct cifsFileInfo *cfile); |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index de36b09763a8..b5c8cc5d7a7f 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #define _CIFSPDU_H | 23 | #define _CIFSPDU_H |
| 24 | 24 | ||
| 25 | #include <net/sock.h> | 25 | #include <net/sock.h> |
| 26 | #include <asm/unaligned.h> | ||
| 26 | #include "smbfsctl.h" | 27 | #include "smbfsctl.h" |
| 27 | 28 | ||
| 28 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 29 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
| @@ -50,6 +51,7 @@ | |||
| 50 | #define SMB_COM_SETATTR 0x09 /* trivial response */ | 51 | #define SMB_COM_SETATTR 0x09 /* trivial response */ |
| 51 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ | 52 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ |
| 52 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ | 53 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ |
| 54 | #define SMB_COM_ECHO 0x2B /* echo request */ | ||
| 53 | #define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */ | 55 | #define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */ |
| 54 | #define SMB_COM_READ_ANDX 0x2E | 56 | #define SMB_COM_READ_ANDX 0x2E |
| 55 | #define SMB_COM_WRITE_ANDX 0x2F | 57 | #define SMB_COM_WRITE_ANDX 0x2F |
| @@ -425,11 +427,49 @@ struct smb_hdr { | |||
| 425 | __u16 Mid; | 427 | __u16 Mid; |
| 426 | __u8 WordCount; | 428 | __u8 WordCount; |
| 427 | } __attribute__((packed)); | 429 | } __attribute__((packed)); |
| 428 | /* given a pointer to an smb_hdr retrieve the value of byte count */ | 430 | |
| 429 | #define BCC(smb_var) (*(__u16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount))) | 431 | /* given a pointer to an smb_hdr retrieve a char pointer to the byte count */ |
| 430 | #define BCC_LE(smb_var) (*(__le16 *)((char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount))) | 432 | #define BCC(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + \ |
| 433 | (2 * (smb_var)->WordCount)) | ||
| 434 | |||
| 431 | /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ | 435 | /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ |
| 432 | #define pByteArea(smb_var) ((unsigned char *)(smb_var) + sizeof(struct smb_hdr) + (2 * (smb_var)->WordCount) + 2) | 436 | #define pByteArea(smb_var) (BCC(smb_var) + 2) |
| 437 | |||
| 438 | /* get the converted ByteCount for a SMB packet and return it */ | ||
| 439 | static inline __u16 | ||
| 440 | get_bcc(struct smb_hdr *hdr) | ||
| 441 | { | ||
| 442 | __u16 *bc_ptr = (__u16 *)BCC(hdr); | ||
| 443 | |||
| 444 | return get_unaligned(bc_ptr); | ||
| 445 | } | ||
| 446 | |||
| 447 | /* get the unconverted ByteCount for a SMB packet and return it */ | ||
| 448 | static inline __u16 | ||
| 449 | get_bcc_le(struct smb_hdr *hdr) | ||
| 450 | { | ||
| 451 | __le16 *bc_ptr = (__le16 *)BCC(hdr); | ||
| 452 | |||
| 453 | return get_unaligned_le16(bc_ptr); | ||
| 454 | } | ||
| 455 | |||
| 456 | /* set the ByteCount for a SMB packet in host-byte order */ | ||
| 457 | static inline void | ||
| 458 | put_bcc(__u16 count, struct smb_hdr *hdr) | ||
| 459 | { | ||
| 460 | __u16 *bc_ptr = (__u16 *)BCC(hdr); | ||
| 461 | |||
| 462 | put_unaligned(count, bc_ptr); | ||
| 463 | } | ||
| 464 | |||
| 465 | /* set the ByteCount for a SMB packet in little-endian */ | ||
| 466 | static inline void | ||
| 467 | put_bcc_le(__u16 count, struct smb_hdr *hdr) | ||
| 468 | { | ||
| 469 | __le16 *bc_ptr = (__le16 *)BCC(hdr); | ||
| 470 | |||
| 471 | put_unaligned_le16(count, bc_ptr); | ||
| 472 | } | ||
| 433 | 473 | ||
| 434 | /* | 474 | /* |
| 435 | * Computer Name Length (since Netbios name was length 16 with last byte 0x20) | 475 | * Computer Name Length (since Netbios name was length 16 with last byte 0x20) |
| @@ -760,6 +800,20 @@ typedef struct smb_com_tconx_rsp_ext { | |||
| 760 | * | 800 | * |
| 761 | */ | 801 | */ |
| 762 | 802 | ||
| 803 | typedef struct smb_com_echo_req { | ||
| 804 | struct smb_hdr hdr; | ||
| 805 | __le16 EchoCount; | ||
| 806 | __le16 ByteCount; | ||
| 807 | char Data[1]; | ||
| 808 | } __attribute__((packed)) ECHO_REQ; | ||
| 809 | |||
| 810 | typedef struct smb_com_echo_rsp { | ||
| 811 | struct smb_hdr hdr; | ||
| 812 | __le16 SequenceNumber; | ||
| 813 | __le16 ByteCount; | ||
| 814 | char Data[1]; | ||
| 815 | } __attribute__((packed)) ECHO_RSP; | ||
| 816 | |||
| 763 | typedef struct smb_com_logoff_andx_req { | 817 | typedef struct smb_com_logoff_andx_req { |
| 764 | struct smb_hdr hdr; /* wct = 2 */ | 818 | struct smb_hdr hdr; /* wct = 2 */ |
| 765 | __u8 AndXCommand; | 819 | __u8 AndXCommand; |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e6d1481b16c1..982895fa7615 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -61,6 +61,12 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata, | |||
| 61 | const char *fullpath, const struct dfs_info3_param *ref, | 61 | const char *fullpath, const struct dfs_info3_param *ref, |
| 62 | char **devname); | 62 | char **devname); |
| 63 | /* extern void renew_parental_timestamps(struct dentry *direntry);*/ | 63 | /* extern void renew_parental_timestamps(struct dentry *direntry);*/ |
| 64 | extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer, | ||
| 65 | struct TCP_Server_Info *server); | ||
| 66 | extern void DeleteMidQEntry(struct mid_q_entry *midEntry); | ||
| 67 | extern int cifs_call_async(struct TCP_Server_Info *server, | ||
| 68 | struct smb_hdr *in_buf, mid_callback_t *callback, | ||
| 69 | void *cbdata); | ||
| 64 | extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | 70 | extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, |
| 65 | struct smb_hdr * /* input */ , | 71 | struct smb_hdr * /* input */ , |
| 66 | struct smb_hdr * /* out */ , | 72 | struct smb_hdr * /* out */ , |
| @@ -347,12 +353,13 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
| 347 | const __u16 netfid, const __u64 len, | 353 | const __u16 netfid, const __u64 len, |
| 348 | const __u64 offset, const __u32 numUnlock, | 354 | const __u64 offset, const __u32 numUnlock, |
| 349 | const __u32 numLock, const __u8 lockType, | 355 | const __u32 numLock, const __u8 lockType, |
| 350 | const bool waitFlag); | 356 | const bool waitFlag, const __u8 oplock_level); |
| 351 | extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | 357 | extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, |
| 352 | const __u16 smb_file_id, const int get_flag, | 358 | const __u16 smb_file_id, const int get_flag, |
| 353 | const __u64 len, struct file_lock *, | 359 | const __u64 len, struct file_lock *, |
| 354 | const __u16 lock_type, const bool waitFlag); | 360 | const __u16 lock_type, const bool waitFlag); |
| 355 | extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); | 361 | extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); |
| 362 | extern int CIFSSMBEcho(struct TCP_Server_Info *server); | ||
| 356 | extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); | 363 | extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); |
| 357 | 364 | ||
| 358 | extern struct cifsSesInfo *sesInfoAlloc(void); | 365 | extern struct cifsSesInfo *sesInfoAlloc(void); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2f6795e524d3..3106f5e5c633 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -331,37 +331,35 @@ smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
| 331 | 331 | ||
| 332 | static int validate_t2(struct smb_t2_rsp *pSMB) | 332 | static int validate_t2(struct smb_t2_rsp *pSMB) |
| 333 | { | 333 | { |
| 334 | int rc = -EINVAL; | 334 | unsigned int total_size; |
| 335 | int total_size; | 335 | |
| 336 | char *pBCC; | 336 | /* check for plausible wct */ |
| 337 | if (pSMB->hdr.WordCount < 10) | ||
| 338 | goto vt2_err; | ||
| 337 | 339 | ||
| 338 | /* check for plausible wct, bcc and t2 data and parm sizes */ | ||
| 339 | /* check for parm and data offset going beyond end of smb */ | 340 | /* check for parm and data offset going beyond end of smb */ |
| 340 | if (pSMB->hdr.WordCount >= 10) { | 341 | if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 || |
| 341 | if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) && | 342 | get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024) |
| 342 | (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) { | 343 | goto vt2_err; |
| 343 | /* check that bcc is at least as big as parms + data */ | 344 | |
| 344 | /* check that bcc is less than negotiated smb buffer */ | 345 | /* check that bcc is at least as big as parms + data */ |
| 345 | total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount); | 346 | /* check that bcc is less than negotiated smb buffer */ |
| 346 | if (total_size < 512) { | 347 | total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount); |
| 347 | total_size += | 348 | if (total_size >= 512) |
| 348 | le16_to_cpu(pSMB->t2_rsp.DataCount); | 349 | goto vt2_err; |
| 349 | /* BCC le converted in SendReceive */ | 350 | |
| 350 | pBCC = (pSMB->hdr.WordCount * 2) + | 351 | total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount); |
| 351 | sizeof(struct smb_hdr) + | 352 | if (total_size > get_bcc(&pSMB->hdr) || |
| 352 | (char *)pSMB; | 353 | total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) |
| 353 | if ((total_size <= (*(u16 *)pBCC)) && | 354 | goto vt2_err; |
| 354 | (total_size < | 355 | |
| 355 | CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) { | 356 | return 0; |
| 356 | return 0; | 357 | vt2_err: |
| 357 | } | ||
| 358 | } | ||
| 359 | } | ||
| 360 | } | ||
| 361 | cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, | 358 | cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, |
| 362 | sizeof(struct smb_t2_rsp) + 16); | 359 | sizeof(struct smb_t2_rsp) + 16); |
| 363 | return rc; | 360 | return -EINVAL; |
| 364 | } | 361 | } |
| 362 | |||
| 365 | int | 363 | int |
| 366 | CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | 364 | CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) |
| 367 | { | 365 | { |
| @@ -452,7 +450,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 452 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), | 450 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), |
| 453 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 451 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
| 454 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | 452 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); |
| 455 | GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); | ||
| 456 | /* even though we do not use raw we might as well set this | 453 | /* even though we do not use raw we might as well set this |
| 457 | accurately, in case we ever find a need for it */ | 454 | accurately, in case we ever find a need for it */ |
| 458 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | 455 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { |
| @@ -566,7 +563,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 566 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 563 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
| 567 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); | 564 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); |
| 568 | cFYI(DBG2, "Max buf = %d", ses->server->maxBuf); | 565 | cFYI(DBG2, "Max buf = %d", ses->server->maxBuf); |
| 569 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); | ||
| 570 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 566 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); |
| 571 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); | 567 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); |
| 572 | server->timeAdj *= 60; | 568 | server->timeAdj *= 60; |
| @@ -706,6 +702,53 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | |||
| 706 | return rc; | 702 | return rc; |
| 707 | } | 703 | } |
| 708 | 704 | ||
| 705 | /* | ||
| 706 | * This is a no-op for now. We're not really interested in the reply, but | ||
| 707 | * rather in the fact that the server sent one and that server->lstrp | ||
| 708 | * gets updated. | ||
| 709 | * | ||
| 710 | * FIXME: maybe we should consider checking that the reply matches request? | ||
| 711 | */ | ||
| 712 | static void | ||
| 713 | cifs_echo_callback(struct mid_q_entry *mid) | ||
| 714 | { | ||
| 715 | struct TCP_Server_Info *server = mid->callback_data; | ||
| 716 | |||
| 717 | DeleteMidQEntry(mid); | ||
| 718 | atomic_dec(&server->inFlight); | ||
| 719 | wake_up(&server->request_q); | ||
| 720 | } | ||
| 721 | |||
| 722 | int | ||
| 723 | CIFSSMBEcho(struct TCP_Server_Info *server) | ||
| 724 | { | ||
| 725 | ECHO_REQ *smb; | ||
| 726 | int rc = 0; | ||
| 727 | |||
| 728 | cFYI(1, "In echo request"); | ||
| 729 | |||
| 730 | rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb); | ||
| 731 | if (rc) | ||
| 732 | return rc; | ||
| 733 | |||
| 734 | /* set up echo request */ | ||
| 735 | smb->hdr.Tid = cpu_to_le16(0xffff); | ||
| 736 | smb->hdr.WordCount = 1; | ||
| 737 | put_unaligned_le16(1, &smb->EchoCount); | ||
| 738 | put_bcc_le(1, &smb->hdr); | ||
| 739 | smb->Data[0] = 'a'; | ||
| 740 | smb->hdr.smb_buf_length += 3; | ||
| 741 | |||
| 742 | rc = cifs_call_async(server, (struct smb_hdr *)smb, | ||
| 743 | cifs_echo_callback, server); | ||
| 744 | if (rc) | ||
| 745 | cFYI(1, "Echo request failed: %d", rc); | ||
| 746 | |||
| 747 | cifs_small_buf_release(smb); | ||
| 748 | |||
| 749 | return rc; | ||
| 750 | } | ||
| 751 | |||
| 709 | int | 752 | int |
| 710 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | 753 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) |
| 711 | { | 754 | { |
| @@ -1193,7 +1236,7 @@ OldOpenRetry: | |||
| 1193 | pSMB->ByteCount = cpu_to_le16(count); | 1236 | pSMB->ByteCount = cpu_to_le16(count); |
| 1194 | /* long_op set to 1 to allow for oplock break timeouts */ | 1237 | /* long_op set to 1 to allow for oplock break timeouts */ |
| 1195 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1238 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1196 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | 1239 | (struct smb_hdr *)pSMBr, &bytes_returned, 0); |
| 1197 | cifs_stats_inc(&tcon->num_opens); | 1240 | cifs_stats_inc(&tcon->num_opens); |
| 1198 | if (rc) { | 1241 | if (rc) { |
| 1199 | cFYI(1, "Error in Open = %d", rc); | 1242 | cFYI(1, "Error in Open = %d", rc); |
| @@ -1306,7 +1349,7 @@ openRetry: | |||
| 1306 | pSMB->ByteCount = cpu_to_le16(count); | 1349 | pSMB->ByteCount = cpu_to_le16(count); |
| 1307 | /* long_op set to 1 to allow for oplock break timeouts */ | 1350 | /* long_op set to 1 to allow for oplock break timeouts */ |
| 1308 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1351 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1309 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | 1352 | (struct smb_hdr *)pSMBr, &bytes_returned, 0); |
| 1310 | cifs_stats_inc(&tcon->num_opens); | 1353 | cifs_stats_inc(&tcon->num_opens); |
| 1311 | if (rc) { | 1354 | if (rc) { |
| 1312 | cFYI(1, "Error in Open = %d", rc); | 1355 | cFYI(1, "Error in Open = %d", rc); |
| @@ -1388,7 +1431,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, | |||
| 1388 | iov[0].iov_base = (char *)pSMB; | 1431 | iov[0].iov_base = (char *)pSMB; |
| 1389 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 1432 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
| 1390 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, | 1433 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, |
| 1391 | &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR); | 1434 | &resp_buf_type, CIFS_LOG_ERROR); |
| 1392 | cifs_stats_inc(&tcon->num_reads); | 1435 | cifs_stats_inc(&tcon->num_reads); |
| 1393 | pSMBr = (READ_RSP *)iov[0].iov_base; | 1436 | pSMBr = (READ_RSP *)iov[0].iov_base; |
| 1394 | if (rc) { | 1437 | if (rc) { |
| @@ -1663,7 +1706,8 @@ int | |||
| 1663 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | 1706 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, |
| 1664 | const __u16 smb_file_id, const __u64 len, | 1707 | const __u16 smb_file_id, const __u64 len, |
| 1665 | const __u64 offset, const __u32 numUnlock, | 1708 | const __u64 offset, const __u32 numUnlock, |
| 1666 | const __u32 numLock, const __u8 lockType, const bool waitFlag) | 1709 | const __u32 numLock, const __u8 lockType, |
| 1710 | const bool waitFlag, const __u8 oplock_level) | ||
| 1667 | { | 1711 | { |
| 1668 | int rc = 0; | 1712 | int rc = 0; |
| 1669 | LOCK_REQ *pSMB = NULL; | 1713 | LOCK_REQ *pSMB = NULL; |
| @@ -1691,6 +1735,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
| 1691 | pSMB->NumberOfLocks = cpu_to_le16(numLock); | 1735 | pSMB->NumberOfLocks = cpu_to_le16(numLock); |
| 1692 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); | 1736 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); |
| 1693 | pSMB->LockType = lockType; | 1737 | pSMB->LockType = lockType; |
| 1738 | pSMB->OplockLevel = oplock_level; | ||
| 1694 | pSMB->AndXCommand = 0xFF; /* none */ | 1739 | pSMB->AndXCommand = 0xFF; /* none */ |
| 1695 | pSMB->Fid = smb_file_id; /* netfid stays le */ | 1740 | pSMB->Fid = smb_file_id; /* netfid stays le */ |
| 1696 | 1741 | ||
| @@ -3087,7 +3132,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, | |||
| 3087 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 3132 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
| 3088 | 3133 | ||
| 3089 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, | 3134 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, |
| 3090 | CIFS_STD_OP); | 3135 | 0); |
| 3091 | cifs_stats_inc(&tcon->num_acl_get); | 3136 | cifs_stats_inc(&tcon->num_acl_get); |
| 3092 | if (rc) { | 3137 | if (rc) { |
| 3093 | cFYI(1, "Send error in QuerySecDesc = %d", rc); | 3138 | cFYI(1, "Send error in QuerySecDesc = %d", rc); |
| @@ -5562,7 +5607,7 @@ QAllEAsRetry: | |||
| 5562 | } | 5607 | } |
| 5563 | 5608 | ||
| 5564 | /* make sure list_len doesn't go past end of SMB */ | 5609 | /* make sure list_len doesn't go past end of SMB */ |
| 5565 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr); | 5610 | end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr); |
| 5566 | if ((char *)ea_response_data + list_len > end_of_smb) { | 5611 | if ((char *)ea_response_data + list_len > end_of_smb) { |
| 5567 | cFYI(1, "EA list appears to go beyond SMB"); | 5612 | cFYI(1, "EA list appears to go beyond SMB"); |
| 5568 | rc = -EIO; | 5613 | rc = -EIO; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 9f59887badd2..18d3c7724d6e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -52,6 +52,9 @@ | |||
| 52 | #define CIFS_PORT 445 | 52 | #define CIFS_PORT 445 |
| 53 | #define RFC1001_PORT 139 | 53 | #define RFC1001_PORT 139 |
| 54 | 54 | ||
| 55 | /* SMB echo "timeout" -- FIXME: tunable? */ | ||
| 56 | #define SMB_ECHO_INTERVAL (60 * HZ) | ||
| 57 | |||
| 55 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | 58 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, |
| 56 | unsigned char *p24); | 59 | unsigned char *p24); |
| 57 | 60 | ||
| @@ -152,6 +155,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 152 | 155 | ||
| 153 | /* before reconnecting the tcp session, mark the smb session (uid) | 156 | /* before reconnecting the tcp session, mark the smb session (uid) |
| 154 | and the tid bad so they are not used until reconnected */ | 157 | and the tid bad so they are not used until reconnected */ |
| 158 | cFYI(1, "%s: marking sessions and tcons for reconnect", __func__); | ||
| 155 | spin_lock(&cifs_tcp_ses_lock); | 159 | spin_lock(&cifs_tcp_ses_lock); |
| 156 | list_for_each(tmp, &server->smb_ses_list) { | 160 | list_for_each(tmp, &server->smb_ses_list) { |
| 157 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | 161 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); |
| @@ -163,7 +167,9 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 163 | } | 167 | } |
| 164 | } | 168 | } |
| 165 | spin_unlock(&cifs_tcp_ses_lock); | 169 | spin_unlock(&cifs_tcp_ses_lock); |
| 170 | |||
| 166 | /* do not want to be sending data on a socket we are freeing */ | 171 | /* do not want to be sending data on a socket we are freeing */ |
| 172 | cFYI(1, "%s: tearing down socket", __func__); | ||
| 167 | mutex_lock(&server->srv_mutex); | 173 | mutex_lock(&server->srv_mutex); |
| 168 | if (server->ssocket) { | 174 | if (server->ssocket) { |
| 169 | cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state, | 175 | cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state, |
| @@ -180,22 +186,20 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 180 | kfree(server->session_key.response); | 186 | kfree(server->session_key.response); |
| 181 | server->session_key.response = NULL; | 187 | server->session_key.response = NULL; |
| 182 | server->session_key.len = 0; | 188 | server->session_key.len = 0; |
| 189 | server->lstrp = jiffies; | ||
| 190 | mutex_unlock(&server->srv_mutex); | ||
| 183 | 191 | ||
| 192 | /* mark submitted MIDs for retry and issue callback */ | ||
| 193 | cFYI(1, "%s: issuing mid callbacks", __func__); | ||
| 184 | spin_lock(&GlobalMid_Lock); | 194 | spin_lock(&GlobalMid_Lock); |
| 185 | list_for_each(tmp, &server->pending_mid_q) { | 195 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
| 186 | mid_entry = list_entry(tmp, struct | 196 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
| 187 | mid_q_entry, | 197 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) |
| 188 | qhead); | ||
| 189 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) { | ||
| 190 | /* Mark other intransit requests as needing | ||
| 191 | retry so we do not immediately mark the | ||
| 192 | session bad again (ie after we reconnect | ||
| 193 | below) as they timeout too */ | ||
| 194 | mid_entry->midState = MID_RETRY_NEEDED; | 198 | mid_entry->midState = MID_RETRY_NEEDED; |
| 195 | } | 199 | list_del_init(&mid_entry->qhead); |
| 200 | mid_entry->callback(mid_entry); | ||
| 196 | } | 201 | } |
| 197 | spin_unlock(&GlobalMid_Lock); | 202 | spin_unlock(&GlobalMid_Lock); |
| 198 | mutex_unlock(&server->srv_mutex); | ||
| 199 | 203 | ||
| 200 | while ((server->tcpStatus != CifsExiting) && | 204 | while ((server->tcpStatus != CifsExiting) && |
| 201 | (server->tcpStatus != CifsGood)) { | 205 | (server->tcpStatus != CifsGood)) { |
| @@ -212,10 +216,9 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 212 | if (server->tcpStatus != CifsExiting) | 216 | if (server->tcpStatus != CifsExiting) |
| 213 | server->tcpStatus = CifsGood; | 217 | server->tcpStatus = CifsGood; |
| 214 | spin_unlock(&GlobalMid_Lock); | 218 | spin_unlock(&GlobalMid_Lock); |
| 215 | /* atomic_set(&server->inFlight,0);*/ | ||
| 216 | wake_up(&server->response_q); | ||
| 217 | } | 219 | } |
| 218 | } | 220 | } |
| 221 | |||
| 219 | return rc; | 222 | return rc; |
| 220 | } | 223 | } |
| 221 | 224 | ||
| @@ -229,9 +232,8 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 229 | static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) | 232 | static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) |
| 230 | { | 233 | { |
| 231 | struct smb_t2_rsp *pSMBt; | 234 | struct smb_t2_rsp *pSMBt; |
| 232 | int total_data_size; | ||
| 233 | int data_in_this_rsp; | ||
| 234 | int remaining; | 235 | int remaining; |
| 236 | __u16 total_data_size, data_in_this_rsp; | ||
| 235 | 237 | ||
| 236 | if (pSMB->Command != SMB_COM_TRANSACTION2) | 238 | if (pSMB->Command != SMB_COM_TRANSACTION2) |
| 237 | return 0; | 239 | return 0; |
| @@ -245,8 +247,8 @@ static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize) | |||
| 245 | 247 | ||
| 246 | pSMBt = (struct smb_t2_rsp *)pSMB; | 248 | pSMBt = (struct smb_t2_rsp *)pSMB; |
| 247 | 249 | ||
| 248 | total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); | 250 | total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); |
| 249 | data_in_this_rsp = le16_to_cpu(pSMBt->t2_rsp.DataCount); | 251 | data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount); |
| 250 | 252 | ||
| 251 | remaining = total_data_size - data_in_this_rsp; | 253 | remaining = total_data_size - data_in_this_rsp; |
| 252 | 254 | ||
| @@ -272,21 +274,18 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) | |||
| 272 | { | 274 | { |
| 273 | struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond; | 275 | struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond; |
| 274 | struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB; | 276 | struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB; |
| 275 | int total_data_size; | ||
| 276 | int total_in_buf; | ||
| 277 | int remaining; | ||
| 278 | int total_in_buf2; | ||
| 279 | char *data_area_of_target; | 277 | char *data_area_of_target; |
| 280 | char *data_area_of_buf2; | 278 | char *data_area_of_buf2; |
| 281 | __u16 byte_count; | 279 | int remaining; |
| 280 | __u16 byte_count, total_data_size, total_in_buf, total_in_buf2; | ||
| 282 | 281 | ||
| 283 | total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount); | 282 | total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); |
| 284 | 283 | ||
| 285 | if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) { | 284 | if (total_data_size != |
| 285 | get_unaligned_le16(&pSMB2->t2_rsp.TotalDataCount)) | ||
| 286 | cFYI(1, "total data size of primary and secondary t2 differ"); | 286 | cFYI(1, "total data size of primary and secondary t2 differ"); |
| 287 | } | ||
| 288 | 287 | ||
| 289 | total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount); | 288 | total_in_buf = get_unaligned_le16(&pSMBt->t2_rsp.DataCount); |
| 290 | 289 | ||
| 291 | remaining = total_data_size - total_in_buf; | 290 | remaining = total_data_size - total_in_buf; |
| 292 | 291 | ||
| @@ -296,28 +295,28 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) | |||
| 296 | if (remaining == 0) /* nothing to do, ignore */ | 295 | if (remaining == 0) /* nothing to do, ignore */ |
| 297 | return 0; | 296 | return 0; |
| 298 | 297 | ||
| 299 | total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount); | 298 | total_in_buf2 = get_unaligned_le16(&pSMB2->t2_rsp.DataCount); |
| 300 | if (remaining < total_in_buf2) { | 299 | if (remaining < total_in_buf2) { |
| 301 | cFYI(1, "transact2 2nd response contains too much data"); | 300 | cFYI(1, "transact2 2nd response contains too much data"); |
| 302 | } | 301 | } |
| 303 | 302 | ||
| 304 | /* find end of first SMB data area */ | 303 | /* find end of first SMB data area */ |
| 305 | data_area_of_target = (char *)&pSMBt->hdr.Protocol + | 304 | data_area_of_target = (char *)&pSMBt->hdr.Protocol + |
| 306 | le16_to_cpu(pSMBt->t2_rsp.DataOffset); | 305 | get_unaligned_le16(&pSMBt->t2_rsp.DataOffset); |
| 307 | /* validate target area */ | 306 | /* validate target area */ |
| 308 | 307 | ||
| 309 | data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol + | 308 | data_area_of_buf2 = (char *)&pSMB2->hdr.Protocol + |
| 310 | le16_to_cpu(pSMB2->t2_rsp.DataOffset); | 309 | get_unaligned_le16(&pSMB2->t2_rsp.DataOffset); |
| 311 | 310 | ||
| 312 | data_area_of_target += total_in_buf; | 311 | data_area_of_target += total_in_buf; |
| 313 | 312 | ||
| 314 | /* copy second buffer into end of first buffer */ | 313 | /* copy second buffer into end of first buffer */ |
| 315 | memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); | 314 | memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2); |
| 316 | total_in_buf += total_in_buf2; | 315 | total_in_buf += total_in_buf2; |
| 317 | pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf); | 316 | put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount); |
| 318 | byte_count = le16_to_cpu(BCC_LE(pTargetSMB)); | 317 | byte_count = get_bcc_le(pTargetSMB); |
| 319 | byte_count += total_in_buf2; | 318 | byte_count += total_in_buf2; |
| 320 | BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); | 319 | put_bcc_le(byte_count, pTargetSMB); |
| 321 | 320 | ||
| 322 | byte_count = pTargetSMB->smb_buf_length; | 321 | byte_count = pTargetSMB->smb_buf_length; |
| 323 | byte_count += total_in_buf2; | 322 | byte_count += total_in_buf2; |
| @@ -331,7 +330,26 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) | |||
| 331 | return 0; /* we are done */ | 330 | return 0; /* we are done */ |
| 332 | } else /* more responses to go */ | 331 | } else /* more responses to go */ |
| 333 | return 1; | 332 | return 1; |
| 333 | } | ||
| 334 | |||
| 335 | static void | ||
| 336 | cifs_echo_request(struct work_struct *work) | ||
| 337 | { | ||
| 338 | int rc; | ||
| 339 | struct TCP_Server_Info *server = container_of(work, | ||
| 340 | struct TCP_Server_Info, echo.work); | ||
| 341 | |||
| 342 | /* no need to ping if we got a response recently */ | ||
| 343 | if (time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ)) | ||
| 344 | goto requeue_echo; | ||
| 334 | 345 | ||
| 346 | rc = CIFSSMBEcho(server); | ||
| 347 | if (rc) | ||
| 348 | cFYI(1, "Unable to send echo request to server: %s", | ||
| 349 | server->hostname); | ||
| 350 | |||
| 351 | requeue_echo: | ||
| 352 | queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL); | ||
| 335 | } | 353 | } |
| 336 | 354 | ||
| 337 | static int | 355 | static int |
| @@ -345,8 +363,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 345 | struct msghdr smb_msg; | 363 | struct msghdr smb_msg; |
| 346 | struct kvec iov; | 364 | struct kvec iov; |
| 347 | struct socket *csocket = server->ssocket; | 365 | struct socket *csocket = server->ssocket; |
| 348 | struct list_head *tmp; | 366 | struct list_head *tmp, *tmp2; |
| 349 | struct cifsSesInfo *ses; | ||
| 350 | struct task_struct *task_to_wake = NULL; | 367 | struct task_struct *task_to_wake = NULL; |
| 351 | struct mid_q_entry *mid_entry; | 368 | struct mid_q_entry *mid_entry; |
| 352 | char temp; | 369 | char temp; |
| @@ -399,7 +416,20 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 399 | smb_msg.msg_control = NULL; | 416 | smb_msg.msg_control = NULL; |
| 400 | smb_msg.msg_controllen = 0; | 417 | smb_msg.msg_controllen = 0; |
| 401 | pdu_length = 4; /* enough to get RFC1001 header */ | 418 | pdu_length = 4; /* enough to get RFC1001 header */ |
| 419 | |||
| 402 | incomplete_rcv: | 420 | incomplete_rcv: |
| 421 | if (echo_retries > 0 && | ||
| 422 | time_after(jiffies, server->lstrp + | ||
| 423 | (echo_retries * SMB_ECHO_INTERVAL))) { | ||
| 424 | cERROR(1, "Server %s has not responded in %d seconds. " | ||
| 425 | "Reconnecting...", server->hostname, | ||
| 426 | (echo_retries * SMB_ECHO_INTERVAL / HZ)); | ||
| 427 | cifs_reconnect(server); | ||
| 428 | csocket = server->ssocket; | ||
| 429 | wake_up(&server->response_q); | ||
| 430 | continue; | ||
| 431 | } | ||
| 432 | |||
| 403 | length = | 433 | length = |
| 404 | kernel_recvmsg(csocket, &smb_msg, | 434 | kernel_recvmsg(csocket, &smb_msg, |
| 405 | &iov, 1, pdu_length, 0 /* BB other flags? */); | 435 | &iov, 1, pdu_length, 0 /* BB other flags? */); |
| @@ -559,10 +589,11 @@ incomplete_rcv: | |||
| 559 | continue; | 589 | continue; |
| 560 | } | 590 | } |
| 561 | 591 | ||
| 592 | mid_entry = NULL; | ||
| 593 | server->lstrp = jiffies; | ||
| 562 | 594 | ||
| 563 | task_to_wake = NULL; | ||
| 564 | spin_lock(&GlobalMid_Lock); | 595 | spin_lock(&GlobalMid_Lock); |
| 565 | list_for_each(tmp, &server->pending_mid_q) { | 596 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
| 566 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 597 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
| 567 | 598 | ||
| 568 | if ((mid_entry->mid == smb_buffer->Mid) && | 599 | if ((mid_entry->mid == smb_buffer->Mid) && |
| @@ -603,20 +634,19 @@ incomplete_rcv: | |||
| 603 | mid_entry->resp_buf = smb_buffer; | 634 | mid_entry->resp_buf = smb_buffer; |
| 604 | mid_entry->largeBuf = isLargeBuf; | 635 | mid_entry->largeBuf = isLargeBuf; |
| 605 | multi_t2_fnd: | 636 | multi_t2_fnd: |
| 606 | task_to_wake = mid_entry->tsk; | ||
| 607 | mid_entry->midState = MID_RESPONSE_RECEIVED; | 637 | mid_entry->midState = MID_RESPONSE_RECEIVED; |
| 638 | list_del_init(&mid_entry->qhead); | ||
| 639 | mid_entry->callback(mid_entry); | ||
| 608 | #ifdef CONFIG_CIFS_STATS2 | 640 | #ifdef CONFIG_CIFS_STATS2 |
| 609 | mid_entry->when_received = jiffies; | 641 | mid_entry->when_received = jiffies; |
| 610 | #endif | 642 | #endif |
| 611 | /* so we do not time out requests to server | ||
| 612 | which is still responding (since server could | ||
| 613 | be busy but not dead) */ | ||
| 614 | server->lstrp = jiffies; | ||
| 615 | break; | 643 | break; |
| 616 | } | 644 | } |
| 645 | mid_entry = NULL; | ||
| 617 | } | 646 | } |
| 618 | spin_unlock(&GlobalMid_Lock); | 647 | spin_unlock(&GlobalMid_Lock); |
| 619 | if (task_to_wake) { | 648 | |
| 649 | if (mid_entry != NULL) { | ||
| 620 | /* Was previous buf put in mpx struct for multi-rsp? */ | 650 | /* Was previous buf put in mpx struct for multi-rsp? */ |
| 621 | if (!isMultiRsp) { | 651 | if (!isMultiRsp) { |
| 622 | /* smb buffer will be freed by user thread */ | 652 | /* smb buffer will be freed by user thread */ |
| @@ -625,11 +655,10 @@ multi_t2_fnd: | |||
| 625 | else | 655 | else |
| 626 | smallbuf = NULL; | 656 | smallbuf = NULL; |
| 627 | } | 657 | } |
| 628 | wake_up_process(task_to_wake); | ||
| 629 | } else if (!is_valid_oplock_break(smb_buffer, server) && | 658 | } else if (!is_valid_oplock_break(smb_buffer, server) && |
| 630 | !isMultiRsp) { | 659 | !isMultiRsp) { |
| 631 | cERROR(1, "No task to wake, unknown frame received! " | 660 | cERROR(1, "No task to wake, unknown frame received! " |
| 632 | "NumMids %d", midCount.counter); | 661 | "NumMids %d", atomic_read(&midCount)); |
| 633 | cifs_dump_mem("Received Data is: ", (char *)smb_buffer, | 662 | cifs_dump_mem("Received Data is: ", (char *)smb_buffer, |
| 634 | sizeof(struct smb_hdr)); | 663 | sizeof(struct smb_hdr)); |
| 635 | #ifdef CONFIG_CIFS_DEBUG2 | 664 | #ifdef CONFIG_CIFS_DEBUG2 |
| @@ -677,44 +706,16 @@ multi_t2_fnd: | |||
| 677 | if (smallbuf) /* no sense logging a debug message if NULL */ | 706 | if (smallbuf) /* no sense logging a debug message if NULL */ |
| 678 | cifs_small_buf_release(smallbuf); | 707 | cifs_small_buf_release(smallbuf); |
| 679 | 708 | ||
| 680 | /* | 709 | if (!list_empty(&server->pending_mid_q)) { |
| 681 | * BB: we shouldn't have to do any of this. It shouldn't be | ||
| 682 | * possible to exit from the thread with active SMB sessions | ||
| 683 | */ | ||
| 684 | spin_lock(&cifs_tcp_ses_lock); | ||
| 685 | if (list_empty(&server->pending_mid_q)) { | ||
| 686 | /* loop through server session structures attached to this and | ||
| 687 | mark them dead */ | ||
| 688 | list_for_each(tmp, &server->smb_ses_list) { | ||
| 689 | ses = list_entry(tmp, struct cifsSesInfo, | ||
| 690 | smb_ses_list); | ||
| 691 | ses->status = CifsExiting; | ||
| 692 | ses->server = NULL; | ||
| 693 | } | ||
| 694 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 695 | } else { | ||
| 696 | /* although we can not zero the server struct pointer yet, | ||
| 697 | since there are active requests which may depnd on them, | ||
| 698 | mark the corresponding SMB sessions as exiting too */ | ||
| 699 | list_for_each(tmp, &server->smb_ses_list) { | ||
| 700 | ses = list_entry(tmp, struct cifsSesInfo, | ||
| 701 | smb_ses_list); | ||
| 702 | ses->status = CifsExiting; | ||
| 703 | } | ||
| 704 | |||
| 705 | spin_lock(&GlobalMid_Lock); | 710 | spin_lock(&GlobalMid_Lock); |
| 706 | list_for_each(tmp, &server->pending_mid_q) { | 711 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
| 707 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 712 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
| 708 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) { | 713 | cFYI(1, "Clearing Mid 0x%x - issuing callback", |
| 709 | cFYI(1, "Clearing Mid 0x%x - waking up ", | ||
| 710 | mid_entry->mid); | 714 | mid_entry->mid); |
| 711 | task_to_wake = mid_entry->tsk; | 715 | list_del_init(&mid_entry->qhead); |
| 712 | if (task_to_wake) | 716 | mid_entry->callback(mid_entry); |
| 713 | wake_up_process(task_to_wake); | ||
| 714 | } | ||
| 715 | } | 717 | } |
| 716 | spin_unlock(&GlobalMid_Lock); | 718 | spin_unlock(&GlobalMid_Lock); |
| 717 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 718 | /* 1/8th of sec is more than enough time for them to exit */ | 719 | /* 1/8th of sec is more than enough time for them to exit */ |
| 719 | msleep(125); | 720 | msleep(125); |
| 720 | } | 721 | } |
| @@ -732,18 +733,6 @@ multi_t2_fnd: | |||
| 732 | coming home not much else we can do but free the memory */ | 733 | coming home not much else we can do but free the memory */ |
| 733 | } | 734 | } |
| 734 | 735 | ||
| 735 | /* last chance to mark ses pointers invalid | ||
| 736 | if there are any pointing to this (e.g | ||
| 737 | if a crazy root user tried to kill cifsd | ||
| 738 | kernel thread explicitly this might happen) */ | ||
| 739 | /* BB: This shouldn't be necessary, see above */ | ||
| 740 | spin_lock(&cifs_tcp_ses_lock); | ||
| 741 | list_for_each(tmp, &server->smb_ses_list) { | ||
| 742 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | ||
| 743 | ses->server = NULL; | ||
| 744 | } | ||
| 745 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 746 | |||
| 747 | kfree(server->hostname); | 736 | kfree(server->hostname); |
| 748 | task_to_wake = xchg(&server->tsk, NULL); | 737 | task_to_wake = xchg(&server->tsk, NULL); |
| 749 | kfree(server); | 738 | kfree(server); |
| @@ -1612,6 +1601,8 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) | |||
| 1612 | list_del_init(&server->tcp_ses_list); | 1601 | list_del_init(&server->tcp_ses_list); |
| 1613 | spin_unlock(&cifs_tcp_ses_lock); | 1602 | spin_unlock(&cifs_tcp_ses_lock); |
| 1614 | 1603 | ||
| 1604 | cancel_delayed_work_sync(&server->echo); | ||
| 1605 | |||
| 1615 | spin_lock(&GlobalMid_Lock); | 1606 | spin_lock(&GlobalMid_Lock); |
| 1616 | server->tcpStatus = CifsExiting; | 1607 | server->tcpStatus = CifsExiting; |
| 1617 | spin_unlock(&GlobalMid_Lock); | 1608 | spin_unlock(&GlobalMid_Lock); |
| @@ -1701,8 +1692,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
| 1701 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); | 1692 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); |
| 1702 | tcp_ses->session_estab = false; | 1693 | tcp_ses->session_estab = false; |
| 1703 | tcp_ses->sequence_number = 0; | 1694 | tcp_ses->sequence_number = 0; |
| 1695 | tcp_ses->lstrp = jiffies; | ||
| 1704 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); | 1696 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); |
| 1705 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); | 1697 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); |
| 1698 | INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); | ||
| 1706 | 1699 | ||
| 1707 | /* | 1700 | /* |
| 1708 | * at this point we are the only ones with the pointer | 1701 | * at this point we are the only ones with the pointer |
| @@ -1751,6 +1744,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
| 1751 | 1744 | ||
| 1752 | cifs_fscache_get_client_cookie(tcp_ses); | 1745 | cifs_fscache_get_client_cookie(tcp_ses); |
| 1753 | 1746 | ||
| 1747 | /* queue echo request delayed work */ | ||
| 1748 | queue_delayed_work(system_nrt_wq, &tcp_ses->echo, SMB_ECHO_INTERVAL); | ||
| 1749 | |||
| 1754 | return tcp_ses; | 1750 | return tcp_ses; |
| 1755 | 1751 | ||
| 1756 | out_err_crypto_release: | 1752 | out_err_crypto_release: |
| @@ -2936,8 +2932,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2936 | TCONX_RSP *pSMBr; | 2932 | TCONX_RSP *pSMBr; |
| 2937 | unsigned char *bcc_ptr; | 2933 | unsigned char *bcc_ptr; |
| 2938 | int rc = 0; | 2934 | int rc = 0; |
| 2939 | int length, bytes_left; | 2935 | int length; |
| 2940 | __u16 count; | 2936 | __u16 bytes_left, count; |
| 2941 | 2937 | ||
| 2942 | if (ses == NULL) | 2938 | if (ses == NULL) |
| 2943 | return -EIO; | 2939 | return -EIO; |
| @@ -2965,7 +2961,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2965 | bcc_ptr++; /* skip password */ | 2961 | bcc_ptr++; /* skip password */ |
| 2966 | /* already aligned so no need to do it below */ | 2962 | /* already aligned so no need to do it below */ |
| 2967 | } else { | 2963 | } else { |
| 2968 | pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); | 2964 | pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
| 2969 | /* BB FIXME add code to fail this if NTLMv2 or Kerberos | 2965 | /* BB FIXME add code to fail this if NTLMv2 or Kerberos |
| 2970 | specified as required (when that support is added to | 2966 | specified as required (when that support is added to |
| 2971 | the vfs in the future) as only NTLM or the much | 2967 | the vfs in the future) as only NTLM or the much |
| @@ -2983,7 +2979,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2983 | #endif /* CIFS_WEAK_PW_HASH */ | 2979 | #endif /* CIFS_WEAK_PW_HASH */ |
| 2984 | SMBNTencrypt(tcon->password, ses->server->cryptkey, bcc_ptr); | 2980 | SMBNTencrypt(tcon->password, ses->server->cryptkey, bcc_ptr); |
| 2985 | 2981 | ||
| 2986 | bcc_ptr += CIFS_SESS_KEY_SIZE; | 2982 | bcc_ptr += CIFS_AUTH_RESP_SIZE; |
| 2987 | if (ses->capabilities & CAP_UNICODE) { | 2983 | if (ses->capabilities & CAP_UNICODE) { |
| 2988 | /* must align unicode strings */ | 2984 | /* must align unicode strings */ |
| 2989 | *bcc_ptr = 0; /* null byte password */ | 2985 | *bcc_ptr = 0; /* null byte password */ |
| @@ -3021,7 +3017,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3021 | pSMB->ByteCount = cpu_to_le16(count); | 3017 | pSMB->ByteCount = cpu_to_le16(count); |
| 3022 | 3018 | ||
| 3023 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, | 3019 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, |
| 3024 | CIFS_STD_OP); | 3020 | 0); |
| 3025 | 3021 | ||
| 3026 | /* above now done in SendReceive */ | 3022 | /* above now done in SendReceive */ |
| 3027 | if ((rc == 0) && (tcon != NULL)) { | 3023 | if ((rc == 0) && (tcon != NULL)) { |
| @@ -3031,7 +3027,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3031 | tcon->need_reconnect = false; | 3027 | tcon->need_reconnect = false; |
| 3032 | tcon->tid = smb_buffer_response->Tid; | 3028 | tcon->tid = smb_buffer_response->Tid; |
| 3033 | bcc_ptr = pByteArea(smb_buffer_response); | 3029 | bcc_ptr = pByteArea(smb_buffer_response); |
| 3034 | bytes_left = BCC(smb_buffer_response); | 3030 | bytes_left = get_bcc(smb_buffer_response); |
| 3035 | length = strnlen(bcc_ptr, bytes_left - 2); | 3031 | length = strnlen(bcc_ptr, bytes_left - 2); |
| 3036 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) | 3032 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) |
| 3037 | is_unicode = true; | 3033 | is_unicode = true; |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index d843631c028d..d7d65a70678e 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -287,6 +287,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
| 287 | struct inode *inode = cifs_file->dentry->d_inode; | 287 | struct inode *inode = cifs_file->dentry->d_inode; |
| 288 | struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink); | 288 | struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink); |
| 289 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 289 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
| 290 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
| 290 | struct cifsLockInfo *li, *tmp; | 291 | struct cifsLockInfo *li, *tmp; |
| 291 | 292 | ||
| 292 | spin_lock(&cifs_file_list_lock); | 293 | spin_lock(&cifs_file_list_lock); |
| @@ -302,6 +303,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
| 302 | if (list_empty(&cifsi->openFileList)) { | 303 | if (list_empty(&cifsi->openFileList)) { |
| 303 | cFYI(1, "closing last open instance for inode %p", | 304 | cFYI(1, "closing last open instance for inode %p", |
| 304 | cifs_file->dentry->d_inode); | 305 | cifs_file->dentry->d_inode); |
| 306 | |||
| 307 | /* in strict cache mode we need invalidate mapping on the last | ||
| 308 | close because it may cause a error when we open this file | ||
| 309 | again and get at least level II oplock */ | ||
| 310 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) | ||
| 311 | CIFS_I(inode)->invalid_mapping = true; | ||
| 312 | |||
| 305 | cifs_set_oplock_level(cifsi, 0); | 313 | cifs_set_oplock_level(cifsi, 0); |
| 306 | } | 314 | } |
| 307 | spin_unlock(&cifs_file_list_lock); | 315 | spin_unlock(&cifs_file_list_lock); |
| @@ -726,12 +734,12 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 726 | 734 | ||
| 727 | /* BB we could chain these into one lock request BB */ | 735 | /* BB we could chain these into one lock request BB */ |
| 728 | rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start, | 736 | rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start, |
| 729 | 0, 1, lockType, 0 /* wait flag */ ); | 737 | 0, 1, lockType, 0 /* wait flag */, 0); |
| 730 | if (rc == 0) { | 738 | if (rc == 0) { |
| 731 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 739 | rc = CIFSSMBLock(xid, tcon, netfid, length, |
| 732 | pfLock->fl_start, 1 /* numUnlock */ , | 740 | pfLock->fl_start, 1 /* numUnlock */ , |
| 733 | 0 /* numLock */ , lockType, | 741 | 0 /* numLock */ , lockType, |
| 734 | 0 /* wait flag */ ); | 742 | 0 /* wait flag */, 0); |
| 735 | pfLock->fl_type = F_UNLCK; | 743 | pfLock->fl_type = F_UNLCK; |
| 736 | if (rc != 0) | 744 | if (rc != 0) |
| 737 | cERROR(1, "Error unlocking previously locked " | 745 | cERROR(1, "Error unlocking previously locked " |
| @@ -748,13 +756,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 748 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 756 | rc = CIFSSMBLock(xid, tcon, netfid, length, |
| 749 | pfLock->fl_start, 0, 1, | 757 | pfLock->fl_start, 0, 1, |
| 750 | lockType | LOCKING_ANDX_SHARED_LOCK, | 758 | lockType | LOCKING_ANDX_SHARED_LOCK, |
| 751 | 0 /* wait flag */); | 759 | 0 /* wait flag */, 0); |
| 752 | if (rc == 0) { | 760 | if (rc == 0) { |
| 753 | rc = CIFSSMBLock(xid, tcon, netfid, | 761 | rc = CIFSSMBLock(xid, tcon, netfid, |
| 754 | length, pfLock->fl_start, 1, 0, | 762 | length, pfLock->fl_start, 1, 0, |
| 755 | lockType | | 763 | lockType | |
| 756 | LOCKING_ANDX_SHARED_LOCK, | 764 | LOCKING_ANDX_SHARED_LOCK, |
| 757 | 0 /* wait flag */); | 765 | 0 /* wait flag */, 0); |
| 758 | pfLock->fl_type = F_RDLCK; | 766 | pfLock->fl_type = F_RDLCK; |
| 759 | if (rc != 0) | 767 | if (rc != 0) |
| 760 | cERROR(1, "Error unlocking " | 768 | cERROR(1, "Error unlocking " |
| @@ -797,8 +805,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 797 | 805 | ||
| 798 | if (numLock) { | 806 | if (numLock) { |
| 799 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 807 | rc = CIFSSMBLock(xid, tcon, netfid, length, |
| 800 | pfLock->fl_start, | 808 | pfLock->fl_start, 0, numLock, lockType, |
| 801 | 0, numLock, lockType, wait_flag); | 809 | wait_flag, 0); |
| 802 | 810 | ||
| 803 | if (rc == 0) { | 811 | if (rc == 0) { |
| 804 | /* For Windows locks we must store them. */ | 812 | /* For Windows locks we must store them. */ |
| @@ -818,9 +826,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 818 | (pfLock->fl_start + length) >= | 826 | (pfLock->fl_start + length) >= |
| 819 | (li->offset + li->length)) { | 827 | (li->offset + li->length)) { |
| 820 | stored_rc = CIFSSMBLock(xid, tcon, | 828 | stored_rc = CIFSSMBLock(xid, tcon, |
| 821 | netfid, | 829 | netfid, li->length, |
| 822 | li->length, li->offset, | 830 | li->offset, 1, 0, |
| 823 | 1, 0, li->type, false); | 831 | li->type, false, 0); |
| 824 | if (stored_rc) | 832 | if (stored_rc) |
| 825 | rc = stored_rc; | 833 | rc = stored_rc; |
| 826 | else { | 834 | else { |
| @@ -839,29 +847,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 839 | return rc; | 847 | return rc; |
| 840 | } | 848 | } |
| 841 | 849 | ||
| 842 | /* | ||
| 843 | * Set the timeout on write requests past EOF. For some servers (Windows) | ||
| 844 | * these calls can be very long. | ||
| 845 | * | ||
| 846 | * If we're writing >10M past the EOF we give a 180s timeout. Anything less | ||
| 847 | * than that gets a 45s timeout. Writes not past EOF get 15s timeouts. | ||
| 848 | * The 10M cutoff is totally arbitrary. A better scheme for this would be | ||
| 849 | * welcome if someone wants to suggest one. | ||
| 850 | * | ||
| 851 | * We may be able to do a better job with this if there were some way to | ||
| 852 | * declare that a file should be sparse. | ||
| 853 | */ | ||
| 854 | static int | ||
| 855 | cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset) | ||
| 856 | { | ||
| 857 | if (offset <= cifsi->server_eof) | ||
| 858 | return CIFS_STD_OP; | ||
| 859 | else if (offset > (cifsi->server_eof + (10 * 1024 * 1024))) | ||
| 860 | return CIFS_VLONG_OP; | ||
| 861 | else | ||
| 862 | return CIFS_LONG_OP; | ||
| 863 | } | ||
| 864 | |||
| 865 | /* update the file size (if needed) after a write */ | 850 | /* update the file size (if needed) after a write */ |
| 866 | static void | 851 | static void |
| 867 | cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, | 852 | cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, |
| @@ -882,7 +867,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 882 | unsigned int total_written; | 867 | unsigned int total_written; |
| 883 | struct cifs_sb_info *cifs_sb; | 868 | struct cifs_sb_info *cifs_sb; |
| 884 | struct cifsTconInfo *pTcon; | 869 | struct cifsTconInfo *pTcon; |
| 885 | int xid, long_op; | 870 | int xid; |
| 886 | struct cifsFileInfo *open_file; | 871 | struct cifsFileInfo *open_file; |
| 887 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 872 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
| 888 | 873 | ||
| @@ -903,7 +888,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 903 | 888 | ||
| 904 | xid = GetXid(); | 889 | xid = GetXid(); |
| 905 | 890 | ||
| 906 | long_op = cifs_write_timeout(cifsi, *poffset); | ||
| 907 | for (total_written = 0; write_size > total_written; | 891 | for (total_written = 0; write_size > total_written; |
| 908 | total_written += bytes_written) { | 892 | total_written += bytes_written) { |
| 909 | rc = -EAGAIN; | 893 | rc = -EAGAIN; |
| @@ -931,7 +915,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 931 | min_t(const int, cifs_sb->wsize, | 915 | min_t(const int, cifs_sb->wsize, |
| 932 | write_size - total_written), | 916 | write_size - total_written), |
| 933 | *poffset, &bytes_written, | 917 | *poffset, &bytes_written, |
| 934 | NULL, write_data + total_written, long_op); | 918 | NULL, write_data + total_written, 0); |
| 935 | } | 919 | } |
| 936 | if (rc || (bytes_written == 0)) { | 920 | if (rc || (bytes_written == 0)) { |
| 937 | if (total_written) | 921 | if (total_written) |
| @@ -944,8 +928,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 944 | cifs_update_eof(cifsi, *poffset, bytes_written); | 928 | cifs_update_eof(cifsi, *poffset, bytes_written); |
| 945 | *poffset += bytes_written; | 929 | *poffset += bytes_written; |
| 946 | } | 930 | } |
| 947 | long_op = CIFS_STD_OP; /* subsequent writes fast - | ||
| 948 | 15 seconds is plenty */ | ||
| 949 | } | 931 | } |
| 950 | 932 | ||
| 951 | cifs_stats_bytes_written(pTcon, total_written); | 933 | cifs_stats_bytes_written(pTcon, total_written); |
| @@ -974,7 +956,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
| 974 | unsigned int total_written; | 956 | unsigned int total_written; |
| 975 | struct cifs_sb_info *cifs_sb; | 957 | struct cifs_sb_info *cifs_sb; |
| 976 | struct cifsTconInfo *pTcon; | 958 | struct cifsTconInfo *pTcon; |
| 977 | int xid, long_op; | 959 | int xid; |
| 978 | struct dentry *dentry = open_file->dentry; | 960 | struct dentry *dentry = open_file->dentry; |
| 979 | struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode); | 961 | struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode); |
| 980 | 962 | ||
| @@ -987,7 +969,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
| 987 | 969 | ||
| 988 | xid = GetXid(); | 970 | xid = GetXid(); |
| 989 | 971 | ||
| 990 | long_op = cifs_write_timeout(cifsi, *poffset); | ||
| 991 | for (total_written = 0; write_size > total_written; | 972 | for (total_written = 0; write_size > total_written; |
| 992 | total_written += bytes_written) { | 973 | total_written += bytes_written) { |
| 993 | rc = -EAGAIN; | 974 | rc = -EAGAIN; |
| @@ -1017,7 +998,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
| 1017 | rc = CIFSSMBWrite2(xid, pTcon, | 998 | rc = CIFSSMBWrite2(xid, pTcon, |
| 1018 | open_file->netfid, len, | 999 | open_file->netfid, len, |
| 1019 | *poffset, &bytes_written, | 1000 | *poffset, &bytes_written, |
| 1020 | iov, 1, long_op); | 1001 | iov, 1, 0); |
| 1021 | } else | 1002 | } else |
| 1022 | rc = CIFSSMBWrite(xid, pTcon, | 1003 | rc = CIFSSMBWrite(xid, pTcon, |
| 1023 | open_file->netfid, | 1004 | open_file->netfid, |
| @@ -1025,7 +1006,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
| 1025 | write_size - total_written), | 1006 | write_size - total_written), |
| 1026 | *poffset, &bytes_written, | 1007 | *poffset, &bytes_written, |
| 1027 | write_data + total_written, | 1008 | write_data + total_written, |
| 1028 | NULL, long_op); | 1009 | NULL, 0); |
| 1029 | } | 1010 | } |
| 1030 | if (rc || (bytes_written == 0)) { | 1011 | if (rc || (bytes_written == 0)) { |
| 1031 | if (total_written) | 1012 | if (total_written) |
| @@ -1038,8 +1019,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
| 1038 | cifs_update_eof(cifsi, *poffset, bytes_written); | 1019 | cifs_update_eof(cifsi, *poffset, bytes_written); |
| 1039 | *poffset += bytes_written; | 1020 | *poffset += bytes_written; |
| 1040 | } | 1021 | } |
| 1041 | long_op = CIFS_STD_OP; /* subsequent writes fast - | ||
| 1042 | 15 seconds is plenty */ | ||
| 1043 | } | 1022 | } |
| 1044 | 1023 | ||
| 1045 | cifs_stats_bytes_written(pTcon, total_written); | 1024 | cifs_stats_bytes_written(pTcon, total_written); |
| @@ -1239,7 +1218,7 @@ static int cifs_writepages(struct address_space *mapping, | |||
| 1239 | struct pagevec pvec; | 1218 | struct pagevec pvec; |
| 1240 | int rc = 0; | 1219 | int rc = 0; |
| 1241 | int scanned = 0; | 1220 | int scanned = 0; |
| 1242 | int xid, long_op; | 1221 | int xid; |
| 1243 | 1222 | ||
| 1244 | cifs_sb = CIFS_SB(mapping->host->i_sb); | 1223 | cifs_sb = CIFS_SB(mapping->host->i_sb); |
| 1245 | 1224 | ||
| @@ -1377,43 +1356,67 @@ retry: | |||
| 1377 | break; | 1356 | break; |
| 1378 | } | 1357 | } |
| 1379 | if (n_iov) { | 1358 | if (n_iov) { |
| 1359 | retry_write: | ||
| 1380 | open_file = find_writable_file(CIFS_I(mapping->host), | 1360 | open_file = find_writable_file(CIFS_I(mapping->host), |
| 1381 | false); | 1361 | false); |
| 1382 | if (!open_file) { | 1362 | if (!open_file) { |
| 1383 | cERROR(1, "No writable handles for inode"); | 1363 | cERROR(1, "No writable handles for inode"); |
| 1384 | rc = -EBADF; | 1364 | rc = -EBADF; |
| 1385 | } else { | 1365 | } else { |
| 1386 | long_op = cifs_write_timeout(cifsi, offset); | ||
| 1387 | rc = CIFSSMBWrite2(xid, tcon, open_file->netfid, | 1366 | rc = CIFSSMBWrite2(xid, tcon, open_file->netfid, |
| 1388 | bytes_to_write, offset, | 1367 | bytes_to_write, offset, |
| 1389 | &bytes_written, iov, n_iov, | 1368 | &bytes_written, iov, n_iov, |
| 1390 | long_op); | 1369 | 0); |
| 1391 | cifsFileInfo_put(open_file); | 1370 | cifsFileInfo_put(open_file); |
| 1392 | cifs_update_eof(cifsi, offset, bytes_written); | ||
| 1393 | } | 1371 | } |
| 1394 | 1372 | ||
| 1395 | if (rc || bytes_written < bytes_to_write) { | 1373 | cFYI(1, "Write2 rc=%d, wrote=%u", rc, bytes_written); |
| 1396 | cERROR(1, "Write2 ret %d, wrote %d", | 1374 | |
| 1397 | rc, bytes_written); | 1375 | /* |
| 1398 | mapping_set_error(mapping, rc); | 1376 | * For now, treat a short write as if nothing got |
| 1399 | } else { | 1377 | * written. A zero length write however indicates |
| 1378 | * ENOSPC or EFBIG. We have no way to know which | ||
| 1379 | * though, so call it ENOSPC for now. EFBIG would | ||
| 1380 | * get translated to AS_EIO anyway. | ||
| 1381 | * | ||
| 1382 | * FIXME: make it take into account the data that did | ||
| 1383 | * get written | ||
| 1384 | */ | ||
| 1385 | if (rc == 0) { | ||
| 1386 | if (bytes_written == 0) | ||
| 1387 | rc = -ENOSPC; | ||
| 1388 | else if (bytes_written < bytes_to_write) | ||
| 1389 | rc = -EAGAIN; | ||
| 1390 | } | ||
| 1391 | |||
| 1392 | /* retry on data-integrity flush */ | ||
| 1393 | if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN) | ||
| 1394 | goto retry_write; | ||
| 1395 | |||
| 1396 | /* fix the stats and EOF */ | ||
| 1397 | if (bytes_written > 0) { | ||
| 1400 | cifs_stats_bytes_written(tcon, bytes_written); | 1398 | cifs_stats_bytes_written(tcon, bytes_written); |
| 1399 | cifs_update_eof(cifsi, offset, bytes_written); | ||
| 1401 | } | 1400 | } |
| 1402 | 1401 | ||
| 1403 | for (i = 0; i < n_iov; i++) { | 1402 | for (i = 0; i < n_iov; i++) { |
| 1404 | page = pvec.pages[first + i]; | 1403 | page = pvec.pages[first + i]; |
| 1405 | /* Should we also set page error on | 1404 | /* on retryable write error, redirty page */ |
| 1406 | success rc but too little data written? */ | 1405 | if (rc == -EAGAIN) |
| 1407 | /* BB investigate retry logic on temporary | 1406 | redirty_page_for_writepage(wbc, page); |
| 1408 | server crash cases and how recovery works | 1407 | else if (rc != 0) |
| 1409 | when page marked as error */ | ||
| 1410 | if (rc) | ||
| 1411 | SetPageError(page); | 1408 | SetPageError(page); |
| 1412 | kunmap(page); | 1409 | kunmap(page); |
| 1413 | unlock_page(page); | 1410 | unlock_page(page); |
| 1414 | end_page_writeback(page); | 1411 | end_page_writeback(page); |
| 1415 | page_cache_release(page); | 1412 | page_cache_release(page); |
| 1416 | } | 1413 | } |
| 1414 | |||
| 1415 | if (rc != -EAGAIN) | ||
| 1416 | mapping_set_error(mapping, rc); | ||
| 1417 | else | ||
| 1418 | rc = 0; | ||
| 1419 | |||
| 1417 | if ((wbc->nr_to_write -= n_iov) <= 0) | 1420 | if ((wbc->nr_to_write -= n_iov) <= 0) |
| 1418 | done = 1; | 1421 | done = 1; |
| 1419 | index = next; | 1422 | index = next; |
| @@ -1525,27 +1528,47 @@ static int cifs_write_end(struct file *file, struct address_space *mapping, | |||
| 1525 | return rc; | 1528 | return rc; |
| 1526 | } | 1529 | } |
| 1527 | 1530 | ||
| 1528 | int cifs_fsync(struct file *file, int datasync) | 1531 | int cifs_strict_fsync(struct file *file, int datasync) |
| 1529 | { | 1532 | { |
| 1530 | int xid; | 1533 | int xid; |
| 1531 | int rc = 0; | 1534 | int rc = 0; |
| 1532 | struct cifsTconInfo *tcon; | 1535 | struct cifsTconInfo *tcon; |
| 1533 | struct cifsFileInfo *smbfile = file->private_data; | 1536 | struct cifsFileInfo *smbfile = file->private_data; |
| 1534 | struct inode *inode = file->f_path.dentry->d_inode; | 1537 | struct inode *inode = file->f_path.dentry->d_inode; |
| 1538 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
| 1535 | 1539 | ||
| 1536 | xid = GetXid(); | 1540 | xid = GetXid(); |
| 1537 | 1541 | ||
| 1538 | cFYI(1, "Sync file - name: %s datasync: 0x%x", | 1542 | cFYI(1, "Sync file - name: %s datasync: 0x%x", |
| 1539 | file->f_path.dentry->d_name.name, datasync); | 1543 | file->f_path.dentry->d_name.name, datasync); |
| 1540 | 1544 | ||
| 1541 | rc = filemap_write_and_wait(inode->i_mapping); | 1545 | if (!CIFS_I(inode)->clientCanCacheRead) |
| 1542 | if (rc == 0) { | 1546 | cifs_invalidate_mapping(inode); |
| 1543 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
| 1544 | 1547 | ||
| 1545 | tcon = tlink_tcon(smbfile->tlink); | 1548 | tcon = tlink_tcon(smbfile->tlink); |
| 1546 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) | 1549 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) |
| 1547 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); | 1550 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); |
| 1548 | } | 1551 | |
| 1552 | FreeXid(xid); | ||
| 1553 | return rc; | ||
| 1554 | } | ||
| 1555 | |||
| 1556 | int cifs_fsync(struct file *file, int datasync) | ||
| 1557 | { | ||
| 1558 | int xid; | ||
| 1559 | int rc = 0; | ||
| 1560 | struct cifsTconInfo *tcon; | ||
| 1561 | struct cifsFileInfo *smbfile = file->private_data; | ||
| 1562 | struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | ||
| 1563 | |||
| 1564 | xid = GetXid(); | ||
| 1565 | |||
| 1566 | cFYI(1, "Sync file - name: %s datasync: 0x%x", | ||
| 1567 | file->f_path.dentry->d_name.name, datasync); | ||
| 1568 | |||
| 1569 | tcon = tlink_tcon(smbfile->tlink); | ||
| 1570 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) | ||
| 1571 | rc = CIFSSMBFlush(xid, tcon, smbfile->netfid); | ||
| 1549 | 1572 | ||
| 1550 | FreeXid(xid); | 1573 | FreeXid(xid); |
| 1551 | return rc; | 1574 | return rc; |
| @@ -1596,42 +1619,42 @@ int cifs_flush(struct file *file, fl_owner_t id) | |||
| 1596 | return rc; | 1619 | return rc; |
| 1597 | } | 1620 | } |
| 1598 | 1621 | ||
| 1599 | ssize_t cifs_user_read(struct file *file, char __user *read_data, | 1622 | static ssize_t |
| 1600 | size_t read_size, loff_t *poffset) | 1623 | cifs_iovec_read(struct file *file, const struct iovec *iov, |
| 1624 | unsigned long nr_segs, loff_t *poffset) | ||
| 1601 | { | 1625 | { |
| 1602 | int rc = -EACCES; | 1626 | int rc; |
| 1603 | unsigned int bytes_read = 0; | 1627 | int xid; |
| 1604 | unsigned int total_read = 0; | 1628 | unsigned int total_read, bytes_read = 0; |
| 1605 | unsigned int current_read_size; | 1629 | size_t len, cur_len; |
| 1630 | int iov_offset = 0; | ||
| 1606 | struct cifs_sb_info *cifs_sb; | 1631 | struct cifs_sb_info *cifs_sb; |
| 1607 | struct cifsTconInfo *pTcon; | 1632 | struct cifsTconInfo *pTcon; |
| 1608 | int xid; | ||
| 1609 | struct cifsFileInfo *open_file; | 1633 | struct cifsFileInfo *open_file; |
| 1610 | char *smb_read_data; | ||
| 1611 | char __user *current_offset; | ||
| 1612 | struct smb_com_read_rsp *pSMBr; | 1634 | struct smb_com_read_rsp *pSMBr; |
| 1635 | char *read_data; | ||
| 1636 | |||
| 1637 | if (!nr_segs) | ||
| 1638 | return 0; | ||
| 1639 | |||
| 1640 | len = iov_length(iov, nr_segs); | ||
| 1641 | if (!len) | ||
| 1642 | return 0; | ||
| 1613 | 1643 | ||
| 1614 | xid = GetXid(); | 1644 | xid = GetXid(); |
| 1615 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 1645 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
| 1616 | 1646 | ||
| 1617 | if (file->private_data == NULL) { | ||
| 1618 | rc = -EBADF; | ||
| 1619 | FreeXid(xid); | ||
| 1620 | return rc; | ||
| 1621 | } | ||
| 1622 | open_file = file->private_data; | 1647 | open_file = file->private_data; |
| 1623 | pTcon = tlink_tcon(open_file->tlink); | 1648 | pTcon = tlink_tcon(open_file->tlink); |
| 1624 | 1649 | ||
| 1625 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) | 1650 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) |
| 1626 | cFYI(1, "attempting read on write only file instance"); | 1651 | cFYI(1, "attempting read on write only file instance"); |
| 1627 | 1652 | ||
| 1628 | for (total_read = 0, current_offset = read_data; | 1653 | for (total_read = 0; total_read < len; total_read += bytes_read) { |
| 1629 | read_size > total_read; | 1654 | cur_len = min_t(const size_t, len - total_read, cifs_sb->rsize); |
| 1630 | total_read += bytes_read, current_offset += bytes_read) { | ||
| 1631 | current_read_size = min_t(const int, read_size - total_read, | ||
| 1632 | cifs_sb->rsize); | ||
| 1633 | rc = -EAGAIN; | 1655 | rc = -EAGAIN; |
| 1634 | smb_read_data = NULL; | 1656 | read_data = NULL; |
| 1657 | |||
| 1635 | while (rc == -EAGAIN) { | 1658 | while (rc == -EAGAIN) { |
| 1636 | int buf_type = CIFS_NO_BUFFER; | 1659 | int buf_type = CIFS_NO_BUFFER; |
| 1637 | if (open_file->invalidHandle) { | 1660 | if (open_file->invalidHandle) { |
| @@ -1639,27 +1662,25 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
| 1639 | if (rc != 0) | 1662 | if (rc != 0) |
| 1640 | break; | 1663 | break; |
| 1641 | } | 1664 | } |
| 1642 | rc = CIFSSMBRead(xid, pTcon, | 1665 | rc = CIFSSMBRead(xid, pTcon, open_file->netfid, |
| 1643 | open_file->netfid, | 1666 | cur_len, *poffset, &bytes_read, |
| 1644 | current_read_size, *poffset, | 1667 | &read_data, &buf_type); |
| 1645 | &bytes_read, &smb_read_data, | 1668 | pSMBr = (struct smb_com_read_rsp *)read_data; |
| 1646 | &buf_type); | 1669 | if (read_data) { |
| 1647 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | 1670 | char *data_offset = read_data + 4 + |
| 1648 | if (smb_read_data) { | 1671 | le16_to_cpu(pSMBr->DataOffset); |
| 1649 | if (copy_to_user(current_offset, | 1672 | if (memcpy_toiovecend(iov, data_offset, |
| 1650 | smb_read_data + | 1673 | iov_offset, bytes_read)) |
| 1651 | 4 /* RFC1001 length field */ + | ||
| 1652 | le16_to_cpu(pSMBr->DataOffset), | ||
| 1653 | bytes_read)) | ||
| 1654 | rc = -EFAULT; | 1674 | rc = -EFAULT; |
| 1655 | |||
| 1656 | if (buf_type == CIFS_SMALL_BUFFER) | 1675 | if (buf_type == CIFS_SMALL_BUFFER) |
| 1657 | cifs_small_buf_release(smb_read_data); | 1676 | cifs_small_buf_release(read_data); |
| 1658 | else if (buf_type == CIFS_LARGE_BUFFER) | 1677 | else if (buf_type == CIFS_LARGE_BUFFER) |
| 1659 | cifs_buf_release(smb_read_data); | 1678 | cifs_buf_release(read_data); |
| 1660 | smb_read_data = NULL; | 1679 | read_data = NULL; |
| 1680 | iov_offset += bytes_read; | ||
| 1661 | } | 1681 | } |
| 1662 | } | 1682 | } |
| 1683 | |||
| 1663 | if (rc || (bytes_read == 0)) { | 1684 | if (rc || (bytes_read == 0)) { |
| 1664 | if (total_read) { | 1685 | if (total_read) { |
| 1665 | break; | 1686 | break; |
| @@ -1672,13 +1693,57 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
| 1672 | *poffset += bytes_read; | 1693 | *poffset += bytes_read; |
| 1673 | } | 1694 | } |
| 1674 | } | 1695 | } |
| 1696 | |||
| 1675 | FreeXid(xid); | 1697 | FreeXid(xid); |
| 1676 | return total_read; | 1698 | return total_read; |
| 1677 | } | 1699 | } |
| 1678 | 1700 | ||
| 1701 | ssize_t cifs_user_read(struct file *file, char __user *read_data, | ||
| 1702 | size_t read_size, loff_t *poffset) | ||
| 1703 | { | ||
| 1704 | struct iovec iov; | ||
| 1705 | iov.iov_base = read_data; | ||
| 1706 | iov.iov_len = read_size; | ||
| 1707 | |||
| 1708 | return cifs_iovec_read(file, &iov, 1, poffset); | ||
| 1709 | } | ||
| 1710 | |||
| 1711 | static ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, | ||
| 1712 | unsigned long nr_segs, loff_t pos) | ||
| 1713 | { | ||
| 1714 | ssize_t read; | ||
| 1715 | |||
| 1716 | read = cifs_iovec_read(iocb->ki_filp, iov, nr_segs, &pos); | ||
| 1717 | if (read > 0) | ||
| 1718 | iocb->ki_pos = pos; | ||
| 1719 | |||
| 1720 | return read; | ||
| 1721 | } | ||
| 1722 | |||
| 1723 | ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, | ||
| 1724 | unsigned long nr_segs, loff_t pos) | ||
| 1725 | { | ||
| 1726 | struct inode *inode; | ||
| 1727 | |||
| 1728 | inode = iocb->ki_filp->f_path.dentry->d_inode; | ||
| 1729 | |||
| 1730 | if (CIFS_I(inode)->clientCanCacheRead) | ||
| 1731 | return generic_file_aio_read(iocb, iov, nr_segs, pos); | ||
| 1732 | |||
| 1733 | /* | ||
| 1734 | * In strict cache mode we need to read from the server all the time | ||
| 1735 | * if we don't have level II oplock because the server can delay mtime | ||
| 1736 | * change - so we can't make a decision about inode invalidating. | ||
| 1737 | * And we can also fail with pagereading if there are mandatory locks | ||
| 1738 | * on pages affected by this read but not on the region from pos to | ||
| 1739 | * pos+len-1. | ||
| 1740 | */ | ||
| 1741 | |||
| 1742 | return cifs_user_readv(iocb, iov, nr_segs, pos); | ||
| 1743 | } | ||
| 1679 | 1744 | ||
| 1680 | static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | 1745 | static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, |
| 1681 | loff_t *poffset) | 1746 | loff_t *poffset) |
| 1682 | { | 1747 | { |
| 1683 | int rc = -EACCES; | 1748 | int rc = -EACCES; |
| 1684 | unsigned int bytes_read = 0; | 1749 | unsigned int bytes_read = 0; |
| @@ -1746,6 +1811,21 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
| 1746 | return total_read; | 1811 | return total_read; |
| 1747 | } | 1812 | } |
| 1748 | 1813 | ||
| 1814 | int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 1815 | { | ||
| 1816 | int rc, xid; | ||
| 1817 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 1818 | |||
| 1819 | xid = GetXid(); | ||
| 1820 | |||
| 1821 | if (!CIFS_I(inode)->clientCanCacheRead) | ||
| 1822 | cifs_invalidate_mapping(inode); | ||
| 1823 | |||
| 1824 | rc = generic_file_mmap(file, vma); | ||
| 1825 | FreeXid(xid); | ||
| 1826 | return rc; | ||
| 1827 | } | ||
| 1828 | |||
| 1749 | int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) | 1829 | int cifs_file_mmap(struct file *file, struct vm_area_struct *vma) |
| 1750 | { | 1830 | { |
| 1751 | int rc, xid; | 1831 | int rc, xid; |
| @@ -2192,7 +2272,8 @@ void cifs_oplock_break(struct work_struct *work) | |||
| 2192 | */ | 2272 | */ |
| 2193 | if (!cfile->oplock_break_cancelled) { | 2273 | if (!cfile->oplock_break_cancelled) { |
| 2194 | rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0, | 2274 | rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0, |
| 2195 | 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false); | 2275 | 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false, |
| 2276 | cinode->clientCanCacheRead ? 1 : 0); | ||
| 2196 | cFYI(1, "Oplock release rc = %d", rc); | 2277 | cFYI(1, "Oplock release rc = %d", rc); |
| 2197 | } | 2278 | } |
| 2198 | 2279 | ||
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 6c9ee8014ff0..8852470b4fbb 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -44,13 +44,17 @@ static void cifs_set_ops(struct inode *inode) | |||
| 44 | inode->i_fop = &cifs_file_direct_nobrl_ops; | 44 | inode->i_fop = &cifs_file_direct_nobrl_ops; |
| 45 | else | 45 | else |
| 46 | inode->i_fop = &cifs_file_direct_ops; | 46 | inode->i_fop = &cifs_file_direct_ops; |
| 47 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) { | ||
| 48 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 49 | inode->i_fop = &cifs_file_strict_nobrl_ops; | ||
| 50 | else | ||
| 51 | inode->i_fop = &cifs_file_strict_ops; | ||
| 47 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 52 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) |
| 48 | inode->i_fop = &cifs_file_nobrl_ops; | 53 | inode->i_fop = &cifs_file_nobrl_ops; |
| 49 | else { /* not direct, send byte range locks */ | 54 | else { /* not direct, send byte range locks */ |
| 50 | inode->i_fop = &cifs_file_ops; | 55 | inode->i_fop = &cifs_file_ops; |
| 51 | } | 56 | } |
| 52 | 57 | ||
| 53 | |||
| 54 | /* check if server can support readpages */ | 58 | /* check if server can support readpages */ |
| 55 | if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf < | 59 | if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf < |
| 56 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) | 60 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) |
| @@ -1679,7 +1683,7 @@ cifs_inode_needs_reval(struct inode *inode) | |||
| 1679 | /* | 1683 | /* |
| 1680 | * Zap the cache. Called when invalid_mapping flag is set. | 1684 | * Zap the cache. Called when invalid_mapping flag is set. |
| 1681 | */ | 1685 | */ |
| 1682 | static void | 1686 | void |
| 1683 | cifs_invalidate_mapping(struct inode *inode) | 1687 | cifs_invalidate_mapping(struct inode *inode) |
| 1684 | { | 1688 | { |
| 1685 | int rc; | 1689 | int rc; |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 43f10281bc19..a09e077ba925 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
| @@ -571,7 +571,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
| 571 | pCifsInode = CIFS_I(netfile->dentry->d_inode); | 571 | pCifsInode = CIFS_I(netfile->dentry->d_inode); |
| 572 | 572 | ||
| 573 | cifs_set_oplock_level(pCifsInode, | 573 | cifs_set_oplock_level(pCifsInode, |
| 574 | pSMB->OplockLevel); | 574 | pSMB->OplockLevel ? OPLOCK_READ : 0); |
| 575 | /* | 575 | /* |
| 576 | * cifs_oplock_break_put() can't be called | 576 | * cifs_oplock_break_put() can't be called |
| 577 | * from here. Get reference after queueing | 577 | * from here. Get reference after queueing |
| @@ -637,77 +637,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) | |||
| 637 | return; | 637 | return; |
| 638 | } | 638 | } |
| 639 | 639 | ||
| 640 | /* Convert 16 bit Unicode pathname to wire format from string in current code | ||
| 641 | page. Conversion may involve remapping up the seven characters that are | ||
| 642 | only legal in POSIX-like OS (if they are present in the string). Path | ||
| 643 | names are little endian 16 bit Unicode on the wire */ | ||
| 644 | int | ||
| 645 | cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | ||
| 646 | const struct nls_table *cp, int mapChars) | ||
| 647 | { | ||
| 648 | int i, j, charlen; | ||
| 649 | int len_remaining = maxlen; | ||
| 650 | char src_char; | ||
| 651 | __u16 temp; | ||
| 652 | |||
| 653 | if (!mapChars) | ||
| 654 | return cifs_strtoUCS(target, source, PATH_MAX, cp); | ||
| 655 | |||
| 656 | for (i = 0, j = 0; i < maxlen; j++) { | ||
| 657 | src_char = source[i]; | ||
| 658 | switch (src_char) { | ||
| 659 | case 0: | ||
| 660 | target[j] = 0; | ||
| 661 | goto ctoUCS_out; | ||
| 662 | case ':': | ||
| 663 | target[j] = cpu_to_le16(UNI_COLON); | ||
| 664 | break; | ||
| 665 | case '*': | ||
| 666 | target[j] = cpu_to_le16(UNI_ASTERIK); | ||
| 667 | break; | ||
| 668 | case '?': | ||
| 669 | target[j] = cpu_to_le16(UNI_QUESTION); | ||
| 670 | break; | ||
| 671 | case '<': | ||
| 672 | target[j] = cpu_to_le16(UNI_LESSTHAN); | ||
| 673 | break; | ||
| 674 | case '>': | ||
| 675 | target[j] = cpu_to_le16(UNI_GRTRTHAN); | ||
| 676 | break; | ||
| 677 | case '|': | ||
| 678 | target[j] = cpu_to_le16(UNI_PIPE); | ||
| 679 | break; | ||
| 680 | /* BB We can not handle remapping slash until | ||
| 681 | all the calls to build_path_from_dentry | ||
| 682 | are modified, as they use slash as separator BB */ | ||
| 683 | /* case '\\': | ||
| 684 | target[j] = cpu_to_le16(UNI_SLASH); | ||
| 685 | break;*/ | ||
| 686 | default: | ||
| 687 | charlen = cp->char2uni(source+i, | ||
| 688 | len_remaining, &temp); | ||
| 689 | /* if no match, use question mark, which | ||
| 690 | at least in some cases servers as wild card */ | ||
| 691 | if (charlen < 1) { | ||
| 692 | target[j] = cpu_to_le16(0x003f); | ||
| 693 | charlen = 1; | ||
| 694 | } else | ||
| 695 | target[j] = cpu_to_le16(temp); | ||
| 696 | len_remaining -= charlen; | ||
| 697 | /* character may take more than one byte in the | ||
| 698 | the source string, but will take exactly two | ||
| 699 | bytes in the target string */ | ||
| 700 | i += charlen; | ||
| 701 | continue; | ||
| 702 | } | ||
| 703 | i++; /* move to next char in source string */ | ||
| 704 | len_remaining--; | ||
| 705 | } | ||
| 706 | |||
| 707 | ctoUCS_out: | ||
| 708 | return i; | ||
| 709 | } | ||
| 710 | |||
| 711 | void | 640 | void |
| 712 | cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) | 641 | cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) |
| 713 | { | 642 | { |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 6783ce6cdc89..8d9189f64477 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
| @@ -916,14 +916,14 @@ unsigned int | |||
| 916 | smbCalcSize(struct smb_hdr *ptr) | 916 | smbCalcSize(struct smb_hdr *ptr) |
| 917 | { | 917 | { |
| 918 | return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + | 918 | return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + |
| 919 | 2 /* size of the bcc field */ + BCC(ptr)); | 919 | 2 /* size of the bcc field */ + get_bcc(ptr)); |
| 920 | } | 920 | } |
| 921 | 921 | ||
| 922 | unsigned int | 922 | unsigned int |
| 923 | smbCalcSize_LE(struct smb_hdr *ptr) | 923 | smbCalcSize_LE(struct smb_hdr *ptr) |
| 924 | { | 924 | { |
| 925 | return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + | 925 | return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + |
| 926 | 2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr))); | 926 | 2 /* size of the bcc field */ + get_bcc_le(ptr)); |
| 927 | } | 927 | } |
| 928 | 928 | ||
| 929 | /* The following are taken from fs/ntfs/util.c */ | 929 | /* The following are taken from fs/ntfs/util.c */ |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index eb746486e49e..1adc9625a344 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
| @@ -277,7 +277,7 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | |||
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | static void | 279 | static void |
| 280 | decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, | 280 | decode_unicode_ssetup(char **pbcc_area, __u16 bleft, struct cifsSesInfo *ses, |
| 281 | const struct nls_table *nls_cp) | 281 | const struct nls_table *nls_cp) |
| 282 | { | 282 | { |
| 283 | int len; | 283 | int len; |
| @@ -323,7 +323,7 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, | |||
| 323 | return; | 323 | return; |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | static int decode_ascii_ssetup(char **pbcc_area, int bleft, | 326 | static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft, |
| 327 | struct cifsSesInfo *ses, | 327 | struct cifsSesInfo *ses, |
| 328 | const struct nls_table *nls_cp) | 328 | const struct nls_table *nls_cp) |
| 329 | { | 329 | { |
| @@ -575,12 +575,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 575 | char *str_area; | 575 | char *str_area; |
| 576 | SESSION_SETUP_ANDX *pSMB; | 576 | SESSION_SETUP_ANDX *pSMB; |
| 577 | __u32 capabilities; | 577 | __u32 capabilities; |
| 578 | int count; | 578 | __u16 count; |
| 579 | int resp_buf_type; | 579 | int resp_buf_type; |
| 580 | struct kvec iov[3]; | 580 | struct kvec iov[3]; |
| 581 | enum securityEnum type; | 581 | enum securityEnum type; |
| 582 | __u16 action; | 582 | __u16 action, bytes_remaining; |
| 583 | int bytes_remaining; | ||
| 584 | struct key *spnego_key = NULL; | 583 | struct key *spnego_key = NULL; |
| 585 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | 584 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ |
| 586 | u16 blob_len; | 585 | u16 blob_len; |
| @@ -876,10 +875,10 @@ ssetup_ntlmssp_authenticate: | |||
| 876 | count = iov[1].iov_len + iov[2].iov_len; | 875 | count = iov[1].iov_len + iov[2].iov_len; |
| 877 | smb_buf->smb_buf_length += count; | 876 | smb_buf->smb_buf_length += count; |
| 878 | 877 | ||
| 879 | BCC_LE(smb_buf) = cpu_to_le16(count); | 878 | put_bcc_le(count, smb_buf); |
| 880 | 879 | ||
| 881 | rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, | 880 | rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, |
| 882 | CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); | 881 | CIFS_LOG_ERROR); |
| 883 | /* SMB request buf freed in SendReceive2 */ | 882 | /* SMB request buf freed in SendReceive2 */ |
| 884 | 883 | ||
| 885 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | 884 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; |
| @@ -910,7 +909,7 @@ ssetup_ntlmssp_authenticate: | |||
| 910 | cFYI(1, "UID = %d ", ses->Suid); | 909 | cFYI(1, "UID = %d ", ses->Suid); |
| 911 | /* response can have either 3 or 4 word count - Samba sends 3 */ | 910 | /* response can have either 3 or 4 word count - Samba sends 3 */ |
| 912 | /* and lanman response is 3 */ | 911 | /* and lanman response is 3 */ |
| 913 | bytes_remaining = BCC(smb_buf); | 912 | bytes_remaining = get_bcc(smb_buf); |
| 914 | bcc_ptr = pByteArea(smb_buf); | 913 | bcc_ptr = pByteArea(smb_buf); |
| 915 | 914 | ||
| 916 | if (smb_buf->WordCount == 4) { | 915 | if (smb_buf->WordCount == 4) { |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 59ca81b16919..c1ccca1a933f 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -36,7 +36,13 @@ | |||
| 36 | 36 | ||
| 37 | extern mempool_t *cifs_mid_poolp; | 37 | extern mempool_t *cifs_mid_poolp; |
| 38 | 38 | ||
| 39 | static struct mid_q_entry * | 39 | static void |
| 40 | wake_up_task(struct mid_q_entry *mid) | ||
| 41 | { | ||
| 42 | wake_up_process(mid->callback_data); | ||
| 43 | } | ||
| 44 | |||
| 45 | struct mid_q_entry * | ||
| 40 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) | 46 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) |
| 41 | { | 47 | { |
| 42 | struct mid_q_entry *temp; | 48 | struct mid_q_entry *temp; |
| @@ -58,28 +64,28 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) | |||
| 58 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ | 64 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ |
| 59 | /* when mid allocated can be before when sent */ | 65 | /* when mid allocated can be before when sent */ |
| 60 | temp->when_alloc = jiffies; | 66 | temp->when_alloc = jiffies; |
| 61 | temp->tsk = current; | 67 | |
| 68 | /* | ||
| 69 | * The default is for the mid to be synchronous, so the | ||
| 70 | * default callback just wakes up the current task. | ||
| 71 | */ | ||
| 72 | temp->callback = wake_up_task; | ||
| 73 | temp->callback_data = current; | ||
| 62 | } | 74 | } |
| 63 | 75 | ||
| 64 | spin_lock(&GlobalMid_Lock); | ||
| 65 | list_add_tail(&temp->qhead, &server->pending_mid_q); | ||
| 66 | atomic_inc(&midCount); | 76 | atomic_inc(&midCount); |
| 67 | temp->midState = MID_REQUEST_ALLOCATED; | 77 | temp->midState = MID_REQUEST_ALLOCATED; |
| 68 | spin_unlock(&GlobalMid_Lock); | ||
| 69 | return temp; | 78 | return temp; |
| 70 | } | 79 | } |
| 71 | 80 | ||
| 72 | static void | 81 | void |
| 73 | DeleteMidQEntry(struct mid_q_entry *midEntry) | 82 | DeleteMidQEntry(struct mid_q_entry *midEntry) |
| 74 | { | 83 | { |
| 75 | #ifdef CONFIG_CIFS_STATS2 | 84 | #ifdef CONFIG_CIFS_STATS2 |
| 76 | unsigned long now; | 85 | unsigned long now; |
| 77 | #endif | 86 | #endif |
| 78 | spin_lock(&GlobalMid_Lock); | ||
| 79 | midEntry->midState = MID_FREE; | 87 | midEntry->midState = MID_FREE; |
| 80 | list_del(&midEntry->qhead); | ||
| 81 | atomic_dec(&midCount); | 88 | atomic_dec(&midCount); |
| 82 | spin_unlock(&GlobalMid_Lock); | ||
| 83 | if (midEntry->largeBuf) | 89 | if (midEntry->largeBuf) |
| 84 | cifs_buf_release(midEntry->resp_buf); | 90 | cifs_buf_release(midEntry->resp_buf); |
| 85 | else | 91 | else |
| @@ -103,6 +109,16 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) | |||
| 103 | mempool_free(midEntry, cifs_mid_poolp); | 109 | mempool_free(midEntry, cifs_mid_poolp); |
| 104 | } | 110 | } |
| 105 | 111 | ||
| 112 | static void | ||
| 113 | delete_mid(struct mid_q_entry *mid) | ||
| 114 | { | ||
| 115 | spin_lock(&GlobalMid_Lock); | ||
| 116 | list_del(&mid->qhead); | ||
| 117 | spin_unlock(&GlobalMid_Lock); | ||
| 118 | |||
| 119 | DeleteMidQEntry(mid); | ||
| 120 | } | ||
| 121 | |||
| 106 | static int | 122 | static int |
| 107 | smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | 123 | smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) |
| 108 | { | 124 | { |
| @@ -244,31 +260,31 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, | |||
| 244 | return smb_sendv(server, &iov, 1); | 260 | return smb_sendv(server, &iov, 1); |
| 245 | } | 261 | } |
| 246 | 262 | ||
| 247 | static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | 263 | static int wait_for_free_request(struct TCP_Server_Info *server, |
| 264 | const int long_op) | ||
| 248 | { | 265 | { |
| 249 | if (long_op == CIFS_ASYNC_OP) { | 266 | if (long_op == CIFS_ASYNC_OP) { |
| 250 | /* oplock breaks must not be held up */ | 267 | /* oplock breaks must not be held up */ |
| 251 | atomic_inc(&ses->server->inFlight); | 268 | atomic_inc(&server->inFlight); |
| 252 | return 0; | 269 | return 0; |
| 253 | } | 270 | } |
| 254 | 271 | ||
| 255 | spin_lock(&GlobalMid_Lock); | 272 | spin_lock(&GlobalMid_Lock); |
| 256 | while (1) { | 273 | while (1) { |
| 257 | if (atomic_read(&ses->server->inFlight) >= | 274 | if (atomic_read(&server->inFlight) >= cifs_max_pending) { |
| 258 | cifs_max_pending){ | ||
| 259 | spin_unlock(&GlobalMid_Lock); | 275 | spin_unlock(&GlobalMid_Lock); |
| 260 | #ifdef CONFIG_CIFS_STATS2 | 276 | #ifdef CONFIG_CIFS_STATS2 |
| 261 | atomic_inc(&ses->server->num_waiters); | 277 | atomic_inc(&server->num_waiters); |
| 262 | #endif | 278 | #endif |
| 263 | wait_event(ses->server->request_q, | 279 | wait_event(server->request_q, |
| 264 | atomic_read(&ses->server->inFlight) | 280 | atomic_read(&server->inFlight) |
| 265 | < cifs_max_pending); | 281 | < cifs_max_pending); |
| 266 | #ifdef CONFIG_CIFS_STATS2 | 282 | #ifdef CONFIG_CIFS_STATS2 |
| 267 | atomic_dec(&ses->server->num_waiters); | 283 | atomic_dec(&server->num_waiters); |
| 268 | #endif | 284 | #endif |
| 269 | spin_lock(&GlobalMid_Lock); | 285 | spin_lock(&GlobalMid_Lock); |
| 270 | } else { | 286 | } else { |
| 271 | if (ses->server->tcpStatus == CifsExiting) { | 287 | if (server->tcpStatus == CifsExiting) { |
| 272 | spin_unlock(&GlobalMid_Lock); | 288 | spin_unlock(&GlobalMid_Lock); |
| 273 | return -ENOENT; | 289 | return -ENOENT; |
| 274 | } | 290 | } |
| @@ -278,7 +294,7 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | |||
| 278 | 294 | ||
| 279 | /* update # of requests on the wire to server */ | 295 | /* update # of requests on the wire to server */ |
| 280 | if (long_op != CIFS_BLOCKING_OP) | 296 | if (long_op != CIFS_BLOCKING_OP) |
| 281 | atomic_inc(&ses->server->inFlight); | 297 | atomic_inc(&server->inFlight); |
| 282 | spin_unlock(&GlobalMid_Lock); | 298 | spin_unlock(&GlobalMid_Lock); |
| 283 | break; | 299 | break; |
| 284 | } | 300 | } |
| @@ -308,53 +324,81 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, | |||
| 308 | *ppmidQ = AllocMidQEntry(in_buf, ses->server); | 324 | *ppmidQ = AllocMidQEntry(in_buf, ses->server); |
| 309 | if (*ppmidQ == NULL) | 325 | if (*ppmidQ == NULL) |
| 310 | return -ENOMEM; | 326 | return -ENOMEM; |
| 327 | spin_lock(&GlobalMid_Lock); | ||
| 328 | list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q); | ||
| 329 | spin_unlock(&GlobalMid_Lock); | ||
| 311 | return 0; | 330 | return 0; |
| 312 | } | 331 | } |
| 313 | 332 | ||
| 314 | static int wait_for_response(struct cifsSesInfo *ses, | 333 | static int |
| 315 | struct mid_q_entry *midQ, | 334 | wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ) |
| 316 | unsigned long timeout, | ||
| 317 | unsigned long time_to_wait) | ||
| 318 | { | 335 | { |
| 319 | unsigned long curr_timeout; | 336 | int error; |
| 320 | 337 | ||
| 321 | for (;;) { | 338 | error = wait_event_killable(server->response_q, |
| 322 | curr_timeout = timeout + jiffies; | 339 | midQ->midState != MID_REQUEST_SUBMITTED); |
| 323 | wait_event_timeout(ses->server->response_q, | 340 | if (error < 0) |
| 324 | midQ->midState != MID_REQUEST_SUBMITTED, timeout); | 341 | return -ERESTARTSYS; |
| 325 | 342 | ||
| 326 | if (time_after(jiffies, curr_timeout) && | 343 | return 0; |
| 327 | (midQ->midState == MID_REQUEST_SUBMITTED) && | 344 | } |
| 328 | ((ses->server->tcpStatus == CifsGood) || | ||
| 329 | (ses->server->tcpStatus == CifsNew))) { | ||
| 330 | 345 | ||
| 331 | unsigned long lrt; | ||
| 332 | 346 | ||
| 333 | /* We timed out. Is the server still | 347 | /* |
| 334 | sending replies ? */ | 348 | * Send a SMB request and set the callback function in the mid to handle |
| 335 | spin_lock(&GlobalMid_Lock); | 349 | * the result. Caller is responsible for dealing with timeouts. |
| 336 | lrt = ses->server->lstrp; | 350 | */ |
| 337 | spin_unlock(&GlobalMid_Lock); | 351 | int |
| 352 | cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf, | ||
| 353 | mid_callback_t *callback, void *cbdata) | ||
| 354 | { | ||
| 355 | int rc; | ||
| 356 | struct mid_q_entry *mid; | ||
| 338 | 357 | ||
| 339 | /* Calculate time_to_wait past last receive time. | 358 | rc = wait_for_free_request(server, CIFS_ASYNC_OP); |
| 340 | Although we prefer not to time out if the | 359 | if (rc) |
| 341 | server is still responding - we will time | 360 | return rc; |
| 342 | out if the server takes more than 15 (or 45 | 361 | |
| 343 | or 180) seconds to respond to this request | 362 | mutex_lock(&server->srv_mutex); |
| 344 | and has not responded to any request from | 363 | mid = AllocMidQEntry(in_buf, server); |
| 345 | other threads on the client within 10 seconds */ | 364 | if (mid == NULL) { |
| 346 | lrt += time_to_wait; | 365 | mutex_unlock(&server->srv_mutex); |
| 347 | if (time_after(jiffies, lrt)) { | 366 | return -ENOMEM; |
| 348 | /* No replies for time_to_wait. */ | ||
| 349 | cERROR(1, "server not responding"); | ||
| 350 | return -1; | ||
| 351 | } | ||
| 352 | } else { | ||
| 353 | return 0; | ||
| 354 | } | ||
| 355 | } | 367 | } |
| 356 | } | ||
| 357 | 368 | ||
| 369 | /* put it on the pending_mid_q */ | ||
| 370 | spin_lock(&GlobalMid_Lock); | ||
| 371 | list_add_tail(&mid->qhead, &server->pending_mid_q); | ||
| 372 | spin_unlock(&GlobalMid_Lock); | ||
| 373 | |||
| 374 | rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); | ||
| 375 | if (rc) { | ||
| 376 | mutex_unlock(&server->srv_mutex); | ||
| 377 | goto out_err; | ||
| 378 | } | ||
| 379 | |||
| 380 | mid->callback = callback; | ||
| 381 | mid->callback_data = cbdata; | ||
| 382 | mid->midState = MID_REQUEST_SUBMITTED; | ||
| 383 | #ifdef CONFIG_CIFS_STATS2 | ||
| 384 | atomic_inc(&server->inSend); | ||
| 385 | #endif | ||
| 386 | rc = smb_send(server, in_buf, in_buf->smb_buf_length); | ||
| 387 | #ifdef CONFIG_CIFS_STATS2 | ||
| 388 | atomic_dec(&server->inSend); | ||
| 389 | mid->when_sent = jiffies; | ||
| 390 | #endif | ||
| 391 | mutex_unlock(&server->srv_mutex); | ||
| 392 | if (rc) | ||
| 393 | goto out_err; | ||
| 394 | |||
| 395 | return rc; | ||
| 396 | out_err: | ||
| 397 | delete_mid(mid); | ||
| 398 | atomic_dec(&server->inFlight); | ||
| 399 | wake_up(&server->request_q); | ||
| 400 | return rc; | ||
| 401 | } | ||
| 358 | 402 | ||
| 359 | /* | 403 | /* |
| 360 | * | 404 | * |
| @@ -382,6 +426,81 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 382 | return rc; | 426 | return rc; |
| 383 | } | 427 | } |
| 384 | 428 | ||
| 429 | static int | ||
| 430 | sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) | ||
| 431 | { | ||
| 432 | int rc = 0; | ||
| 433 | |||
| 434 | cFYI(1, "%s: cmd=%d mid=%d state=%d", __func__, mid->command, | ||
| 435 | mid->mid, mid->midState); | ||
| 436 | |||
| 437 | spin_lock(&GlobalMid_Lock); | ||
| 438 | /* ensure that it's no longer on the pending_mid_q */ | ||
| 439 | list_del_init(&mid->qhead); | ||
| 440 | |||
| 441 | switch (mid->midState) { | ||
| 442 | case MID_RESPONSE_RECEIVED: | ||
| 443 | spin_unlock(&GlobalMid_Lock); | ||
| 444 | return rc; | ||
| 445 | case MID_REQUEST_SUBMITTED: | ||
| 446 | /* socket is going down, reject all calls */ | ||
| 447 | if (server->tcpStatus == CifsExiting) { | ||
| 448 | cERROR(1, "%s: canceling mid=%d cmd=0x%x state=%d", | ||
| 449 | __func__, mid->mid, mid->command, mid->midState); | ||
| 450 | rc = -EHOSTDOWN; | ||
| 451 | break; | ||
| 452 | } | ||
| 453 | case MID_RETRY_NEEDED: | ||
| 454 | rc = -EAGAIN; | ||
| 455 | break; | ||
| 456 | default: | ||
| 457 | cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__, | ||
| 458 | mid->mid, mid->midState); | ||
| 459 | rc = -EIO; | ||
| 460 | } | ||
| 461 | spin_unlock(&GlobalMid_Lock); | ||
| 462 | |||
| 463 | DeleteMidQEntry(mid); | ||
| 464 | return rc; | ||
| 465 | } | ||
| 466 | |||
| 467 | /* | ||
| 468 | * An NT cancel request header looks just like the original request except: | ||
| 469 | * | ||
| 470 | * The Command is SMB_COM_NT_CANCEL | ||
| 471 | * The WordCount is zeroed out | ||
| 472 | * The ByteCount is zeroed out | ||
| 473 | * | ||
| 474 | * This function mangles an existing request buffer into a | ||
| 475 | * SMB_COM_NT_CANCEL request and then sends it. | ||
| 476 | */ | ||
| 477 | static int | ||
| 478 | send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, | ||
| 479 | struct mid_q_entry *mid) | ||
| 480 | { | ||
| 481 | int rc = 0; | ||
| 482 | |||
| 483 | /* -4 for RFC1001 length and +2 for BCC field */ | ||
| 484 | in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4 + 2; | ||
| 485 | in_buf->Command = SMB_COM_NT_CANCEL; | ||
| 486 | in_buf->WordCount = 0; | ||
| 487 | put_bcc_le(0, in_buf); | ||
| 488 | |||
| 489 | mutex_lock(&server->srv_mutex); | ||
| 490 | rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); | ||
| 491 | if (rc) { | ||
| 492 | mutex_unlock(&server->srv_mutex); | ||
| 493 | return rc; | ||
| 494 | } | ||
| 495 | rc = smb_send(server, in_buf, in_buf->smb_buf_length); | ||
| 496 | mutex_unlock(&server->srv_mutex); | ||
| 497 | |||
| 498 | cFYI(1, "issued NT_CANCEL for mid %u, rc = %d", | ||
| 499 | in_buf->Mid, rc); | ||
| 500 | |||
| 501 | return rc; | ||
| 502 | } | ||
| 503 | |||
| 385 | int | 504 | int |
| 386 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | 505 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
| 387 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, | 506 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, |
| @@ -390,7 +509,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 390 | int rc = 0; | 509 | int rc = 0; |
| 391 | int long_op; | 510 | int long_op; |
| 392 | unsigned int receive_len; | 511 | unsigned int receive_len; |
| 393 | unsigned long timeout; | ||
| 394 | struct mid_q_entry *midQ; | 512 | struct mid_q_entry *midQ; |
| 395 | struct smb_hdr *in_buf = iov[0].iov_base; | 513 | struct smb_hdr *in_buf = iov[0].iov_base; |
| 396 | 514 | ||
| @@ -413,7 +531,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 413 | to the same server. We may make this configurable later or | 531 | to the same server. We may make this configurable later or |
| 414 | use ses->maxReq */ | 532 | use ses->maxReq */ |
| 415 | 533 | ||
| 416 | rc = wait_for_free_request(ses, long_op); | 534 | rc = wait_for_free_request(ses->server, long_op); |
| 417 | if (rc) { | 535 | if (rc) { |
| 418 | cifs_small_buf_release(in_buf); | 536 | cifs_small_buf_release(in_buf); |
| 419 | return rc; | 537 | return rc; |
| @@ -457,65 +575,20 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 457 | if (rc < 0) | 575 | if (rc < 0) |
| 458 | goto out; | 576 | goto out; |
| 459 | 577 | ||
| 460 | if (long_op == CIFS_STD_OP) | 578 | if (long_op == CIFS_ASYNC_OP) |
| 461 | timeout = 15 * HZ; | ||
| 462 | else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */ | ||
| 463 | timeout = 180 * HZ; | ||
| 464 | else if (long_op == CIFS_LONG_OP) | ||
| 465 | timeout = 45 * HZ; /* should be greater than | ||
| 466 | servers oplock break timeout (about 43 seconds) */ | ||
| 467 | else if (long_op == CIFS_ASYNC_OP) | ||
| 468 | goto out; | 579 | goto out; |
| 469 | else if (long_op == CIFS_BLOCKING_OP) | ||
| 470 | timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */ | ||
| 471 | else { | ||
| 472 | cERROR(1, "unknown timeout flag %d", long_op); | ||
| 473 | rc = -EIO; | ||
| 474 | goto out; | ||
| 475 | } | ||
| 476 | |||
| 477 | /* wait for 15 seconds or until woken up due to response arriving or | ||
| 478 | due to last connection to this server being unmounted */ | ||
| 479 | if (signal_pending(current)) { | ||
| 480 | /* if signal pending do not hold up user for full smb timeout | ||
| 481 | but we still give response a chance to complete */ | ||
| 482 | timeout = 2 * HZ; | ||
| 483 | } | ||
| 484 | |||
| 485 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
| 486 | wait_for_response(ses, midQ, timeout, 10 * HZ); | ||
| 487 | |||
| 488 | spin_lock(&GlobalMid_Lock); | ||
| 489 | 580 | ||
| 490 | if (midQ->resp_buf == NULL) { | 581 | rc = wait_for_response(ses->server, midQ); |
| 491 | cERROR(1, "No response to cmd %d mid %d", | 582 | if (rc != 0) |
| 492 | midQ->command, midQ->mid); | 583 | goto out; |
| 493 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | ||
| 494 | if (ses->server->tcpStatus == CifsExiting) | ||
| 495 | rc = -EHOSTDOWN; | ||
| 496 | else { | ||
| 497 | ses->server->tcpStatus = CifsNeedReconnect; | ||
| 498 | midQ->midState = MID_RETRY_NEEDED; | ||
| 499 | } | ||
| 500 | } | ||
| 501 | 584 | ||
| 502 | if (rc != -EHOSTDOWN) { | 585 | rc = sync_mid_result(midQ, ses->server); |
| 503 | if (midQ->midState == MID_RETRY_NEEDED) { | 586 | if (rc != 0) { |
| 504 | rc = -EAGAIN; | ||
| 505 | cFYI(1, "marking request for retry"); | ||
| 506 | } else { | ||
| 507 | rc = -EIO; | ||
| 508 | } | ||
| 509 | } | ||
| 510 | spin_unlock(&GlobalMid_Lock); | ||
| 511 | DeleteMidQEntry(midQ); | ||
| 512 | /* Update # of requests on wire to server */ | ||
| 513 | atomic_dec(&ses->server->inFlight); | 587 | atomic_dec(&ses->server->inFlight); |
| 514 | wake_up(&ses->server->request_q); | 588 | wake_up(&ses->server->request_q); |
| 515 | return rc; | 589 | return rc; |
| 516 | } | 590 | } |
| 517 | 591 | ||
| 518 | spin_unlock(&GlobalMid_Lock); | ||
| 519 | receive_len = midQ->resp_buf->smb_buf_length; | 592 | receive_len = midQ->resp_buf->smb_buf_length; |
| 520 | 593 | ||
| 521 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 594 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
| @@ -559,19 +632,18 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 559 | if (receive_len >= sizeof(struct smb_hdr) - 4 | 632 | if (receive_len >= sizeof(struct smb_hdr) - 4 |
| 560 | /* do not count RFC1001 header */ + | 633 | /* do not count RFC1001 header */ + |
| 561 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) | 634 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) |
| 562 | BCC(midQ->resp_buf) = | 635 | put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); |
| 563 | le16_to_cpu(BCC_LE(midQ->resp_buf)); | ||
| 564 | if ((flags & CIFS_NO_RESP) == 0) | 636 | if ((flags & CIFS_NO_RESP) == 0) |
| 565 | midQ->resp_buf = NULL; /* mark it so buf will | 637 | midQ->resp_buf = NULL; /* mark it so buf will |
| 566 | not be freed by | 638 | not be freed by |
| 567 | DeleteMidQEntry */ | 639 | delete_mid */ |
| 568 | } else { | 640 | } else { |
| 569 | rc = -EIO; | 641 | rc = -EIO; |
| 570 | cFYI(1, "Bad MID state?"); | 642 | cFYI(1, "Bad MID state?"); |
| 571 | } | 643 | } |
| 572 | 644 | ||
| 573 | out: | 645 | out: |
| 574 | DeleteMidQEntry(midQ); | 646 | delete_mid(midQ); |
| 575 | atomic_dec(&ses->server->inFlight); | 647 | atomic_dec(&ses->server->inFlight); |
| 576 | wake_up(&ses->server->request_q); | 648 | wake_up(&ses->server->request_q); |
| 577 | 649 | ||
| @@ -585,7 +657,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 585 | { | 657 | { |
| 586 | int rc = 0; | 658 | int rc = 0; |
| 587 | unsigned int receive_len; | 659 | unsigned int receive_len; |
| 588 | unsigned long timeout; | ||
| 589 | struct mid_q_entry *midQ; | 660 | struct mid_q_entry *midQ; |
| 590 | 661 | ||
| 591 | if (ses == NULL) { | 662 | if (ses == NULL) { |
| @@ -610,7 +681,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 610 | return -EIO; | 681 | return -EIO; |
| 611 | } | 682 | } |
| 612 | 683 | ||
| 613 | rc = wait_for_free_request(ses, long_op); | 684 | rc = wait_for_free_request(ses->server, long_op); |
| 614 | if (rc) | 685 | if (rc) |
| 615 | return rc; | 686 | return rc; |
| 616 | 687 | ||
| @@ -649,64 +720,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 649 | if (rc < 0) | 720 | if (rc < 0) |
| 650 | goto out; | 721 | goto out; |
| 651 | 722 | ||
| 652 | if (long_op == CIFS_STD_OP) | 723 | if (long_op == CIFS_ASYNC_OP) |
| 653 | timeout = 15 * HZ; | ||
| 654 | /* wait for 15 seconds or until woken up due to response arriving or | ||
| 655 | due to last connection to this server being unmounted */ | ||
| 656 | else if (long_op == CIFS_ASYNC_OP) | ||
| 657 | goto out; | 724 | goto out; |
| 658 | else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */ | ||
| 659 | timeout = 180 * HZ; | ||
| 660 | else if (long_op == CIFS_LONG_OP) | ||
| 661 | timeout = 45 * HZ; /* should be greater than | ||
| 662 | servers oplock break timeout (about 43 seconds) */ | ||
| 663 | else if (long_op == CIFS_BLOCKING_OP) | ||
| 664 | timeout = 0x7FFFFFFF; /* large but no so large as to wrap */ | ||
| 665 | else { | ||
| 666 | cERROR(1, "unknown timeout flag %d", long_op); | ||
| 667 | rc = -EIO; | ||
| 668 | goto out; | ||
| 669 | } | ||
| 670 | 725 | ||
| 671 | if (signal_pending(current)) { | 726 | rc = wait_for_response(ses->server, midQ); |
| 672 | /* if signal pending do not hold up user for full smb timeout | 727 | if (rc != 0) |
| 673 | but we still give response a chance to complete */ | 728 | goto out; |
| 674 | timeout = 2 * HZ; | ||
| 675 | } | ||
| 676 | |||
| 677 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
| 678 | wait_for_response(ses, midQ, timeout, 10 * HZ); | ||
| 679 | |||
| 680 | spin_lock(&GlobalMid_Lock); | ||
| 681 | if (midQ->resp_buf == NULL) { | ||
| 682 | cERROR(1, "No response for cmd %d mid %d", | ||
| 683 | midQ->command, midQ->mid); | ||
| 684 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | ||
| 685 | if (ses->server->tcpStatus == CifsExiting) | ||
| 686 | rc = -EHOSTDOWN; | ||
| 687 | else { | ||
| 688 | ses->server->tcpStatus = CifsNeedReconnect; | ||
| 689 | midQ->midState = MID_RETRY_NEEDED; | ||
| 690 | } | ||
| 691 | } | ||
| 692 | 729 | ||
| 693 | if (rc != -EHOSTDOWN) { | 730 | rc = sync_mid_result(midQ, ses->server); |
| 694 | if (midQ->midState == MID_RETRY_NEEDED) { | 731 | if (rc != 0) { |
| 695 | rc = -EAGAIN; | ||
| 696 | cFYI(1, "marking request for retry"); | ||
| 697 | } else { | ||
| 698 | rc = -EIO; | ||
| 699 | } | ||
| 700 | } | ||
| 701 | spin_unlock(&GlobalMid_Lock); | ||
| 702 | DeleteMidQEntry(midQ); | ||
| 703 | /* Update # of requests on wire to server */ | ||
| 704 | atomic_dec(&ses->server->inFlight); | 732 | atomic_dec(&ses->server->inFlight); |
| 705 | wake_up(&ses->server->request_q); | 733 | wake_up(&ses->server->request_q); |
| 706 | return rc; | 734 | return rc; |
| 707 | } | 735 | } |
| 708 | 736 | ||
| 709 | spin_unlock(&GlobalMid_Lock); | ||
| 710 | receive_len = midQ->resp_buf->smb_buf_length; | 737 | receive_len = midQ->resp_buf->smb_buf_length; |
| 711 | 738 | ||
| 712 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 739 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
| @@ -748,43 +775,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 748 | if (receive_len >= sizeof(struct smb_hdr) - 4 | 775 | if (receive_len >= sizeof(struct smb_hdr) - 4 |
| 749 | /* do not count RFC1001 header */ + | 776 | /* do not count RFC1001 header */ + |
| 750 | (2 * out_buf->WordCount) + 2 /* bcc */ ) | 777 | (2 * out_buf->WordCount) + 2 /* bcc */ ) |
| 751 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | 778 | put_bcc(get_bcc_le(midQ->resp_buf), midQ->resp_buf); |
| 752 | } else { | 779 | } else { |
| 753 | rc = -EIO; | 780 | rc = -EIO; |
| 754 | cERROR(1, "Bad MID state?"); | 781 | cERROR(1, "Bad MID state?"); |
| 755 | } | 782 | } |
| 756 | 783 | ||
| 757 | out: | 784 | out: |
| 758 | DeleteMidQEntry(midQ); | 785 | delete_mid(midQ); |
| 759 | atomic_dec(&ses->server->inFlight); | 786 | atomic_dec(&ses->server->inFlight); |
| 760 | wake_up(&ses->server->request_q); | 787 | wake_up(&ses->server->request_q); |
| 761 | 788 | ||
| 762 | return rc; | 789 | return rc; |
| 763 | } | 790 | } |
| 764 | 791 | ||
| 765 | /* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */ | ||
| 766 | |||
| 767 | static int | ||
| 768 | send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf, | ||
| 769 | struct mid_q_entry *midQ) | ||
| 770 | { | ||
| 771 | int rc = 0; | ||
| 772 | struct cifsSesInfo *ses = tcon->ses; | ||
| 773 | __u16 mid = in_buf->Mid; | ||
| 774 | |||
| 775 | header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0); | ||
| 776 | in_buf->Mid = mid; | ||
| 777 | mutex_lock(&ses->server->srv_mutex); | ||
| 778 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | ||
| 779 | if (rc) { | ||
| 780 | mutex_unlock(&ses->server->srv_mutex); | ||
| 781 | return rc; | ||
| 782 | } | ||
| 783 | rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); | ||
| 784 | mutex_unlock(&ses->server->srv_mutex); | ||
| 785 | return rc; | ||
| 786 | } | ||
| 787 | |||
| 788 | /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows | 792 | /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows |
| 789 | blocking lock to return. */ | 793 | blocking lock to return. */ |
| 790 | 794 | ||
| @@ -807,7 +811,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 807 | pSMB->hdr.Mid = GetNextMid(ses->server); | 811 | pSMB->hdr.Mid = GetNextMid(ses->server); |
| 808 | 812 | ||
| 809 | return SendReceive(xid, ses, in_buf, out_buf, | 813 | return SendReceive(xid, ses, in_buf, out_buf, |
| 810 | &bytes_returned, CIFS_STD_OP); | 814 | &bytes_returned, 0); |
| 811 | } | 815 | } |
| 812 | 816 | ||
| 813 | int | 817 | int |
| @@ -845,7 +849,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 845 | return -EIO; | 849 | return -EIO; |
| 846 | } | 850 | } |
| 847 | 851 | ||
| 848 | rc = wait_for_free_request(ses, CIFS_BLOCKING_OP); | 852 | rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP); |
| 849 | if (rc) | 853 | if (rc) |
| 850 | return rc; | 854 | return rc; |
| 851 | 855 | ||
| @@ -863,7 +867,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 863 | 867 | ||
| 864 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 868 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
| 865 | if (rc) { | 869 | if (rc) { |
| 866 | DeleteMidQEntry(midQ); | 870 | delete_mid(midQ); |
| 867 | mutex_unlock(&ses->server->srv_mutex); | 871 | mutex_unlock(&ses->server->srv_mutex); |
| 868 | return rc; | 872 | return rc; |
| 869 | } | 873 | } |
| @@ -880,7 +884,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 880 | mutex_unlock(&ses->server->srv_mutex); | 884 | mutex_unlock(&ses->server->srv_mutex); |
| 881 | 885 | ||
| 882 | if (rc < 0) { | 886 | if (rc < 0) { |
| 883 | DeleteMidQEntry(midQ); | 887 | delete_mid(midQ); |
| 884 | return rc; | 888 | return rc; |
| 885 | } | 889 | } |
| 886 | 890 | ||
| @@ -899,10 +903,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 899 | if (in_buf->Command == SMB_COM_TRANSACTION2) { | 903 | if (in_buf->Command == SMB_COM_TRANSACTION2) { |
| 900 | /* POSIX lock. We send a NT_CANCEL SMB to cause the | 904 | /* POSIX lock. We send a NT_CANCEL SMB to cause the |
| 901 | blocking lock to return. */ | 905 | blocking lock to return. */ |
| 902 | 906 | rc = send_nt_cancel(ses->server, in_buf, midQ); | |
| 903 | rc = send_nt_cancel(tcon, in_buf, midQ); | ||
| 904 | if (rc) { | 907 | if (rc) { |
| 905 | DeleteMidQEntry(midQ); | 908 | delete_mid(midQ); |
| 906 | return rc; | 909 | return rc; |
| 907 | } | 910 | } |
| 908 | } else { | 911 | } else { |
| @@ -914,47 +917,22 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 914 | /* If we get -ENOLCK back the lock may have | 917 | /* If we get -ENOLCK back the lock may have |
| 915 | already been removed. Don't exit in this case. */ | 918 | already been removed. Don't exit in this case. */ |
| 916 | if (rc && rc != -ENOLCK) { | 919 | if (rc && rc != -ENOLCK) { |
| 917 | DeleteMidQEntry(midQ); | 920 | delete_mid(midQ); |
| 918 | return rc; | 921 | return rc; |
| 919 | } | 922 | } |
| 920 | } | 923 | } |
| 921 | 924 | ||
| 922 | /* Wait 5 seconds for the response. */ | 925 | if (wait_for_response(ses->server, midQ) == 0) { |
| 923 | if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) { | ||
| 924 | /* We got the response - restart system call. */ | 926 | /* We got the response - restart system call. */ |
| 925 | rstart = 1; | 927 | rstart = 1; |
| 926 | } | 928 | } |
| 927 | } | 929 | } |
| 928 | 930 | ||
| 929 | spin_lock(&GlobalMid_Lock); | 931 | rc = sync_mid_result(midQ, ses->server); |
| 930 | if (midQ->resp_buf) { | 932 | if (rc != 0) |
| 931 | spin_unlock(&GlobalMid_Lock); | ||
| 932 | receive_len = midQ->resp_buf->smb_buf_length; | ||
| 933 | } else { | ||
| 934 | cERROR(1, "No response for cmd %d mid %d", | ||
| 935 | midQ->command, midQ->mid); | ||
| 936 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | ||
| 937 | if (ses->server->tcpStatus == CifsExiting) | ||
| 938 | rc = -EHOSTDOWN; | ||
| 939 | else { | ||
| 940 | ses->server->tcpStatus = CifsNeedReconnect; | ||
| 941 | midQ->midState = MID_RETRY_NEEDED; | ||
| 942 | } | ||
| 943 | } | ||
| 944 | |||
| 945 | if (rc != -EHOSTDOWN) { | ||
| 946 | if (midQ->midState == MID_RETRY_NEEDED) { | ||
| 947 | rc = -EAGAIN; | ||
| 948 | cFYI(1, "marking request for retry"); | ||
| 949 | } else { | ||
| 950 | rc = -EIO; | ||
| 951 | } | ||
| 952 | } | ||
| 953 | spin_unlock(&GlobalMid_Lock); | ||
| 954 | DeleteMidQEntry(midQ); | ||
| 955 | return rc; | 933 | return rc; |
| 956 | } | ||
| 957 | 934 | ||
| 935 | receive_len = midQ->resp_buf->smb_buf_length; | ||
| 958 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 936 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
| 959 | cERROR(1, "Frame too large received. Length: %d Xid: %d", | 937 | cERROR(1, "Frame too large received. Length: %d Xid: %d", |
| 960 | receive_len, xid); | 938 | receive_len, xid); |
| @@ -998,10 +976,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 998 | if (receive_len >= sizeof(struct smb_hdr) - 4 | 976 | if (receive_len >= sizeof(struct smb_hdr) - 4 |
| 999 | /* do not count RFC1001 header */ + | 977 | /* do not count RFC1001 header */ + |
| 1000 | (2 * out_buf->WordCount) + 2 /* bcc */ ) | 978 | (2 * out_buf->WordCount) + 2 /* bcc */ ) |
| 1001 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | 979 | put_bcc(get_bcc_le(out_buf), out_buf); |
| 1002 | 980 | ||
| 1003 | out: | 981 | out: |
| 1004 | DeleteMidQEntry(midQ); | 982 | delete_mid(midQ); |
| 1005 | if (rstart && rc == -EACCES) | 983 | if (rstart && rc == -EACCES) |
| 1006 | return -ERESTARTSYS; | 984 | return -ERESTARTSYS; |
| 1007 | return rc; | 985 | return rc; |
diff --git a/fs/direct-io.c b/fs/direct-io.c index 85882f6ba5f7..b044705eedd4 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
| @@ -325,12 +325,16 @@ void dio_end_io(struct bio *bio, int error) | |||
| 325 | } | 325 | } |
| 326 | EXPORT_SYMBOL_GPL(dio_end_io); | 326 | EXPORT_SYMBOL_GPL(dio_end_io); |
| 327 | 327 | ||
| 328 | static int | 328 | static void |
| 329 | dio_bio_alloc(struct dio *dio, struct block_device *bdev, | 329 | dio_bio_alloc(struct dio *dio, struct block_device *bdev, |
| 330 | sector_t first_sector, int nr_vecs) | 330 | sector_t first_sector, int nr_vecs) |
| 331 | { | 331 | { |
| 332 | struct bio *bio; | 332 | struct bio *bio; |
| 333 | 333 | ||
| 334 | /* | ||
| 335 | * bio_alloc() is guaranteed to return a bio when called with | ||
| 336 | * __GFP_WAIT and we request a valid number of vectors. | ||
| 337 | */ | ||
| 334 | bio = bio_alloc(GFP_KERNEL, nr_vecs); | 338 | bio = bio_alloc(GFP_KERNEL, nr_vecs); |
| 335 | 339 | ||
| 336 | bio->bi_bdev = bdev; | 340 | bio->bi_bdev = bdev; |
| @@ -342,7 +346,6 @@ dio_bio_alloc(struct dio *dio, struct block_device *bdev, | |||
| 342 | 346 | ||
| 343 | dio->bio = bio; | 347 | dio->bio = bio; |
| 344 | dio->logical_offset_in_bio = dio->cur_page_fs_offset; | 348 | dio->logical_offset_in_bio = dio->cur_page_fs_offset; |
| 345 | return 0; | ||
| 346 | } | 349 | } |
| 347 | 350 | ||
| 348 | /* | 351 | /* |
| @@ -583,8 +586,9 @@ static int dio_new_bio(struct dio *dio, sector_t start_sector) | |||
| 583 | goto out; | 586 | goto out; |
| 584 | sector = start_sector << (dio->blkbits - 9); | 587 | sector = start_sector << (dio->blkbits - 9); |
| 585 | nr_pages = min(dio->pages_in_io, bio_get_nr_vecs(dio->map_bh.b_bdev)); | 588 | nr_pages = min(dio->pages_in_io, bio_get_nr_vecs(dio->map_bh.b_bdev)); |
| 589 | nr_pages = min(nr_pages, BIO_MAX_PAGES); | ||
| 586 | BUG_ON(nr_pages <= 0); | 590 | BUG_ON(nr_pages <= 0); |
| 587 | ret = dio_bio_alloc(dio, dio->map_bh.b_bdev, sector, nr_pages); | 591 | dio_bio_alloc(dio, dio->map_bh.b_bdev, sector, nr_pages); |
| 588 | dio->boundary = 0; | 592 | dio->boundary = 0; |
| 589 | out: | 593 | out: |
| 590 | return ret; | 594 | return ret; |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 7aa767d4f06f..85c8cc8f2473 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
| @@ -754,7 +754,7 @@ static int ext3_release_dquot(struct dquot *dquot); | |||
| 754 | static int ext3_mark_dquot_dirty(struct dquot *dquot); | 754 | static int ext3_mark_dquot_dirty(struct dquot *dquot); |
| 755 | static int ext3_write_info(struct super_block *sb, int type); | 755 | static int ext3_write_info(struct super_block *sb, int type); |
| 756 | static int ext3_quota_on(struct super_block *sb, int type, int format_id, | 756 | static int ext3_quota_on(struct super_block *sb, int type, int format_id, |
| 757 | char *path); | 757 | struct path *path); |
| 758 | static int ext3_quota_on_mount(struct super_block *sb, int type); | 758 | static int ext3_quota_on_mount(struct super_block *sb, int type); |
| 759 | static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, | 759 | static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, |
| 760 | size_t len, loff_t off); | 760 | size_t len, loff_t off); |
| @@ -2877,27 +2877,20 @@ static int ext3_quota_on_mount(struct super_block *sb, int type) | |||
| 2877 | * Standard function to be called on quota_on | 2877 | * Standard function to be called on quota_on |
| 2878 | */ | 2878 | */ |
| 2879 | static int ext3_quota_on(struct super_block *sb, int type, int format_id, | 2879 | static int ext3_quota_on(struct super_block *sb, int type, int format_id, |
| 2880 | char *name) | 2880 | struct path *path) |
| 2881 | { | 2881 | { |
| 2882 | int err; | 2882 | int err; |
| 2883 | struct path path; | ||
| 2884 | 2883 | ||
| 2885 | if (!test_opt(sb, QUOTA)) | 2884 | if (!test_opt(sb, QUOTA)) |
| 2886 | return -EINVAL; | 2885 | return -EINVAL; |
| 2887 | 2886 | ||
| 2888 | err = kern_path(name, LOOKUP_FOLLOW, &path); | ||
| 2889 | if (err) | ||
| 2890 | return err; | ||
| 2891 | |||
| 2892 | /* Quotafile not on the same filesystem? */ | 2887 | /* Quotafile not on the same filesystem? */ |
| 2893 | if (path.mnt->mnt_sb != sb) { | 2888 | if (path->mnt->mnt_sb != sb) |
| 2894 | path_put(&path); | ||
| 2895 | return -EXDEV; | 2889 | return -EXDEV; |
| 2896 | } | ||
| 2897 | /* Journaling quota? */ | 2890 | /* Journaling quota? */ |
| 2898 | if (EXT3_SB(sb)->s_qf_names[type]) { | 2891 | if (EXT3_SB(sb)->s_qf_names[type]) { |
| 2899 | /* Quotafile not of fs root? */ | 2892 | /* Quotafile not of fs root? */ |
| 2900 | if (path.dentry->d_parent != sb->s_root) | 2893 | if (path->dentry->d_parent != sb->s_root) |
| 2901 | ext3_msg(sb, KERN_WARNING, | 2894 | ext3_msg(sb, KERN_WARNING, |
| 2902 | "warning: Quota file not on filesystem root. " | 2895 | "warning: Quota file not on filesystem root. " |
| 2903 | "Journaled quota will not work."); | 2896 | "Journaled quota will not work."); |
| @@ -2907,7 +2900,7 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2907 | * When we journal data on quota file, we have to flush journal to see | 2900 | * When we journal data on quota file, we have to flush journal to see |
| 2908 | * all updates to the file when we bypass pagecache... | 2901 | * all updates to the file when we bypass pagecache... |
| 2909 | */ | 2902 | */ |
| 2910 | if (ext3_should_journal_data(path.dentry->d_inode)) { | 2903 | if (ext3_should_journal_data(path->dentry->d_inode)) { |
| 2911 | /* | 2904 | /* |
| 2912 | * We don't need to lock updates but journal_flush() could | 2905 | * We don't need to lock updates but journal_flush() could |
| 2913 | * otherwise be livelocked... | 2906 | * otherwise be livelocked... |
| @@ -2915,15 +2908,11 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2915 | journal_lock_updates(EXT3_SB(sb)->s_journal); | 2908 | journal_lock_updates(EXT3_SB(sb)->s_journal); |
| 2916 | err = journal_flush(EXT3_SB(sb)->s_journal); | 2909 | err = journal_flush(EXT3_SB(sb)->s_journal); |
| 2917 | journal_unlock_updates(EXT3_SB(sb)->s_journal); | 2910 | journal_unlock_updates(EXT3_SB(sb)->s_journal); |
| 2918 | if (err) { | 2911 | if (err) |
| 2919 | path_put(&path); | ||
| 2920 | return err; | 2912 | return err; |
| 2921 | } | ||
| 2922 | } | 2913 | } |
| 2923 | 2914 | ||
| 2924 | err = dquot_quota_on_path(sb, type, format_id, &path); | 2915 | return dquot_quota_on(sb, type, format_id, path); |
| 2925 | path_put(&path); | ||
| 2926 | return err; | ||
| 2927 | } | 2916 | } |
| 2928 | 2917 | ||
| 2929 | /* Read data from quotafile - avoid pagecache and such because we cannot afford | 2918 | /* Read data from quotafile - avoid pagecache and such because we cannot afford |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index cb10a06775e4..48ce561fafac 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -1161,7 +1161,7 @@ static int ext4_release_dquot(struct dquot *dquot); | |||
| 1161 | static int ext4_mark_dquot_dirty(struct dquot *dquot); | 1161 | static int ext4_mark_dquot_dirty(struct dquot *dquot); |
| 1162 | static int ext4_write_info(struct super_block *sb, int type); | 1162 | static int ext4_write_info(struct super_block *sb, int type); |
| 1163 | static int ext4_quota_on(struct super_block *sb, int type, int format_id, | 1163 | static int ext4_quota_on(struct super_block *sb, int type, int format_id, |
| 1164 | char *path); | 1164 | struct path *path); |
| 1165 | static int ext4_quota_off(struct super_block *sb, int type); | 1165 | static int ext4_quota_off(struct super_block *sb, int type); |
| 1166 | static int ext4_quota_on_mount(struct super_block *sb, int type); | 1166 | static int ext4_quota_on_mount(struct super_block *sb, int type); |
| 1167 | static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, | 1167 | static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, |
| @@ -4558,27 +4558,20 @@ static int ext4_quota_on_mount(struct super_block *sb, int type) | |||
| 4558 | * Standard function to be called on quota_on | 4558 | * Standard function to be called on quota_on |
| 4559 | */ | 4559 | */ |
| 4560 | static int ext4_quota_on(struct super_block *sb, int type, int format_id, | 4560 | static int ext4_quota_on(struct super_block *sb, int type, int format_id, |
| 4561 | char *name) | 4561 | struct path *path) |
| 4562 | { | 4562 | { |
| 4563 | int err; | 4563 | int err; |
| 4564 | struct path path; | ||
| 4565 | 4564 | ||
| 4566 | if (!test_opt(sb, QUOTA)) | 4565 | if (!test_opt(sb, QUOTA)) |
| 4567 | return -EINVAL; | 4566 | return -EINVAL; |
| 4568 | 4567 | ||
| 4569 | err = kern_path(name, LOOKUP_FOLLOW, &path); | ||
| 4570 | if (err) | ||
| 4571 | return err; | ||
| 4572 | |||
| 4573 | /* Quotafile not on the same filesystem? */ | 4568 | /* Quotafile not on the same filesystem? */ |
| 4574 | if (path.mnt->mnt_sb != sb) { | 4569 | if (path->mnt->mnt_sb != sb) |
| 4575 | path_put(&path); | ||
| 4576 | return -EXDEV; | 4570 | return -EXDEV; |
| 4577 | } | ||
| 4578 | /* Journaling quota? */ | 4571 | /* Journaling quota? */ |
| 4579 | if (EXT4_SB(sb)->s_qf_names[type]) { | 4572 | if (EXT4_SB(sb)->s_qf_names[type]) { |
| 4580 | /* Quotafile not in fs root? */ | 4573 | /* Quotafile not in fs root? */ |
| 4581 | if (path.dentry->d_parent != sb->s_root) | 4574 | if (path->dentry->d_parent != sb->s_root) |
| 4582 | ext4_msg(sb, KERN_WARNING, | 4575 | ext4_msg(sb, KERN_WARNING, |
| 4583 | "Quota file not on filesystem root. " | 4576 | "Quota file not on filesystem root. " |
| 4584 | "Journaled quota will not work"); | 4577 | "Journaled quota will not work"); |
| @@ -4589,7 +4582,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, | |||
| 4589 | * all updates to the file when we bypass pagecache... | 4582 | * all updates to the file when we bypass pagecache... |
| 4590 | */ | 4583 | */ |
| 4591 | if (EXT4_SB(sb)->s_journal && | 4584 | if (EXT4_SB(sb)->s_journal && |
| 4592 | ext4_should_journal_data(path.dentry->d_inode)) { | 4585 | ext4_should_journal_data(path->dentry->d_inode)) { |
| 4593 | /* | 4586 | /* |
| 4594 | * We don't need to lock updates but journal_flush() could | 4587 | * We don't need to lock updates but journal_flush() could |
| 4595 | * otherwise be livelocked... | 4588 | * otherwise be livelocked... |
| @@ -4597,15 +4590,11 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, | |||
| 4597 | jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); | 4590 | jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); |
| 4598 | err = jbd2_journal_flush(EXT4_SB(sb)->s_journal); | 4591 | err = jbd2_journal_flush(EXT4_SB(sb)->s_journal); |
| 4599 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); | 4592 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); |
| 4600 | if (err) { | 4593 | if (err) |
| 4601 | path_put(&path); | ||
| 4602 | return err; | 4594 | return err; |
| 4603 | } | ||
| 4604 | } | 4595 | } |
| 4605 | 4596 | ||
| 4606 | err = dquot_quota_on_path(sb, type, format_id, &path); | 4597 | return dquot_quota_on(sb, type, format_id, path); |
| 4607 | path_put(&path); | ||
| 4608 | return err; | ||
| 4609 | } | 4598 | } |
| 4610 | 4599 | ||
| 4611 | static int ext4_quota_off(struct super_block *sb, int type) | 4600 | static int ext4_quota_off(struct super_block *sb, int type) |
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 2232b3c780bd..7aa7d4f8984a 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
| @@ -74,16 +74,14 @@ static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr) | |||
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | /** | 76 | /** |
| 77 | * GFS2 lookup code fills in vfs inode contents based on info obtained | 77 | * gfs2_set_iop - Sets inode operations |
| 78 | * from directory entry inside gfs2_inode_lookup(). This has caused issues | 78 | * @inode: The inode with correct i_mode filled in |
| 79 | * with NFS code path since its get_dentry routine doesn't have the relevant | ||
| 80 | * directory entry when gfs2_inode_lookup() is invoked. Part of the code | ||
| 81 | * segment inside gfs2_inode_lookup code needs to get moved around. | ||
| 82 | * | 79 | * |
| 83 | * Clears I_NEW as well. | 80 | * GFS2 lookup code fills in vfs inode contents based on info obtained |
| 84 | **/ | 81 | * from directory entry inside gfs2_inode_lookup(). |
| 82 | */ | ||
| 85 | 83 | ||
| 86 | void gfs2_set_iop(struct inode *inode) | 84 | static void gfs2_set_iop(struct inode *inode) |
| 87 | { | 85 | { |
| 88 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 86 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
| 89 | umode_t mode = inode->i_mode; | 87 | umode_t mode = inode->i_mode; |
| @@ -106,8 +104,6 @@ void gfs2_set_iop(struct inode *inode) | |||
| 106 | inode->i_op = &gfs2_file_iops; | 104 | inode->i_op = &gfs2_file_iops; |
| 107 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | 105 | init_special_inode(inode, inode->i_mode, inode->i_rdev); |
| 108 | } | 106 | } |
| 109 | |||
| 110 | unlock_new_inode(inode); | ||
| 111 | } | 107 | } |
| 112 | 108 | ||
| 113 | /** | 109 | /** |
| @@ -119,10 +115,8 @@ void gfs2_set_iop(struct inode *inode) | |||
| 119 | * Returns: A VFS inode, or an error | 115 | * Returns: A VFS inode, or an error |
| 120 | */ | 116 | */ |
| 121 | 117 | ||
| 122 | struct inode *gfs2_inode_lookup(struct super_block *sb, | 118 | struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, |
| 123 | unsigned int type, | 119 | u64 no_addr, u64 no_formal_ino) |
| 124 | u64 no_addr, | ||
| 125 | u64 no_formal_ino) | ||
| 126 | { | 120 | { |
| 127 | struct inode *inode; | 121 | struct inode *inode; |
| 128 | struct gfs2_inode *ip; | 122 | struct gfs2_inode *ip; |
| @@ -152,51 +146,37 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, | |||
| 152 | error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); | 146 | error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); |
| 153 | if (unlikely(error)) | 147 | if (unlikely(error)) |
| 154 | goto fail_iopen; | 148 | goto fail_iopen; |
| 155 | ip->i_iopen_gh.gh_gl->gl_object = ip; | ||
| 156 | 149 | ||
| 150 | ip->i_iopen_gh.gh_gl->gl_object = ip; | ||
| 157 | gfs2_glock_put(io_gl); | 151 | gfs2_glock_put(io_gl); |
| 158 | io_gl = NULL; | 152 | io_gl = NULL; |
| 159 | 153 | ||
| 160 | if ((type == DT_UNKNOWN) && (no_formal_ino == 0)) | ||
| 161 | goto gfs2_nfsbypass; | ||
| 162 | |||
| 163 | inode->i_mode = DT2IF(type); | ||
| 164 | |||
| 165 | /* | ||
| 166 | * We must read the inode in order to work out its type in | ||
| 167 | * this case. Note that this doesn't happen often as we normally | ||
| 168 | * know the type beforehand. This code path only occurs during | ||
| 169 | * unlinked inode recovery (where it is safe to do this glock, | ||
| 170 | * which is not true in the general case). | ||
| 171 | */ | ||
| 172 | if (type == DT_UNKNOWN) { | 154 | if (type == DT_UNKNOWN) { |
| 173 | struct gfs2_holder gh; | 155 | /* Inode glock must be locked already */ |
| 174 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | 156 | error = gfs2_inode_refresh(GFS2_I(inode)); |
| 175 | if (unlikely(error)) | 157 | if (error) |
| 176 | goto fail_glock; | 158 | goto fail_refresh; |
| 177 | /* Inode is now uptodate */ | 159 | } else { |
| 178 | gfs2_glock_dq_uninit(&gh); | 160 | inode->i_mode = DT2IF(type); |
| 179 | } | 161 | } |
| 180 | 162 | ||
| 181 | gfs2_set_iop(inode); | 163 | gfs2_set_iop(inode); |
| 164 | unlock_new_inode(inode); | ||
| 182 | } | 165 | } |
| 183 | 166 | ||
| 184 | gfs2_nfsbypass: | ||
| 185 | return inode; | 167 | return inode; |
| 186 | fail_glock: | 168 | |
| 187 | gfs2_glock_dq(&ip->i_iopen_gh); | 169 | fail_refresh: |
| 170 | ip->i_iopen_gh.gh_gl->gl_object = NULL; | ||
| 171 | gfs2_glock_dq_uninit(&ip->i_iopen_gh); | ||
| 188 | fail_iopen: | 172 | fail_iopen: |
| 189 | if (io_gl) | 173 | if (io_gl) |
| 190 | gfs2_glock_put(io_gl); | 174 | gfs2_glock_put(io_gl); |
| 191 | fail_put: | 175 | fail_put: |
| 192 | if (inode->i_state & I_NEW) | 176 | ip->i_gl->gl_object = NULL; |
| 193 | ip->i_gl->gl_object = NULL; | ||
| 194 | gfs2_glock_put(ip->i_gl); | 177 | gfs2_glock_put(ip->i_gl); |
| 195 | fail: | 178 | fail: |
| 196 | if (inode->i_state & I_NEW) | 179 | iget_failed(inode); |
| 197 | iget_failed(inode); | ||
| 198 | else | ||
| 199 | iput(inode); | ||
| 200 | return ERR_PTR(error); | 180 | return ERR_PTR(error); |
| 201 | } | 181 | } |
| 202 | 182 | ||
| @@ -221,14 +201,6 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, | |||
| 221 | if (IS_ERR(inode)) | 201 | if (IS_ERR(inode)) |
| 222 | goto fail; | 202 | goto fail; |
| 223 | 203 | ||
| 224 | error = gfs2_inode_refresh(GFS2_I(inode)); | ||
| 225 | if (error) | ||
| 226 | goto fail_iput; | ||
| 227 | |||
| 228 | /* Pick up the works we bypass in gfs2_inode_lookup */ | ||
| 229 | if (inode->i_state & I_NEW) | ||
| 230 | gfs2_set_iop(inode); | ||
| 231 | |||
| 232 | /* Two extra checks for NFS only */ | 204 | /* Two extra checks for NFS only */ |
| 233 | if (no_formal_ino) { | 205 | if (no_formal_ino) { |
| 234 | error = -ESTALE; | 206 | error = -ESTALE; |
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 732a183efdb3..3e00a66e7cbd 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h | |||
| @@ -96,7 +96,6 @@ err: | |||
| 96 | return -EIO; | 96 | return -EIO; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | extern void gfs2_set_iop(struct inode *inode); | ||
| 100 | extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, | 99 | extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, |
| 101 | u64 no_addr, u64 no_formal_ino); | 100 | u64 no_addr, u64 no_formal_ino); |
| 102 | extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, | 101 | extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 16c2ecac7eb7..ec73ed70bae1 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
| @@ -1336,6 +1336,7 @@ static void gfs2_evict_inode(struct inode *inode) | |||
| 1336 | if (error) | 1336 | if (error) |
| 1337 | goto out_truncate; | 1337 | goto out_truncate; |
| 1338 | 1338 | ||
| 1339 | ip->i_iopen_gh.gh_flags |= GL_NOCACHE; | ||
| 1339 | gfs2_glock_dq_wait(&ip->i_iopen_gh); | 1340 | gfs2_glock_dq_wait(&ip->i_iopen_gh); |
| 1340 | gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); | 1341 | gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); |
| 1341 | error = gfs2_glock_nq(&ip->i_iopen_gh); | 1342 | error = gfs2_glock_nq(&ip->i_iopen_gh); |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 06d1f749ca89..38f986d2447e 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
| @@ -993,8 +993,7 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb) | |||
| 993 | } | 993 | } |
| 994 | 994 | ||
| 995 | /* Handle quota on quotactl */ | 995 | /* Handle quota on quotactl */ |
| 996 | static int ocfs2_quota_on(struct super_block *sb, int type, int format_id, | 996 | static int ocfs2_quota_on(struct super_block *sb, int type, int format_id) |
| 997 | char *path) | ||
| 998 | { | 997 | { |
| 999 | unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, | 998 | unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, |
| 1000 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}; | 999 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}; |
| @@ -1013,7 +1012,7 @@ static int ocfs2_quota_off(struct super_block *sb, int type) | |||
| 1013 | } | 1012 | } |
| 1014 | 1013 | ||
| 1015 | static const struct quotactl_ops ocfs2_quotactl_ops = { | 1014 | static const struct quotactl_ops ocfs2_quotactl_ops = { |
| 1016 | .quota_on = ocfs2_quota_on, | 1015 | .quota_on_meta = ocfs2_quota_on, |
| 1017 | .quota_off = ocfs2_quota_off, | 1016 | .quota_off = ocfs2_quota_off, |
| 1018 | .quota_sync = dquot_quota_sync, | 1017 | .quota_sync = dquot_quota_sync, |
| 1019 | .get_info = dquot_get_dqinfo, | 1018 | .get_info = dquot_get_dqinfo, |
| @@ -441,7 +441,7 @@ redo: | |||
| 441 | break; | 441 | break; |
| 442 | } | 442 | } |
| 443 | if (do_wakeup) { | 443 | if (do_wakeup) { |
| 444 | wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT); | 444 | wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT | POLLWRNORM); |
| 445 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); | 445 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); |
| 446 | } | 446 | } |
| 447 | pipe_wait(pipe); | 447 | pipe_wait(pipe); |
| @@ -450,7 +450,7 @@ redo: | |||
| 450 | 450 | ||
| 451 | /* Signal writers asynchronously that there is more room. */ | 451 | /* Signal writers asynchronously that there is more room. */ |
| 452 | if (do_wakeup) { | 452 | if (do_wakeup) { |
| 453 | wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT); | 453 | wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT | POLLWRNORM); |
| 454 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); | 454 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); |
| 455 | } | 455 | } |
| 456 | if (ret > 0) | 456 | if (ret > 0) |
| @@ -612,7 +612,7 @@ redo2: | |||
| 612 | break; | 612 | break; |
| 613 | } | 613 | } |
| 614 | if (do_wakeup) { | 614 | if (do_wakeup) { |
| 615 | wake_up_interruptible_sync_poll(&pipe->wait, POLLIN); | 615 | wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM); |
| 616 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); | 616 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); |
| 617 | do_wakeup = 0; | 617 | do_wakeup = 0; |
| 618 | } | 618 | } |
| @@ -623,7 +623,7 @@ redo2: | |||
| 623 | out: | 623 | out: |
| 624 | mutex_unlock(&inode->i_mutex); | 624 | mutex_unlock(&inode->i_mutex); |
| 625 | if (do_wakeup) { | 625 | if (do_wakeup) { |
| 626 | wake_up_interruptible_sync_poll(&pipe->wait, POLLIN); | 626 | wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM); |
| 627 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); | 627 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); |
| 628 | } | 628 | } |
| 629 | if (ret > 0) | 629 | if (ret > 0) |
| @@ -715,7 +715,7 @@ pipe_release(struct inode *inode, int decr, int decw) | |||
| 715 | if (!pipe->readers && !pipe->writers) { | 715 | if (!pipe->readers && !pipe->writers) { |
| 716 | free_pipe_info(inode); | 716 | free_pipe_info(inode); |
| 717 | } else { | 717 | } else { |
| 718 | wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT); | 718 | wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM | POLLERR | POLLHUP); |
| 719 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); | 719 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); |
| 720 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); | 720 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); |
| 721 | } | 721 | } |
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index 6a0068841d96..15af6222f8a4 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | config PROC_FS | 1 | config PROC_FS |
| 2 | bool "/proc file system support" if EMBEDDED | 2 | bool "/proc file system support" if EXPERT |
| 3 | default y | 3 | default y |
| 4 | help | 4 | help |
| 5 | This is a virtual file system providing information about the status | 5 | This is a virtual file system providing information about the status |
| @@ -40,7 +40,7 @@ config PROC_VMCORE | |||
| 40 | Exports the dump image of crashed kernel in ELF format. | 40 | Exports the dump image of crashed kernel in ELF format. |
| 41 | 41 | ||
| 42 | config PROC_SYSCTL | 42 | config PROC_SYSCTL |
| 43 | bool "Sysctl support (/proc/sys)" if EMBEDDED | 43 | bool "Sysctl support (/proc/sys)" if EXPERT |
| 44 | depends on PROC_FS | 44 | depends on PROC_FS |
| 45 | select SYSCTL | 45 | select SYSCTL |
| 46 | default y | 46 | default y |
| @@ -61,7 +61,7 @@ config PROC_SYSCTL | |||
| 61 | config PROC_PAGE_MONITOR | 61 | config PROC_PAGE_MONITOR |
| 62 | default y | 62 | default y |
| 63 | depends on PROC_FS && MMU | 63 | depends on PROC_FS && MMU |
| 64 | bool "Enable /proc page monitoring" if EMBEDDED | 64 | bool "Enable /proc page monitoring" if EXPERT |
| 65 | help | 65 | help |
| 66 | Various /proc files exist to monitor process memory utilization: | 66 | Various /proc files exist to monitor process memory utilization: |
| 67 | /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap, | 67 | /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap, |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 84becd3e4772..a2a622e079f0 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
| @@ -2189,8 +2189,8 @@ int dquot_resume(struct super_block *sb, int type) | |||
| 2189 | } | 2189 | } |
| 2190 | EXPORT_SYMBOL(dquot_resume); | 2190 | EXPORT_SYMBOL(dquot_resume); |
| 2191 | 2191 | ||
| 2192 | int dquot_quota_on_path(struct super_block *sb, int type, int format_id, | 2192 | int dquot_quota_on(struct super_block *sb, int type, int format_id, |
| 2193 | struct path *path) | 2193 | struct path *path) |
| 2194 | { | 2194 | { |
| 2195 | int error = security_quota_on(path->dentry); | 2195 | int error = security_quota_on(path->dentry); |
| 2196 | if (error) | 2196 | if (error) |
| @@ -2204,20 +2204,6 @@ int dquot_quota_on_path(struct super_block *sb, int type, int format_id, | |||
| 2204 | DQUOT_LIMITS_ENABLED); | 2204 | DQUOT_LIMITS_ENABLED); |
| 2205 | return error; | 2205 | return error; |
| 2206 | } | 2206 | } |
| 2207 | EXPORT_SYMBOL(dquot_quota_on_path); | ||
| 2208 | |||
| 2209 | int dquot_quota_on(struct super_block *sb, int type, int format_id, char *name) | ||
| 2210 | { | ||
| 2211 | struct path path; | ||
| 2212 | int error; | ||
| 2213 | |||
| 2214 | error = kern_path(name, LOOKUP_FOLLOW, &path); | ||
| 2215 | if (!error) { | ||
| 2216 | error = dquot_quota_on_path(sb, type, format_id, &path); | ||
| 2217 | path_put(&path); | ||
| 2218 | } | ||
| 2219 | return error; | ||
| 2220 | } | ||
| 2221 | EXPORT_SYMBOL(dquot_quota_on); | 2207 | EXPORT_SYMBOL(dquot_quota_on); |
| 2222 | 2208 | ||
| 2223 | /* | 2209 | /* |
diff --git a/fs/quota/quota.c b/fs/quota/quota.c index b299961e1edb..b34bdb25490c 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c | |||
| @@ -64,18 +64,15 @@ static int quota_sync_all(int type) | |||
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id, | 66 | static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id, |
| 67 | void __user *addr) | 67 | struct path *path) |
| 68 | { | 68 | { |
| 69 | char *pathname; | 69 | if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta) |
| 70 | int ret = -ENOSYS; | 70 | return -ENOSYS; |
| 71 | 71 | if (sb->s_qcop->quota_on_meta) | |
| 72 | pathname = getname(addr); | 72 | return sb->s_qcop->quota_on_meta(sb, type, id); |
| 73 | if (IS_ERR(pathname)) | 73 | if (IS_ERR(path)) |
| 74 | return PTR_ERR(pathname); | 74 | return PTR_ERR(path); |
| 75 | if (sb->s_qcop->quota_on) | 75 | return sb->s_qcop->quota_on(sb, type, id, path); |
| 76 | ret = sb->s_qcop->quota_on(sb, type, id, pathname); | ||
| 77 | putname(pathname); | ||
| 78 | return ret; | ||
| 79 | } | 76 | } |
| 80 | 77 | ||
| 81 | static int quota_getfmt(struct super_block *sb, int type, void __user *addr) | 78 | static int quota_getfmt(struct super_block *sb, int type, void __user *addr) |
| @@ -241,7 +238,7 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id, | |||
| 241 | 238 | ||
| 242 | /* Copy parameters and call proper function */ | 239 | /* Copy parameters and call proper function */ |
| 243 | static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, | 240 | static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, |
| 244 | void __user *addr) | 241 | void __user *addr, struct path *path) |
| 245 | { | 242 | { |
| 246 | int ret; | 243 | int ret; |
| 247 | 244 | ||
| @@ -256,7 +253,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, | |||
| 256 | 253 | ||
| 257 | switch (cmd) { | 254 | switch (cmd) { |
| 258 | case Q_QUOTAON: | 255 | case Q_QUOTAON: |
| 259 | return quota_quotaon(sb, type, cmd, id, addr); | 256 | return quota_quotaon(sb, type, cmd, id, path); |
| 260 | case Q_QUOTAOFF: | 257 | case Q_QUOTAOFF: |
| 261 | if (!sb->s_qcop->quota_off) | 258 | if (!sb->s_qcop->quota_off) |
| 262 | return -ENOSYS; | 259 | return -ENOSYS; |
| @@ -335,6 +332,7 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special, | |||
| 335 | { | 332 | { |
| 336 | uint cmds, type; | 333 | uint cmds, type; |
| 337 | struct super_block *sb = NULL; | 334 | struct super_block *sb = NULL; |
| 335 | struct path path, *pathp = NULL; | ||
| 338 | int ret; | 336 | int ret; |
| 339 | 337 | ||
| 340 | cmds = cmd >> SUBCMDSHIFT; | 338 | cmds = cmd >> SUBCMDSHIFT; |
| @@ -351,12 +349,27 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special, | |||
| 351 | return -ENODEV; | 349 | return -ENODEV; |
| 352 | } | 350 | } |
| 353 | 351 | ||
| 352 | /* | ||
| 353 | * Path for quotaon has to be resolved before grabbing superblock | ||
| 354 | * because that gets s_umount sem which is also possibly needed by path | ||
| 355 | * resolution (think about autofs) and thus deadlocks could arise. | ||
| 356 | */ | ||
| 357 | if (cmds == Q_QUOTAON) { | ||
| 358 | ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW, &path); | ||
| 359 | if (ret) | ||
| 360 | pathp = ERR_PTR(ret); | ||
| 361 | else | ||
| 362 | pathp = &path; | ||
| 363 | } | ||
| 364 | |||
| 354 | sb = quotactl_block(special); | 365 | sb = quotactl_block(special); |
| 355 | if (IS_ERR(sb)) | 366 | if (IS_ERR(sb)) |
| 356 | return PTR_ERR(sb); | 367 | return PTR_ERR(sb); |
| 357 | 368 | ||
| 358 | ret = do_quotactl(sb, type, cmds, id, addr); | 369 | ret = do_quotactl(sb, type, cmds, id, addr, pathp); |
| 359 | 370 | ||
| 360 | drop_super(sb); | 371 | drop_super(sb); |
| 372 | if (pathp && !IS_ERR(pathp)) | ||
| 373 | path_put(pathp); | ||
| 361 | return ret; | 374 | return ret; |
| 362 | } | 375 | } |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 2575682a9ead..0aab04f46827 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
| @@ -632,7 +632,7 @@ static int reiserfs_acquire_dquot(struct dquot *); | |||
| 632 | static int reiserfs_release_dquot(struct dquot *); | 632 | static int reiserfs_release_dquot(struct dquot *); |
| 633 | static int reiserfs_mark_dquot_dirty(struct dquot *); | 633 | static int reiserfs_mark_dquot_dirty(struct dquot *); |
| 634 | static int reiserfs_write_info(struct super_block *, int); | 634 | static int reiserfs_write_info(struct super_block *, int); |
| 635 | static int reiserfs_quota_on(struct super_block *, int, int, char *); | 635 | static int reiserfs_quota_on(struct super_block *, int, int, struct path *); |
| 636 | 636 | ||
| 637 | static const struct dquot_operations reiserfs_quota_operations = { | 637 | static const struct dquot_operations reiserfs_quota_operations = { |
| 638 | .write_dquot = reiserfs_write_dquot, | 638 | .write_dquot = reiserfs_write_dquot, |
| @@ -2048,25 +2048,21 @@ static int reiserfs_quota_on_mount(struct super_block *sb, int type) | |||
| 2048 | * Standard function to be called on quota_on | 2048 | * Standard function to be called on quota_on |
| 2049 | */ | 2049 | */ |
| 2050 | static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | 2050 | static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, |
| 2051 | char *name) | 2051 | struct path *path) |
| 2052 | { | 2052 | { |
| 2053 | int err; | 2053 | int err; |
| 2054 | struct path path; | ||
| 2055 | struct inode *inode; | 2054 | struct inode *inode; |
| 2056 | struct reiserfs_transaction_handle th; | 2055 | struct reiserfs_transaction_handle th; |
| 2057 | 2056 | ||
| 2058 | if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA))) | 2057 | if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA))) |
| 2059 | return -EINVAL; | 2058 | return -EINVAL; |
| 2060 | 2059 | ||
| 2061 | err = kern_path(name, LOOKUP_FOLLOW, &path); | ||
| 2062 | if (err) | ||
| 2063 | return err; | ||
| 2064 | /* Quotafile not on the same filesystem? */ | 2060 | /* Quotafile not on the same filesystem? */ |
| 2065 | if (path.mnt->mnt_sb != sb) { | 2061 | if (path->mnt->mnt_sb != sb) { |
| 2066 | err = -EXDEV; | 2062 | err = -EXDEV; |
| 2067 | goto out; | 2063 | goto out; |
| 2068 | } | 2064 | } |
| 2069 | inode = path.dentry->d_inode; | 2065 | inode = path->dentry->d_inode; |
| 2070 | /* We must not pack tails for quota files on reiserfs for quota IO to work */ | 2066 | /* We must not pack tails for quota files on reiserfs for quota IO to work */ |
| 2071 | if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) { | 2067 | if (!(REISERFS_I(inode)->i_flags & i_nopack_mask)) { |
| 2072 | err = reiserfs_unpack(inode, NULL); | 2068 | err = reiserfs_unpack(inode, NULL); |
| @@ -2082,7 +2078,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2082 | /* Journaling quota? */ | 2078 | /* Journaling quota? */ |
| 2083 | if (REISERFS_SB(sb)->s_qf_names[type]) { | 2079 | if (REISERFS_SB(sb)->s_qf_names[type]) { |
| 2084 | /* Quotafile not of fs root? */ | 2080 | /* Quotafile not of fs root? */ |
| 2085 | if (path.dentry->d_parent != sb->s_root) | 2081 | if (path->dentry->d_parent != sb->s_root) |
| 2086 | reiserfs_warning(sb, "super-6521", | 2082 | reiserfs_warning(sb, "super-6521", |
| 2087 | "Quota file not on filesystem root. " | 2083 | "Quota file not on filesystem root. " |
| 2088 | "Journalled quota will not work."); | 2084 | "Journalled quota will not work."); |
| @@ -2101,9 +2097,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2101 | if (err) | 2097 | if (err) |
| 2102 | goto out; | 2098 | goto out; |
| 2103 | } | 2099 | } |
| 2104 | err = dquot_quota_on_path(sb, type, format_id, &path); | 2100 | err = dquot_quota_on(sb, type, format_id, path); |
| 2105 | out: | 2101 | out: |
| 2106 | path_put(&path); | ||
| 2107 | return err; | 2102 | return err; |
| 2108 | } | 2103 | } |
| 2109 | 2104 | ||
diff --git a/fs/sysfs/Kconfig b/fs/sysfs/Kconfig index f4b67588b9d6..8c41feacbac5 100644 --- a/fs/sysfs/Kconfig +++ b/fs/sysfs/Kconfig | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | config SYSFS | 1 | config SYSFS |
| 2 | bool "sysfs file system support" if EMBEDDED | 2 | bool "sysfs file system support" if EXPERT |
| 3 | default y | 3 | default y |
| 4 | help | 4 | help |
| 5 | The sysfs filesystem is a virtual filesystem that the kernel uses to | 5 | The sysfs filesystem is a virtual filesystem that the kernel uses to |
