Commit 8d4ab5daca4b3bf9c9166908db0c436722d52e77
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: cifs: when renaming don't try to unlink negative dentry cifs: remove unneeded bcc_ptr update in CIFSTCon cifs: add cFYI messages with some of the saved strings from ssetup/tcon cifs: fix buffer size for tcon->nativeFileSystem field cifs: fix unicode string area word alignment in session setup [CIFS] Fix build break caused by change to new current_umask helper function [CIFS] Fix sparse warnings [CIFS] Add support for posix open during lookup cifs: no need to use rcu_assign_pointer on immutable keys cifs: remove dnotify thread code [CIFS] remove some build warnings cifs: vary timeout on writes past EOF based on offset (try #5) [CIFS] Fix build break from recent DFS patch when DFS support not enabled Remote DFS root support. [CIFS] Endian convert UniqueId when reporting inode numbers from server files cifs: remove some pointless conditionals before kfree() cifs: flush data on any setattr
Showing 13 changed files Side-by-side Diff
fs/cifs/CHANGES
... | ... | @@ -15,7 +15,8 @@ |
15 | 15 | fails to support it properly, as with Samba server versions prior to 3.3.2) |
16 | 16 | Fix "redzone overwritten" bug in cifs_put_tcon (CIFSTcon may allocate too |
17 | 17 | little memory for the "nativeFileSystem" field returned by the server |
18 | -during mount). | |
18 | +during mount). Endian convert inode numbers if necessary (makes it easier | |
19 | +to compare inode numbers on network files from big endian systems). | |
19 | 20 | |
20 | 21 | Version 1.56 |
21 | 22 | ------------ |
fs/cifs/cifs_spnego.c
fs/cifs/cifsfs.c
... | ... | @@ -66,9 +66,6 @@ |
66 | 66 | extern struct task_struct *oplockThread; /* remove sparse warning */ |
67 | 67 | struct task_struct *oplockThread = NULL; |
68 | 68 | /* extern struct task_struct * dnotifyThread; remove sparse warning */ |
69 | -#ifdef CONFIG_CIFS_EXPERIMENTAL | |
70 | -static struct task_struct *dnotifyThread = NULL; | |
71 | -#endif | |
72 | 69 | static const struct super_operations cifs_super_ops; |
73 | 70 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; |
74 | 71 | module_param(CIFSMaxBufSize, int, 0); |
... | ... | @@ -316,6 +313,7 @@ |
316 | 313 | cifs_inode->clientCanCacheAll = false; |
317 | 314 | cifs_inode->delete_pending = false; |
318 | 315 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
316 | + cifs_inode->server_eof = 0; | |
319 | 317 | |
320 | 318 | /* Can not set i_flags here - they get immediately overwritten |
321 | 319 | to zero by the VFS */ |
... | ... | @@ -1040,34 +1038,6 @@ |
1040 | 1038 | return 0; |
1041 | 1039 | } |
1042 | 1040 | |
1043 | -#ifdef CONFIG_CIFS_EXPERIMENTAL | |
1044 | -static int cifs_dnotify_thread(void *dummyarg) | |
1045 | -{ | |
1046 | - struct list_head *tmp; | |
1047 | - struct TCP_Server_Info *server; | |
1048 | - | |
1049 | - do { | |
1050 | - if (try_to_freeze()) | |
1051 | - continue; | |
1052 | - set_current_state(TASK_INTERRUPTIBLE); | |
1053 | - schedule_timeout(15*HZ); | |
1054 | - /* check if any stuck requests that need | |
1055 | - to be woken up and wakeq so the | |
1056 | - thread can wake up and error out */ | |
1057 | - read_lock(&cifs_tcp_ses_lock); | |
1058 | - list_for_each(tmp, &cifs_tcp_ses_list) { | |
1059 | - server = list_entry(tmp, struct TCP_Server_Info, | |
1060 | - tcp_ses_list); | |
1061 | - if (atomic_read(&server->inFlight)) | |
1062 | - wake_up_all(&server->response_q); | |
1063 | - } | |
1064 | - read_unlock(&cifs_tcp_ses_lock); | |
1065 | - } while (!kthread_should_stop()); | |
1066 | - | |
1067 | - return 0; | |
1068 | -} | |
1069 | -#endif | |
1070 | - | |
1071 | 1041 | static int __init |
1072 | 1042 | init_cifs(void) |
1073 | 1043 | { |
1074 | 1044 | |
... | ... | @@ -1144,21 +1114,8 @@ |
1144 | 1114 | goto out_unregister_dfs_key_type; |
1145 | 1115 | } |
1146 | 1116 | |
1147 | -#ifdef CONFIG_CIFS_EXPERIMENTAL | |
1148 | - dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd"); | |
1149 | - if (IS_ERR(dnotifyThread)) { | |
1150 | - rc = PTR_ERR(dnotifyThread); | |
1151 | - cERROR(1, ("error %d create dnotify thread", rc)); | |
1152 | - goto out_stop_oplock_thread; | |
1153 | - } | |
1154 | -#endif | |
1155 | - | |
1156 | 1117 | return 0; |
1157 | 1118 | |
1158 | -#ifdef CONFIG_CIFS_EXPERIMENTAL | |
1159 | - out_stop_oplock_thread: | |
1160 | -#endif | |
1161 | - kthread_stop(oplockThread); | |
1162 | 1119 | out_unregister_dfs_key_type: |
1163 | 1120 | #ifdef CONFIG_CIFS_DFS_UPCALL |
1164 | 1121 | unregister_key_type(&key_type_dns_resolver); |
... | ... | @@ -1196,9 +1153,6 @@ |
1196 | 1153 | cifs_destroy_inodecache(); |
1197 | 1154 | cifs_destroy_mids(); |
1198 | 1155 | cifs_destroy_request_bufs(); |
1199 | -#ifdef CONFIG_CIFS_EXPERIMENTAL | |
1200 | - kthread_stop(dnotifyThread); | |
1201 | -#endif | |
1202 | 1156 | kthread_stop(oplockThread); |
1203 | 1157 | } |
1204 | 1158 |
fs/cifs/cifsglob.h
... | ... | @@ -350,7 +350,7 @@ |
350 | 350 | bool invalidHandle:1; /* file closed via session abend */ |
351 | 351 | bool messageMode:1; /* for pipes: message vs byte mode */ |
352 | 352 | atomic_t wrtPending; /* handle in use - defer close */ |
353 | - struct semaphore fh_sem; /* prevents reopen race after dead ses*/ | |
353 | + struct mutex fh_mutex; /* prevents reopen race after dead ses*/ | |
354 | 354 | struct cifs_search_info srch_inf; |
355 | 355 | }; |
356 | 356 | |
... | ... | @@ -370,6 +370,7 @@ |
370 | 370 | bool clientCanCacheAll:1; /* read and writebehind oplock */ |
371 | 371 | bool oplockPending:1; |
372 | 372 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ |
373 | + u64 server_eof; /* current file size on server */ | |
373 | 374 | struct inode vfs_inode; |
374 | 375 | }; |
375 | 376 |
fs/cifs/cifspdu.h
... | ... | @@ -2163,7 +2163,7 @@ |
2163 | 2163 | __le32 Type; |
2164 | 2164 | __le64 DevMajor; |
2165 | 2165 | __le64 DevMinor; |
2166 | - __u64 UniqueId; | |
2166 | + __le64 UniqueId; | |
2167 | 2167 | __le64 Permissions; |
2168 | 2168 | __le64 Nlinks; |
2169 | 2169 | } __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ |
... | ... | @@ -2308,7 +2308,7 @@ |
2308 | 2308 | } __attribute__((packed)); |
2309 | 2309 | |
2310 | 2310 | struct file_internal_info { |
2311 | - __u64 UniqueId; /* inode number */ | |
2311 | + __le64 UniqueId; /* inode number */ | |
2312 | 2312 | } __attribute__((packed)); /* level 0x3ee */ |
2313 | 2313 | |
2314 | 2314 | struct file_mode_info { |
... | ... | @@ -2338,7 +2338,7 @@ |
2338 | 2338 | __le32 Type; |
2339 | 2339 | __le64 DevMajor; |
2340 | 2340 | __le64 DevMinor; |
2341 | - __u64 UniqueId; | |
2341 | + __le64 UniqueId; | |
2342 | 2342 | __le64 Permissions; |
2343 | 2343 | __le64 Nlinks; |
2344 | 2344 | char FileName[1]; |
... | ... | @@ -2386,7 +2386,7 @@ |
2386 | 2386 | __le32 FileNameLength; |
2387 | 2387 | __le32 EaSize; /* EA size */ |
2388 | 2388 | __le32 Reserved; |
2389 | - __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ | |
2389 | + __le64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ | |
2390 | 2390 | char FileName[1]; |
2391 | 2391 | } __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */ |
2392 | 2392 |
fs/cifs/cifssmb.c
... | ... | @@ -1626,6 +1626,8 @@ |
1626 | 1626 | int smb_hdr_len; |
1627 | 1627 | int resp_buf_type = 0; |
1628 | 1628 | |
1629 | + *nbytes = 0; | |
1630 | + | |
1629 | 1631 | cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count)); |
1630 | 1632 | |
1631 | 1633 | if (tcon->ses->capabilities & CAP_LARGE_FILES) { |
1632 | 1634 | |
... | ... | @@ -1682,11 +1684,9 @@ |
1682 | 1684 | cifs_stats_inc(&tcon->num_writes); |
1683 | 1685 | if (rc) { |
1684 | 1686 | cFYI(1, ("Send error Write2 = %d", rc)); |
1685 | - *nbytes = 0; | |
1686 | 1687 | } else if (resp_buf_type == 0) { |
1687 | 1688 | /* presumably this can not happen, but best to be safe */ |
1688 | 1689 | rc = -EIO; |
1689 | - *nbytes = 0; | |
1690 | 1690 | } else { |
1691 | 1691 | WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base; |
1692 | 1692 | *nbytes = le16_to_cpu(pSMBr->CountHigh); |
... | ... | @@ -3918,7 +3918,7 @@ |
3918 | 3918 | } |
3919 | 3919 | pfinfo = (struct file_internal_info *) |
3920 | 3920 | (data_offset + (char *) &pSMBr->hdr.Protocol); |
3921 | - *inode_number = pfinfo->UniqueId; | |
3921 | + *inode_number = le64_to_cpu(pfinfo->UniqueId); | |
3922 | 3922 | } |
3923 | 3923 | } |
3924 | 3924 | GetInodeNumOut: |
fs/cifs/connect.c
... | ... | @@ -2214,9 +2214,58 @@ |
2214 | 2214 | return rc; |
2215 | 2215 | } |
2216 | 2216 | |
2217 | +static void | |
2218 | +cleanup_volume_info(struct smb_vol **pvolume_info) | |
2219 | +{ | |
2220 | + struct smb_vol *volume_info; | |
2221 | + | |
2222 | + if (!pvolume_info && !*pvolume_info) | |
2223 | + return; | |
2224 | + | |
2225 | + volume_info = *pvolume_info; | |
2226 | + kzfree(volume_info->password); | |
2227 | + kfree(volume_info->UNC); | |
2228 | + kfree(volume_info->prepath); | |
2229 | + kfree(volume_info); | |
2230 | + *pvolume_info = NULL; | |
2231 | + return; | |
2232 | +} | |
2233 | + | |
2234 | +#ifdef CONFIG_CIFS_DFS_UPCALL | |
2235 | +/* build_path_to_root returns full path to root when | |
2236 | + * we do not have an exiting connection (tcon) */ | |
2237 | +static char * | |
2238 | +build_unc_path_to_root(const struct smb_vol *volume_info, | |
2239 | + const struct cifs_sb_info *cifs_sb) | |
2240 | +{ | |
2241 | + char *full_path; | |
2242 | + | |
2243 | + int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1); | |
2244 | + full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL); | |
2245 | + if (full_path == NULL) | |
2246 | + return ERR_PTR(-ENOMEM); | |
2247 | + | |
2248 | + strncpy(full_path, volume_info->UNC, unc_len); | |
2249 | + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { | |
2250 | + int i; | |
2251 | + for (i = 0; i < unc_len; i++) { | |
2252 | + if (full_path[i] == '\\') | |
2253 | + full_path[i] = '/'; | |
2254 | + } | |
2255 | + } | |
2256 | + | |
2257 | + if (cifs_sb->prepathlen) | |
2258 | + strncpy(full_path + unc_len, cifs_sb->prepath, | |
2259 | + cifs_sb->prepathlen); | |
2260 | + | |
2261 | + full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */ | |
2262 | + return full_path; | |
2263 | +} | |
2264 | +#endif | |
2265 | + | |
2217 | 2266 | int |
2218 | 2267 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, |
2219 | - char *mount_data, const char *devname) | |
2268 | + char *mount_data_global, const char *devname) | |
2220 | 2269 | { |
2221 | 2270 | int rc = 0; |
2222 | 2271 | int xid; |
... | ... | @@ -2225,6 +2274,13 @@ |
2225 | 2274 | struct cifsTconInfo *tcon = NULL; |
2226 | 2275 | struct TCP_Server_Info *srvTcp = NULL; |
2227 | 2276 | char *full_path; |
2277 | + char *mount_data = mount_data_global; | |
2278 | +#ifdef CONFIG_CIFS_DFS_UPCALL | |
2279 | + struct dfs_info3_param *referrals = NULL; | |
2280 | + unsigned int num_referrals = 0; | |
2281 | +try_mount_again: | |
2282 | +#endif | |
2283 | + full_path = NULL; | |
2228 | 2284 | |
2229 | 2285 | xid = GetXid(); |
2230 | 2286 | |
2231 | 2287 | |
... | ... | @@ -2371,11 +2427,9 @@ |
2371 | 2427 | } |
2372 | 2428 | } |
2373 | 2429 | |
2374 | - /* check for null share name ie connect to dfs root */ | |
2375 | 2430 | if ((strchr(volume_info->UNC + 3, '\\') == NULL) |
2376 | 2431 | && (strchr(volume_info->UNC + 3, '/') == NULL)) { |
2377 | - /* rc = connect_to_dfs_path(...) */ | |
2378 | - cFYI(1, ("DFS root not supported")); | |
2432 | + cERROR(1, ("Missing share name")); | |
2379 | 2433 | rc = -ENODEV; |
2380 | 2434 | goto mount_fail_check; |
2381 | 2435 | } else { |
... | ... | @@ -2392,7 +2446,7 @@ |
2392 | 2446 | } |
2393 | 2447 | } |
2394 | 2448 | if (rc) |
2395 | - goto mount_fail_check; | |
2449 | + goto remote_path_check; | |
2396 | 2450 | tcon->seal = volume_info->seal; |
2397 | 2451 | write_lock(&cifs_tcp_ses_lock); |
2398 | 2452 | list_add(&tcon->tcon_list, &pSesInfo->tcon_list); |
... | ... | @@ -2417,19 +2471,9 @@ |
2417 | 2471 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ |
2418 | 2472 | sb->s_time_gran = 100; |
2419 | 2473 | |
2420 | -mount_fail_check: | |
2421 | - /* on error free sesinfo and tcon struct if needed */ | |
2422 | - if (rc) { | |
2423 | - /* If find_unc succeeded then rc == 0 so we can not end */ | |
2424 | - /* up accidently freeing someone elses tcon struct */ | |
2425 | - if (tcon) | |
2426 | - cifs_put_tcon(tcon); | |
2427 | - else if (pSesInfo) | |
2428 | - cifs_put_smb_ses(pSesInfo); | |
2429 | - else | |
2430 | - cifs_put_tcp_session(srvTcp); | |
2431 | - goto out; | |
2432 | - } | |
2474 | + if (rc) | |
2475 | + goto remote_path_check; | |
2476 | + | |
2433 | 2477 | cifs_sb->tcon = tcon; |
2434 | 2478 | |
2435 | 2479 | /* do not care if following two calls succeed - informational */ |
... | ... | @@ -2461,7 +2505,9 @@ |
2461 | 2505 | cifs_sb->rsize = min(cifs_sb->rsize, |
2462 | 2506 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); |
2463 | 2507 | |
2464 | - if (!rc && cifs_sb->prepathlen) { | |
2508 | +remote_path_check: | |
2509 | + /* check if a whole path (including prepath) is not remote */ | |
2510 | + if (!rc && cifs_sb->prepathlen && tcon) { | |
2465 | 2511 | /* build_path_to_root works only when we have a valid tcon */ |
2466 | 2512 | full_path = cifs_build_path_to_root(cifs_sb); |
2467 | 2513 | if (full_path == NULL) { |
2468 | 2514 | |
2469 | 2515 | |
... | ... | @@ -2469,31 +2515,79 @@ |
2469 | 2515 | goto mount_fail_check; |
2470 | 2516 | } |
2471 | 2517 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); |
2472 | - if (rc) { | |
2473 | - cERROR(1, ("Path %s in not accessible: %d", | |
2474 | - full_path, rc)); | |
2518 | + if (rc != -EREMOTE) { | |
2475 | 2519 | kfree(full_path); |
2476 | 2520 | goto mount_fail_check; |
2477 | 2521 | } |
2478 | 2522 | kfree(full_path); |
2479 | 2523 | } |
2480 | 2524 | |
2525 | + /* get referral if needed */ | |
2526 | + if (rc == -EREMOTE) { | |
2527 | +#ifdef CONFIG_CIFS_DFS_UPCALL | |
2528 | + /* convert forward to back slashes in prepath here if needed */ | |
2529 | + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) | |
2530 | + convert_delimiter(cifs_sb->prepath, | |
2531 | + CIFS_DIR_SEP(cifs_sb)); | |
2532 | + full_path = build_unc_path_to_root(volume_info, cifs_sb); | |
2533 | + if (IS_ERR(full_path)) { | |
2534 | + rc = PTR_ERR(full_path); | |
2535 | + goto mount_fail_check; | |
2536 | + } | |
2537 | + | |
2538 | + cFYI(1, ("Getting referral for: %s", full_path)); | |
2539 | + rc = get_dfs_path(xid, pSesInfo , full_path + 1, | |
2540 | + cifs_sb->local_nls, &num_referrals, &referrals, | |
2541 | + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | |
2542 | + if (!rc && num_referrals > 0) { | |
2543 | + char *fake_devname = NULL; | |
2544 | + | |
2545 | + if (mount_data != mount_data_global) | |
2546 | + kfree(mount_data); | |
2547 | + mount_data = cifs_compose_mount_options( | |
2548 | + cifs_sb->mountdata, full_path + 1, | |
2549 | + referrals, &fake_devname); | |
2550 | + kfree(fake_devname); | |
2551 | + free_dfs_info_array(referrals, num_referrals); | |
2552 | + | |
2553 | + if (tcon) | |
2554 | + cifs_put_tcon(tcon); | |
2555 | + else if (pSesInfo) | |
2556 | + cifs_put_smb_ses(pSesInfo); | |
2557 | + | |
2558 | + cleanup_volume_info(&volume_info); | |
2559 | + FreeXid(xid); | |
2560 | + kfree(full_path); | |
2561 | + goto try_mount_again; | |
2562 | + } | |
2563 | +#else /* No DFS support, return error on mount */ | |
2564 | + rc = -EOPNOTSUPP; | |
2565 | +#endif | |
2566 | + } | |
2567 | + | |
2568 | +mount_fail_check: | |
2569 | + /* on error free sesinfo and tcon struct if needed */ | |
2570 | + if (rc) { | |
2571 | + if (mount_data != mount_data_global) | |
2572 | + kfree(mount_data); | |
2573 | + /* If find_unc succeeded then rc == 0 so we can not end */ | |
2574 | + /* up accidently freeing someone elses tcon struct */ | |
2575 | + if (tcon) | |
2576 | + cifs_put_tcon(tcon); | |
2577 | + else if (pSesInfo) | |
2578 | + cifs_put_smb_ses(pSesInfo); | |
2579 | + else | |
2580 | + cifs_put_tcp_session(srvTcp); | |
2581 | + goto out; | |
2582 | + } | |
2583 | + | |
2481 | 2584 | /* volume_info->password is freed above when existing session found |
2482 | 2585 | (in which case it is not needed anymore) but when new sesion is created |
2483 | 2586 | the password ptr is put in the new session structure (in which case the |
2484 | 2587 | password will be freed at unmount time) */ |
2485 | 2588 | out: |
2486 | 2589 | /* zero out password before freeing */ |
2487 | - if (volume_info) { | |
2488 | - if (volume_info->password != NULL) { | |
2489 | - memset(volume_info->password, 0, | |
2490 | - strlen(volume_info->password)); | |
2491 | - kfree(volume_info->password); | |
2492 | - } | |
2493 | - kfree(volume_info->UNC); | |
2494 | - kfree(volume_info->prepath); | |
2495 | - kfree(volume_info); | |
2496 | - } | |
2590 | + cleanup_volume_info(&volume_info); | |
2497 | 2591 | FreeXid(xid); |
2498 | 2592 | return rc; |
2499 | 2593 | } |
... | ... | @@ -2673,8 +2767,7 @@ |
2673 | 2767 | /* We look for obvious messed up bcc or strings in response so we do not go off |
2674 | 2768 | the end since (at least) WIN2K and Windows XP have a major bug in not null |
2675 | 2769 | terminating last Unicode string in response */ |
2676 | - if (ses->serverOS) | |
2677 | - kfree(ses->serverOS); | |
2770 | + kfree(ses->serverOS); | |
2678 | 2771 | ses->serverOS = kzalloc(2 * (len + 1), |
2679 | 2772 | GFP_KERNEL); |
2680 | 2773 | if (ses->serverOS == NULL) |
... | ... | @@ -2710,8 +2803,7 @@ |
2710 | 2803 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); |
2711 | 2804 | /* last string is not always null terminated |
2712 | 2805 | (for e.g. for Windows XP & 2000) */ |
2713 | - if (ses->serverDomain) | |
2714 | - kfree(ses->serverDomain); | |
2806 | + kfree(ses->serverDomain); | |
2715 | 2807 | ses->serverDomain = |
2716 | 2808 | kzalloc(2*(len+1), |
2717 | 2809 | GFP_KERNEL); |
... | ... | @@ -2725,8 +2817,7 @@ |
2725 | 2817 | ses->serverDomain[1+(2*len)] = 0; |
2726 | 2818 | } else { /* else no more room so create |
2727 | 2819 | dummy domain string */ |
2728 | - if (ses->serverDomain) | |
2729 | - kfree(ses->serverDomain); | |
2820 | + kfree(ses->serverDomain); | |
2730 | 2821 | ses->serverDomain = |
2731 | 2822 | kzalloc(2, GFP_KERNEL); |
2732 | 2823 | } |
... | ... | @@ -2772,8 +2863,7 @@ |
2772 | 2863 | bcc_ptr++; |
2773 | 2864 | |
2774 | 2865 | len = strnlen(bcc_ptr, 1024); |
2775 | - if (ses->serverDomain) | |
2776 | - kfree(ses->serverDomain); | |
2866 | + kfree(ses->serverDomain); | |
2777 | 2867 | ses->serverDomain = kzalloc(len + 1, |
2778 | 2868 | GFP_KERNEL); |
2779 | 2869 | if (ses->serverDomain == NULL) |
... | ... | @@ -3013,8 +3103,7 @@ |
3013 | 3103 | /* We look for obvious messed up bcc or strings in response so we do not go off |
3014 | 3104 | the end since (at least) WIN2K and Windows XP have a major bug in not null |
3015 | 3105 | terminating last Unicode string in response */ |
3016 | - if (ses->serverOS) | |
3017 | - kfree(ses->serverOS); | |
3106 | + kfree(ses->serverOS); | |
3018 | 3107 | ses->serverOS = |
3019 | 3108 | kzalloc(2 * (len + 1), GFP_KERNEL); |
3020 | 3109 | cifs_strfromUCS_le(ses->serverOS, |
... | ... | @@ -3086,8 +3175,7 @@ |
3086 | 3175 | if (((long) bcc_ptr + len) - (long) |
3087 | 3176 | pByteArea(smb_buffer_response) |
3088 | 3177 | <= BCC(smb_buffer_response)) { |
3089 | - if (ses->serverOS) | |
3090 | - kfree(ses->serverOS); | |
3178 | + kfree(ses->serverOS); | |
3091 | 3179 | ses->serverOS = |
3092 | 3180 | kzalloc(len + 1, |
3093 | 3181 | GFP_KERNEL); |
... | ... | @@ -3414,8 +3502,7 @@ |
3414 | 3502 | /* We look for obvious messed up bcc or strings in response so we do not go off |
3415 | 3503 | the end since (at least) WIN2K and Windows XP have a major bug in not null |
3416 | 3504 | terminating last Unicode string in response */ |
3417 | - if (ses->serverOS) | |
3418 | - kfree(ses->serverOS); | |
3505 | + kfree(ses->serverOS); | |
3419 | 3506 | ses->serverOS = |
3420 | 3507 | kzalloc(2 * (len + 1), GFP_KERNEL); |
3421 | 3508 | cifs_strfromUCS_le(ses->serverOS, |
... | ... | @@ -3448,8 +3535,7 @@ |
3448 | 3535 | if (remaining_words > 0) { |
3449 | 3536 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); |
3450 | 3537 | /* last string not always null terminated (e.g. for Windows XP & 2000) */ |
3451 | - if (ses->serverDomain) | |
3452 | - kfree(ses->serverDomain); | |
3538 | + kfree(ses->serverDomain); | |
3453 | 3539 | ses->serverDomain = |
3454 | 3540 | kzalloc(2 * |
3455 | 3541 | (len + |
3456 | 3542 | |
... | ... | @@ -3476,13 +3562,11 @@ |
3476 | 3562 | = 0; |
3477 | 3563 | } /* else no more room so create dummy domain string */ |
3478 | 3564 | else { |
3479 | - if (ses->serverDomain) | |
3480 | - kfree(ses->serverDomain); | |
3565 | + kfree(ses->serverDomain); | |
3481 | 3566 | ses->serverDomain = kzalloc(2,GFP_KERNEL); |
3482 | 3567 | } |
3483 | 3568 | } else { /* no room so create dummy domain and NOS string */ |
3484 | - if (ses->serverDomain) | |
3485 | - kfree(ses->serverDomain); | |
3569 | + kfree(ses->serverDomain); | |
3486 | 3570 | ses->serverDomain = kzalloc(2, GFP_KERNEL); |
3487 | 3571 | kfree(ses->serverNOS); |
3488 | 3572 | ses->serverNOS = kzalloc(2, GFP_KERNEL); |
... | ... | @@ -3492,8 +3576,7 @@ |
3492 | 3576 | if (((long) bcc_ptr + len) - |
3493 | 3577 | (long) pByteArea(smb_buffer_response) |
3494 | 3578 | <= BCC(smb_buffer_response)) { |
3495 | - if (ses->serverOS) | |
3496 | - kfree(ses->serverOS); | |
3579 | + kfree(ses->serverOS); | |
3497 | 3580 | ses->serverOS = kzalloc(len + 1, GFP_KERNEL); |
3498 | 3581 | strncpy(ses->serverOS,bcc_ptr, len); |
3499 | 3582 | |
... | ... | @@ -3512,8 +3595,7 @@ |
3512 | 3595 | bcc_ptr++; |
3513 | 3596 | |
3514 | 3597 | len = strnlen(bcc_ptr, 1024); |
3515 | - if (ses->serverDomain) | |
3516 | - kfree(ses->serverDomain); | |
3598 | + kfree(ses->serverDomain); | |
3517 | 3599 | ses->serverDomain = |
3518 | 3600 | kzalloc(len+1, |
3519 | 3601 | GFP_KERNEL); |
3520 | 3602 | |
... | ... | @@ -3674,16 +3756,15 @@ |
3674 | 3756 | BCC(smb_buffer_response)) { |
3675 | 3757 | kfree(tcon->nativeFileSystem); |
3676 | 3758 | tcon->nativeFileSystem = |
3677 | - kzalloc(2*(length + 1), GFP_KERNEL); | |
3678 | - if (tcon->nativeFileSystem) | |
3759 | + kzalloc((4 * length) + 2, GFP_KERNEL); | |
3760 | + if (tcon->nativeFileSystem) { | |
3679 | 3761 | cifs_strfromUCS_le( |
3680 | 3762 | tcon->nativeFileSystem, |
3681 | 3763 | (__le16 *) bcc_ptr, |
3682 | 3764 | length, nls_codepage); |
3683 | - bcc_ptr += 2 * length; | |
3684 | - bcc_ptr[0] = 0; /* null terminate the string */ | |
3685 | - bcc_ptr[1] = 0; | |
3686 | - bcc_ptr += 2; | |
3765 | + cFYI(1, ("nativeFileSystem=%s", | |
3766 | + tcon->nativeFileSystem)); | |
3767 | + } | |
3687 | 3768 | } |
3688 | 3769 | /* else do not bother copying these information fields*/ |
3689 | 3770 | } else { |
fs/cifs/dir.c
... | ... | @@ -129,12 +129,62 @@ |
129 | 129 | return full_path; |
130 | 130 | } |
131 | 131 | |
132 | +static void | |
133 | +cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, | |
134 | + struct cifsTconInfo *tcon, bool write_only) | |
135 | +{ | |
136 | + int oplock = 0; | |
137 | + struct cifsFileInfo *pCifsFile; | |
138 | + struct cifsInodeInfo *pCifsInode; | |
139 | + | |
140 | + pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | |
141 | + | |
142 | + if (pCifsFile == NULL) | |
143 | + return; | |
144 | + | |
145 | + if (oplockEnabled) | |
146 | + oplock = REQ_OPLOCK; | |
147 | + | |
148 | + pCifsFile->netfid = fileHandle; | |
149 | + pCifsFile->pid = current->tgid; | |
150 | + pCifsFile->pInode = newinode; | |
151 | + pCifsFile->invalidHandle = false; | |
152 | + pCifsFile->closePend = false; | |
153 | + mutex_init(&pCifsFile->fh_mutex); | |
154 | + mutex_init(&pCifsFile->lock_mutex); | |
155 | + INIT_LIST_HEAD(&pCifsFile->llist); | |
156 | + atomic_set(&pCifsFile->wrtPending, 0); | |
157 | + | |
158 | + /* set the following in open now | |
159 | + pCifsFile->pfile = file; */ | |
160 | + write_lock(&GlobalSMBSeslock); | |
161 | + list_add(&pCifsFile->tlist, &tcon->openFileList); | |
162 | + pCifsInode = CIFS_I(newinode); | |
163 | + if (pCifsInode) { | |
164 | + /* if readable file instance put first in list*/ | |
165 | + if (write_only) | |
166 | + list_add_tail(&pCifsFile->flist, | |
167 | + &pCifsInode->openFileList); | |
168 | + else | |
169 | + list_add(&pCifsFile->flist, &pCifsInode->openFileList); | |
170 | + | |
171 | + if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | |
172 | + pCifsInode->clientCanCacheAll = true; | |
173 | + pCifsInode->clientCanCacheRead = true; | |
174 | + cFYI(1, ("Exclusive Oplock inode %p", newinode)); | |
175 | + } else if ((oplock & 0xF) == OPLOCK_READ) | |
176 | + pCifsInode->clientCanCacheRead = true; | |
177 | + } | |
178 | + write_unlock(&GlobalSMBSeslock); | |
179 | +} | |
180 | + | |
132 | 181 | int cifs_posix_open(char *full_path, struct inode **pinode, |
133 | 182 | struct super_block *sb, int mode, int oflags, |
134 | 183 | int *poplock, __u16 *pnetfid, int xid) |
135 | 184 | { |
136 | 185 | int rc; |
137 | 186 | __u32 oplock; |
187 | + bool write_only = false; | |
138 | 188 | FILE_UNIX_BASIC_INFO *presp_data; |
139 | 189 | __u32 posix_flags = 0; |
140 | 190 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
... | ... | @@ -172,6 +222,8 @@ |
172 | 222 | if (oflags & O_DIRECT) |
173 | 223 | posix_flags |= SMB_O_DIRECT; |
174 | 224 | |
225 | + if (!(oflags & FMODE_READ)) | |
226 | + write_only = true; | |
175 | 227 | |
176 | 228 | rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, |
177 | 229 | pnetfid, presp_data, &oplock, full_path, |
... | ... | @@ -187,8 +239,10 @@ |
187 | 239 | if (!pinode) |
188 | 240 | goto posix_open_ret; /* caller does not need info */ |
189 | 241 | |
190 | - if (*pinode == NULL) | |
191 | - *pinode = cifs_new_inode(sb, &presp_data->UniqueId); | |
242 | + if (*pinode == NULL) { | |
243 | + __u64 unique_id = le64_to_cpu(presp_data->UniqueId); | |
244 | + *pinode = cifs_new_inode(sb, &unique_id); | |
245 | + } | |
192 | 246 | /* else an inode was passed in. Update its info, don't create one */ |
193 | 247 | |
194 | 248 | /* We do not need to close the file if new_inode fails since |
... | ... | @@ -198,6 +252,8 @@ |
198 | 252 | |
199 | 253 | posix_fill_in_inode(*pinode, presp_data, 1); |
200 | 254 | |
255 | + cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only); | |
256 | + | |
201 | 257 | posix_open_ret: |
202 | 258 | kfree(presp_data); |
203 | 259 | return rc; |
... | ... | @@ -239,7 +295,6 @@ |
239 | 295 | char *full_path = NULL; |
240 | 296 | FILE_ALL_INFO *buf = NULL; |
241 | 297 | struct inode *newinode = NULL; |
242 | - struct cifsInodeInfo *pCifsInode; | |
243 | 298 | int disposition = FILE_OVERWRITE_IF; |
244 | 299 | bool write_only = false; |
245 | 300 | |
... | ... | @@ -410,44 +465,8 @@ |
410 | 465 | /* mknod case - do not leave file open */ |
411 | 466 | CIFSSMBClose(xid, tcon, fileHandle); |
412 | 467 | } else if (newinode) { |
413 | - struct cifsFileInfo *pCifsFile = | |
414 | - kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | |
415 | - | |
416 | - if (pCifsFile == NULL) | |
417 | - goto cifs_create_out; | |
418 | - pCifsFile->netfid = fileHandle; | |
419 | - pCifsFile->pid = current->tgid; | |
420 | - pCifsFile->pInode = newinode; | |
421 | - pCifsFile->invalidHandle = false; | |
422 | - pCifsFile->closePend = false; | |
423 | - init_MUTEX(&pCifsFile->fh_sem); | |
424 | - mutex_init(&pCifsFile->lock_mutex); | |
425 | - INIT_LIST_HEAD(&pCifsFile->llist); | |
426 | - atomic_set(&pCifsFile->wrtPending, 0); | |
427 | - | |
428 | - /* set the following in open now | |
429 | - pCifsFile->pfile = file; */ | |
430 | - write_lock(&GlobalSMBSeslock); | |
431 | - list_add(&pCifsFile->tlist, &tcon->openFileList); | |
432 | - pCifsInode = CIFS_I(newinode); | |
433 | - if (pCifsInode) { | |
434 | - /* if readable file instance put first in list*/ | |
435 | - if (write_only) { | |
436 | - list_add_tail(&pCifsFile->flist, | |
437 | - &pCifsInode->openFileList); | |
438 | - } else { | |
439 | - list_add(&pCifsFile->flist, | |
440 | - &pCifsInode->openFileList); | |
441 | - } | |
442 | - if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | |
443 | - pCifsInode->clientCanCacheAll = true; | |
444 | - pCifsInode->clientCanCacheRead = true; | |
445 | - cFYI(1, ("Exclusive Oplock inode %p", | |
446 | - newinode)); | |
447 | - } else if ((oplock & 0xF) == OPLOCK_READ) | |
448 | - pCifsInode->clientCanCacheRead = true; | |
449 | - } | |
450 | - write_unlock(&GlobalSMBSeslock); | |
468 | + cifs_fill_fileinfo(newinode, fileHandle, | |
469 | + cifs_sb->tcon, write_only); | |
451 | 470 | } |
452 | 471 | cifs_create_out: |
453 | 472 | kfree(buf); |
454 | 473 | |
455 | 474 | |
... | ... | @@ -580,17 +599,21 @@ |
580 | 599 | return rc; |
581 | 600 | } |
582 | 601 | |
583 | - | |
584 | 602 | struct dentry * |
585 | 603 | cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, |
586 | 604 | struct nameidata *nd) |
587 | 605 | { |
588 | 606 | int xid; |
589 | 607 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ |
608 | + int oplock = 0; | |
609 | + int mode; | |
610 | + __u16 fileHandle = 0; | |
611 | + bool posix_open = false; | |
590 | 612 | struct cifs_sb_info *cifs_sb; |
591 | 613 | struct cifsTconInfo *pTcon; |
592 | 614 | struct inode *newInode = NULL; |
593 | 615 | char *full_path = NULL; |
616 | + struct file *filp; | |
594 | 617 | |
595 | 618 | xid = GetXid(); |
596 | 619 | |
597 | 620 | |
... | ... | @@ -632,12 +655,37 @@ |
632 | 655 | } |
633 | 656 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); |
634 | 657 | |
635 | - if (pTcon->unix_ext) | |
636 | - rc = cifs_get_inode_info_unix(&newInode, full_path, | |
637 | - parent_dir_inode->i_sb, xid); | |
638 | - else | |
658 | + if (pTcon->unix_ext) { | |
659 | + if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && | |
660 | + (nd->flags & LOOKUP_OPEN)) { | |
661 | + if (!((nd->intent.open.flags & O_CREAT) && | |
662 | + (nd->intent.open.flags & O_EXCL))) { | |
663 | + mode = nd->intent.open.create_mode & | |
664 | + ~current_umask(); | |
665 | + rc = cifs_posix_open(full_path, &newInode, | |
666 | + parent_dir_inode->i_sb, mode, | |
667 | + nd->intent.open.flags, &oplock, | |
668 | + &fileHandle, xid); | |
669 | + /* | |
670 | + * This code works around a bug in | |
671 | + * samba posix open in samba versions 3.3.1 | |
672 | + * and earlier where create works | |
673 | + * but open fails with invalid parameter. | |
674 | + * If either of these error codes are | |
675 | + * returned, follow the normal lookup. | |
676 | + * Otherwise, the error during posix open | |
677 | + * is handled. | |
678 | + */ | |
679 | + if ((rc != -EINVAL) && (rc != -EOPNOTSUPP)) | |
680 | + posix_open = true; | |
681 | + } | |
682 | + } | |
683 | + if (!posix_open) | |
684 | + rc = cifs_get_inode_info_unix(&newInode, full_path, | |
685 | + parent_dir_inode->i_sb, xid); | |
686 | + } else | |
639 | 687 | rc = cifs_get_inode_info(&newInode, full_path, NULL, |
640 | - parent_dir_inode->i_sb, xid, NULL); | |
688 | + parent_dir_inode->i_sb, xid, NULL); | |
641 | 689 | |
642 | 690 | if ((rc == 0) && (newInode != NULL)) { |
643 | 691 | if (pTcon->nocase) |
... | ... | @@ -645,7 +693,8 @@ |
645 | 693 | else |
646 | 694 | direntry->d_op = &cifs_dentry_ops; |
647 | 695 | d_add(direntry, newInode); |
648 | - | |
696 | + if (posix_open) | |
697 | + filp = lookup_instantiate_filp(nd, direntry, NULL); | |
649 | 698 | /* since paths are not looked up by component - the parent |
650 | 699 | directories are presumed to be good here */ |
651 | 700 | renew_parental_timestamps(direntry); |
fs/cifs/dns_resolve.c
fs/cifs/file.c
... | ... | @@ -46,7 +46,7 @@ |
46 | 46 | memset(private_data, 0, sizeof(struct cifsFileInfo)); |
47 | 47 | private_data->netfid = netfid; |
48 | 48 | private_data->pid = current->tgid; |
49 | - init_MUTEX(&private_data->fh_sem); | |
49 | + mutex_init(&private_data->fh_mutex); | |
50 | 50 | mutex_init(&private_data->lock_mutex); |
51 | 51 | INIT_LIST_HEAD(&private_data->llist); |
52 | 52 | private_data->pfile = file; /* needed for writepage */ |
53 | 53 | |
54 | 54 | |
55 | 55 | |
56 | 56 | |
57 | 57 | |
... | ... | @@ -284,36 +284,33 @@ |
284 | 284 | cifs_sb = CIFS_SB(inode->i_sb); |
285 | 285 | tcon = cifs_sb->tcon; |
286 | 286 | |
287 | - if (file->f_flags & O_CREAT) { | |
288 | - /* search inode for this file and fill in file->private_data */ | |
289 | - pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | |
290 | - read_lock(&GlobalSMBSeslock); | |
291 | - list_for_each(tmp, &pCifsInode->openFileList) { | |
292 | - pCifsFile = list_entry(tmp, struct cifsFileInfo, | |
293 | - flist); | |
294 | - if ((pCifsFile->pfile == NULL) && | |
295 | - (pCifsFile->pid == current->tgid)) { | |
296 | - /* mode set in cifs_create */ | |
287 | + /* search inode for this file and fill in file->private_data */ | |
288 | + pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | |
289 | + read_lock(&GlobalSMBSeslock); | |
290 | + list_for_each(tmp, &pCifsInode->openFileList) { | |
291 | + pCifsFile = list_entry(tmp, struct cifsFileInfo, | |
292 | + flist); | |
293 | + if ((pCifsFile->pfile == NULL) && | |
294 | + (pCifsFile->pid == current->tgid)) { | |
295 | + /* mode set in cifs_create */ | |
297 | 296 | |
298 | - /* needed for writepage */ | |
299 | - pCifsFile->pfile = file; | |
297 | + /* needed for writepage */ | |
298 | + pCifsFile->pfile = file; | |
300 | 299 | |
301 | - file->private_data = pCifsFile; | |
302 | - break; | |
303 | - } | |
300 | + file->private_data = pCifsFile; | |
301 | + break; | |
304 | 302 | } |
305 | - read_unlock(&GlobalSMBSeslock); | |
306 | - if (file->private_data != NULL) { | |
307 | - rc = 0; | |
308 | - FreeXid(xid); | |
309 | - return rc; | |
310 | - } else { | |
311 | - if (file->f_flags & O_EXCL) | |
312 | - cERROR(1, ("could not find file instance for " | |
313 | - "new file %p", file)); | |
314 | - } | |
315 | 303 | } |
304 | + read_unlock(&GlobalSMBSeslock); | |
316 | 305 | |
306 | + if (file->private_data != NULL) { | |
307 | + rc = 0; | |
308 | + FreeXid(xid); | |
309 | + return rc; | |
310 | + } else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL)) | |
311 | + cERROR(1, ("could not find file instance for " | |
312 | + "new file %p", file)); | |
313 | + | |
317 | 314 | full_path = build_path_from_dentry(file->f_path.dentry); |
318 | 315 | if (full_path == NULL) { |
319 | 316 | FreeXid(xid); |
320 | 317 | |
... | ... | @@ -500,9 +497,9 @@ |
500 | 497 | return -EBADF; |
501 | 498 | |
502 | 499 | xid = GetXid(); |
503 | - down(&pCifsFile->fh_sem); | |
500 | + mutex_unlock(&pCifsFile->fh_mutex); | |
504 | 501 | if (!pCifsFile->invalidHandle) { |
505 | - up(&pCifsFile->fh_sem); | |
502 | + mutex_lock(&pCifsFile->fh_mutex); | |
506 | 503 | FreeXid(xid); |
507 | 504 | return 0; |
508 | 505 | } |
... | ... | @@ -533,7 +530,7 @@ |
533 | 530 | if (full_path == NULL) { |
534 | 531 | rc = -ENOMEM; |
535 | 532 | reopen_error_exit: |
536 | - up(&pCifsFile->fh_sem); | |
533 | + mutex_lock(&pCifsFile->fh_mutex); | |
537 | 534 | FreeXid(xid); |
538 | 535 | return rc; |
539 | 536 | } |
540 | 537 | |
... | ... | @@ -575,14 +572,14 @@ |
575 | 572 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
576 | 573 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
577 | 574 | if (rc) { |
578 | - up(&pCifsFile->fh_sem); | |
575 | + mutex_lock(&pCifsFile->fh_mutex); | |
579 | 576 | cFYI(1, ("cifs_open returned 0x%x", rc)); |
580 | 577 | cFYI(1, ("oplock: %d", oplock)); |
581 | 578 | } else { |
582 | 579 | reopen_success: |
583 | 580 | pCifsFile->netfid = netfid; |
584 | 581 | pCifsFile->invalidHandle = false; |
585 | - up(&pCifsFile->fh_sem); | |
582 | + mutex_lock(&pCifsFile->fh_mutex); | |
586 | 583 | pCifsInode = CIFS_I(inode); |
587 | 584 | if (pCifsInode) { |
588 | 585 | if (can_flush) { |
... | ... | @@ -971,6 +968,40 @@ |
971 | 968 | return rc; |
972 | 969 | } |
973 | 970 | |
971 | +/* | |
972 | + * Set the timeout on write requests past EOF. For some servers (Windows) | |
973 | + * these calls can be very long. | |
974 | + * | |
975 | + * If we're writing >10M past the EOF we give a 180s timeout. Anything less | |
976 | + * than that gets a 45s timeout. Writes not past EOF get 15s timeouts. | |
977 | + * The 10M cutoff is totally arbitrary. A better scheme for this would be | |
978 | + * welcome if someone wants to suggest one. | |
979 | + * | |
980 | + * We may be able to do a better job with this if there were some way to | |
981 | + * declare that a file should be sparse. | |
982 | + */ | |
983 | +static int | |
984 | +cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset) | |
985 | +{ | |
986 | + if (offset <= cifsi->server_eof) | |
987 | + return CIFS_STD_OP; | |
988 | + else if (offset > (cifsi->server_eof + (10 * 1024 * 1024))) | |
989 | + return CIFS_VLONG_OP; | |
990 | + else | |
991 | + return CIFS_LONG_OP; | |
992 | +} | |
993 | + | |
994 | +/* update the file size (if needed) after a write */ | |
995 | +static void | |
996 | +cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, | |
997 | + unsigned int bytes_written) | |
998 | +{ | |
999 | + loff_t end_of_write = offset + bytes_written; | |
1000 | + | |
1001 | + if (end_of_write > cifsi->server_eof) | |
1002 | + cifsi->server_eof = end_of_write; | |
1003 | +} | |
1004 | + | |
974 | 1005 | ssize_t cifs_user_write(struct file *file, const char __user *write_data, |
975 | 1006 | size_t write_size, loff_t *poffset) |
976 | 1007 | { |
... | ... | @@ -981,6 +1012,7 @@ |
981 | 1012 | struct cifsTconInfo *pTcon; |
982 | 1013 | int xid, long_op; |
983 | 1014 | struct cifsFileInfo *open_file; |
1015 | + struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode); | |
984 | 1016 | |
985 | 1017 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
986 | 1018 | |
... | ... | @@ -1000,11 +1032,7 @@ |
1000 | 1032 | |
1001 | 1033 | xid = GetXid(); |
1002 | 1034 | |
1003 | - if (*poffset > file->f_path.dentry->d_inode->i_size) | |
1004 | - long_op = CIFS_VLONG_OP; /* writes past EOF take long time */ | |
1005 | - else | |
1006 | - long_op = CIFS_LONG_OP; | |
1007 | - | |
1035 | + long_op = cifs_write_timeout(cifsi, *poffset); | |
1008 | 1036 | for (total_written = 0; write_size > total_written; |
1009 | 1037 | total_written += bytes_written) { |
1010 | 1038 | rc = -EAGAIN; |
1011 | 1039 | |
... | ... | @@ -1048,8 +1076,10 @@ |
1048 | 1076 | FreeXid(xid); |
1049 | 1077 | return rc; |
1050 | 1078 | } |
1051 | - } else | |
1079 | + } else { | |
1080 | + cifs_update_eof(cifsi, *poffset, bytes_written); | |
1052 | 1081 | *poffset += bytes_written; |
1082 | + } | |
1053 | 1083 | long_op = CIFS_STD_OP; /* subsequent writes fast - |
1054 | 1084 | 15 seconds is plenty */ |
1055 | 1085 | } |
... | ... | @@ -1085,6 +1115,7 @@ |
1085 | 1115 | struct cifsTconInfo *pTcon; |
1086 | 1116 | int xid, long_op; |
1087 | 1117 | struct cifsFileInfo *open_file; |
1118 | + struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode); | |
1088 | 1119 | |
1089 | 1120 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
1090 | 1121 | |
... | ... | @@ -1099,11 +1130,7 @@ |
1099 | 1130 | |
1100 | 1131 | xid = GetXid(); |
1101 | 1132 | |
1102 | - if (*poffset > file->f_path.dentry->d_inode->i_size) | |
1103 | - long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */ | |
1104 | - else | |
1105 | - long_op = CIFS_LONG_OP; | |
1106 | - | |
1133 | + long_op = cifs_write_timeout(cifsi, *poffset); | |
1107 | 1134 | for (total_written = 0; write_size > total_written; |
1108 | 1135 | total_written += bytes_written) { |
1109 | 1136 | rc = -EAGAIN; |
1110 | 1137 | |
... | ... | @@ -1166,8 +1193,10 @@ |
1166 | 1193 | FreeXid(xid); |
1167 | 1194 | return rc; |
1168 | 1195 | } |
1169 | - } else | |
1196 | + } else { | |
1197 | + cifs_update_eof(cifsi, *poffset, bytes_written); | |
1170 | 1198 | *poffset += bytes_written; |
1199 | + } | |
1171 | 1200 | long_op = CIFS_STD_OP; /* subsequent writes fast - |
1172 | 1201 | 15 seconds is plenty */ |
1173 | 1202 | } |
1174 | 1203 | |
... | ... | @@ -1380,11 +1409,12 @@ |
1380 | 1409 | int nr_pages; |
1381 | 1410 | __u64 offset = 0; |
1382 | 1411 | struct cifsFileInfo *open_file; |
1412 | + struct cifsInodeInfo *cifsi = CIFS_I(mapping->host); | |
1383 | 1413 | struct page *page; |
1384 | 1414 | struct pagevec pvec; |
1385 | 1415 | int rc = 0; |
1386 | 1416 | int scanned = 0; |
1387 | - int xid; | |
1417 | + int xid, long_op; | |
1388 | 1418 | |
1389 | 1419 | cifs_sb = CIFS_SB(mapping->host->i_sb); |
1390 | 1420 | |
1391 | 1421 | |
1392 | 1422 | |
... | ... | @@ -1528,12 +1558,15 @@ |
1528 | 1558 | cERROR(1, ("No writable handles for inode")); |
1529 | 1559 | rc = -EBADF; |
1530 | 1560 | } else { |
1561 | + long_op = cifs_write_timeout(cifsi, offset); | |
1531 | 1562 | rc = CIFSSMBWrite2(xid, cifs_sb->tcon, |
1532 | 1563 | open_file->netfid, |
1533 | 1564 | bytes_to_write, offset, |
1534 | 1565 | &bytes_written, iov, n_iov, |
1535 | - CIFS_LONG_OP); | |
1566 | + long_op); | |
1536 | 1567 | atomic_dec(&open_file->wrtPending); |
1568 | + cifs_update_eof(cifsi, offset, bytes_written); | |
1569 | + | |
1537 | 1570 | if (rc || bytes_written < bytes_to_write) { |
1538 | 1571 | cERROR(1, ("Write2 ret %d, wrote %d", |
1539 | 1572 | rc, bytes_written)); |
fs/cifs/inode.c
... | ... | @@ -143,6 +143,7 @@ |
143 | 143 | |
144 | 144 | inode->i_nlink = le64_to_cpu(info->Nlinks); |
145 | 145 | |
146 | + cifsInfo->server_eof = end_of_file; | |
146 | 147 | spin_lock(&inode->i_lock); |
147 | 148 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { |
148 | 149 | /* |
... | ... | @@ -276,7 +277,8 @@ |
276 | 277 | |
277 | 278 | /* get new inode */ |
278 | 279 | if (*pinode == NULL) { |
279 | - *pinode = cifs_new_inode(sb, &find_data.UniqueId); | |
280 | + __u64 unique_id = le64_to_cpu(find_data.UniqueId); | |
281 | + *pinode = cifs_new_inode(sb, &unique_id); | |
280 | 282 | if (*pinode == NULL) { |
281 | 283 | rc = -ENOMEM; |
282 | 284 | goto cgiiu_exit; |
283 | 285 | |
284 | 286 | |
... | ... | @@ -605,12 +607,12 @@ |
605 | 607 | inode->i_mode |= S_IFREG; |
606 | 608 | } |
607 | 609 | |
610 | + cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile); | |
608 | 611 | spin_lock(&inode->i_lock); |
609 | - if (is_size_safe_to_change(cifsInfo, | |
610 | - le64_to_cpu(pfindData->EndOfFile))) { | |
612 | + if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) { | |
611 | 613 | /* can not safely shrink the file size here if the |
612 | 614 | client is writing to it due to potential races */ |
613 | - i_size_write(inode, le64_to_cpu(pfindData->EndOfFile)); | |
615 | + i_size_write(inode, cifsInfo->server_eof); | |
614 | 616 | |
615 | 617 | /* 512 bytes (2**9) is the fake blocksize that must be |
616 | 618 | used for this calculation */ |
... | ... | @@ -1138,6 +1140,7 @@ |
1138 | 1140 | cFYI(1, ("posix mkdir returned 0x%x", rc)); |
1139 | 1141 | d_drop(direntry); |
1140 | 1142 | } else { |
1143 | + __u64 unique_id; | |
1141 | 1144 | if (pInfo->Type == cpu_to_le32(-1)) { |
1142 | 1145 | /* no return info, go query for it */ |
1143 | 1146 | kfree(pInfo); |
... | ... | @@ -1151,8 +1154,8 @@ |
1151 | 1154 | else |
1152 | 1155 | direntry->d_op = &cifs_dentry_ops; |
1153 | 1156 | |
1154 | - newinode = cifs_new_inode(inode->i_sb, | |
1155 | - &pInfo->UniqueId); | |
1157 | + unique_id = le64_to_cpu(pInfo->UniqueId); | |
1158 | + newinode = cifs_new_inode(inode->i_sb, &unique_id); | |
1156 | 1159 | if (newinode == NULL) { |
1157 | 1160 | kfree(pInfo); |
1158 | 1161 | goto mkdir_get_info; |
... | ... | @@ -1450,7 +1453,8 @@ |
1450 | 1453 | checking the UniqueId via FILE_INTERNAL_INFO */ |
1451 | 1454 | |
1452 | 1455 | unlink_target: |
1453 | - if ((rc == -EACCES) || (rc == -EEXIST)) { | |
1456 | + /* Try unlinking the target dentry if it's not negative */ | |
1457 | + if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) { | |
1454 | 1458 | tmprc = cifs_unlink(target_dir, target_dentry); |
1455 | 1459 | if (tmprc) |
1456 | 1460 | goto cifs_rename_exit; |
... | ... | @@ -1753,6 +1757,7 @@ |
1753 | 1757 | } |
1754 | 1758 | |
1755 | 1759 | if (rc == 0) { |
1760 | + cifsInode->server_eof = attrs->ia_size; | |
1756 | 1761 | rc = cifs_vmtruncate(inode, attrs->ia_size); |
1757 | 1762 | cifs_truncate_page(inode->i_mapping, inode->i_size); |
1758 | 1763 | } |
... | ... | @@ -1792,20 +1797,21 @@ |
1792 | 1797 | goto out; |
1793 | 1798 | } |
1794 | 1799 | |
1795 | - if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | |
1796 | - /* | |
1797 | - Flush data before changing file size or changing the last | |
1798 | - write time of the file on the server. If the | |
1799 | - flush returns error, store it to report later and continue. | |
1800 | - BB: This should be smarter. Why bother flushing pages that | |
1801 | - will be truncated anyway? Also, should we error out here if | |
1802 | - the flush returns error? | |
1803 | - */ | |
1804 | - rc = filemap_write_and_wait(inode->i_mapping); | |
1805 | - if (rc != 0) { | |
1806 | - cifsInode->write_behind_rc = rc; | |
1807 | - rc = 0; | |
1808 | - } | |
1800 | + /* | |
1801 | + * Attempt to flush data before changing attributes. We need to do | |
1802 | + * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the | |
1803 | + * ownership or mode then we may also need to do this. Here, we take | |
1804 | + * the safe way out and just do the flush on all setattr requests. If | |
1805 | + * the flush returns error, store it to report later and continue. | |
1806 | + * | |
1807 | + * BB: This should be smarter. Why bother flushing pages that | |
1808 | + * will be truncated anyway? Also, should we error out here if | |
1809 | + * the flush returns error? | |
1810 | + */ | |
1811 | + rc = filemap_write_and_wait(inode->i_mapping); | |
1812 | + if (rc != 0) { | |
1813 | + cifsInode->write_behind_rc = rc; | |
1814 | + rc = 0; | |
1809 | 1815 | } |
1810 | 1816 | |
1811 | 1817 | if (attrs->ia_valid & ATTR_SIZE) { |
... | ... | @@ -1903,20 +1909,21 @@ |
1903 | 1909 | return -ENOMEM; |
1904 | 1910 | } |
1905 | 1911 | |
1906 | - if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | |
1907 | - /* | |
1908 | - Flush data before changing file size or changing the last | |
1909 | - write time of the file on the server. If the | |
1910 | - flush returns error, store it to report later and continue. | |
1911 | - BB: This should be smarter. Why bother flushing pages that | |
1912 | - will be truncated anyway? Also, should we error out here if | |
1913 | - the flush returns error? | |
1914 | - */ | |
1915 | - rc = filemap_write_and_wait(inode->i_mapping); | |
1916 | - if (rc != 0) { | |
1917 | - cifsInode->write_behind_rc = rc; | |
1918 | - rc = 0; | |
1919 | - } | |
1912 | + /* | |
1913 | + * Attempt to flush data before changing attributes. We need to do | |
1914 | + * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the | |
1915 | + * ownership or mode then we may also need to do this. Here, we take | |
1916 | + * the safe way out and just do the flush on all setattr requests. If | |
1917 | + * the flush returns error, store it to report later and continue. | |
1918 | + * | |
1919 | + * BB: This should be smarter. Why bother flushing pages that | |
1920 | + * will be truncated anyway? Also, should we error out here if | |
1921 | + * the flush returns error? | |
1922 | + */ | |
1923 | + rc = filemap_write_and_wait(inode->i_mapping); | |
1924 | + if (rc != 0) { | |
1925 | + cifsInode->write_behind_rc = rc; | |
1926 | + rc = 0; | |
1920 | 1927 | } |
1921 | 1928 | |
1922 | 1929 | if (attrs->ia_valid & ATTR_SIZE) { |
fs/cifs/readdir.c
... | ... | @@ -239,6 +239,7 @@ |
239 | 239 | if (atomic_read(&cifsInfo->inUse) == 0) |
240 | 240 | atomic_set(&cifsInfo->inUse, 1); |
241 | 241 | |
242 | + cifsInfo->server_eof = end_of_file; | |
242 | 243 | spin_lock(&tmp_inode->i_lock); |
243 | 244 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { |
244 | 245 | /* can not safely change the file size here if the |
... | ... | @@ -375,6 +376,7 @@ |
375 | 376 | tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); |
376 | 377 | tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); |
377 | 378 | |
379 | + cifsInfo->server_eof = end_of_file; | |
378 | 380 | spin_lock(&tmp_inode->i_lock); |
379 | 381 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { |
380 | 382 | /* can not safely change the file size here if the |
... | ... | @@ -840,7 +842,7 @@ |
840 | 842 | len = strnlen(filename, PATH_MAX); |
841 | 843 | } |
842 | 844 | |
843 | - *pinum = pFindData->UniqueId; | |
845 | + *pinum = le64_to_cpu(pFindData->UniqueId); | |
844 | 846 | } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { |
845 | 847 | FILE_DIRECTORY_INFO *pFindData = |
846 | 848 | (FILE_DIRECTORY_INFO *)current_entry; |
... | ... | @@ -856,7 +858,7 @@ |
856 | 858 | (SEARCH_ID_FULL_DIR_INFO *)current_entry; |
857 | 859 | filename = &pFindData->FileName[0]; |
858 | 860 | len = le32_to_cpu(pFindData->FileNameLength); |
859 | - *pinum = pFindData->UniqueId; | |
861 | + *pinum = le64_to_cpu(pFindData->UniqueId); | |
860 | 862 | } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { |
861 | 863 | FILE_BOTH_DIRECTORY_INFO *pFindData = |
862 | 864 | (FILE_BOTH_DIRECTORY_INFO *)current_entry; |
fs/cifs/sess.c
... | ... | @@ -285,35 +285,36 @@ |
285 | 285 | int words_left, len; |
286 | 286 | char *data = *pbcc_area; |
287 | 287 | |
288 | - | |
289 | - | |
290 | 288 | cFYI(1, ("bleft %d", bleft)); |
291 | 289 | |
290 | + /* | |
291 | + * Windows servers do not always double null terminate their final | |
292 | + * Unicode string. Check to see if there are an uneven number of bytes | |
293 | + * left. If so, then add an extra NULL pad byte to the end of the | |
294 | + * response. | |
295 | + * | |
296 | + * See section 2.7.2 in "Implementing CIFS" for details | |
297 | + */ | |
298 | + if (bleft % 2) { | |
299 | + data[bleft] = 0; | |
300 | + ++bleft; | |
301 | + } | |
292 | 302 | |
293 | - /* SMB header is unaligned, so cifs servers word align start of | |
294 | - Unicode strings */ | |
295 | - data++; | |
296 | - bleft--; /* Windows servers do not always double null terminate | |
297 | - their final Unicode string - in which case we | |
298 | - now will not attempt to decode the byte of junk | |
299 | - which follows it */ | |
300 | - | |
301 | 303 | words_left = bleft / 2; |
302 | 304 | |
303 | 305 | /* save off server operating system */ |
304 | 306 | len = UniStrnlen((wchar_t *) data, words_left); |
305 | 307 | |
306 | -/* We look for obvious messed up bcc or strings in response so we do not go off | |
307 | - the end since (at least) WIN2K and Windows XP have a major bug in not null | |
308 | - terminating last Unicode string in response */ | |
309 | 308 | if (len >= words_left) |
310 | 309 | return rc; |
311 | 310 | |
312 | 311 | kfree(ses->serverOS); |
313 | 312 | /* UTF-8 string will not grow more than four times as big as UCS-16 */ |
314 | 313 | ses->serverOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL); |
315 | - if (ses->serverOS != NULL) | |
314 | + if (ses->serverOS != NULL) { | |
316 | 315 | cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); |
316 | + cFYI(1, ("serverOS=%s", ses->serverOS)); | |
317 | + } | |
317 | 318 | data += 2 * (len + 1); |
318 | 319 | words_left -= len + 1; |
319 | 320 | |
... | ... | @@ -328,6 +329,7 @@ |
328 | 329 | if (ses->serverNOS != NULL) { |
329 | 330 | cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, |
330 | 331 | nls_cp); |
332 | + cFYI(1, ("serverNOS=%s", ses->serverNOS)); | |
331 | 333 | if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) { |
332 | 334 | cFYI(1, ("NT4 server")); |
333 | 335 | ses->flags |= CIFS_SES_NT4; |
334 | 336 | |
... | ... | @@ -343,12 +345,11 @@ |
343 | 345 | return rc; |
344 | 346 | |
345 | 347 | kfree(ses->serverDomain); |
346 | - ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ | |
348 | + ses->serverDomain = kzalloc((4 * len) + 2, GFP_KERNEL); | |
347 | 349 | if (ses->serverDomain != NULL) { |
348 | 350 | cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, |
349 | 351 | nls_cp); |
350 | - ses->serverDomain[2*len] = 0; | |
351 | - ses->serverDomain[(2*len) + 1] = 0; | |
352 | + cFYI(1, ("serverDomain=%s", ses->serverDomain)); | |
352 | 353 | } |
353 | 354 | data += 2 * (len + 1); |
354 | 355 | words_left -= len + 1; |
355 | 356 | |
356 | 357 | |
... | ... | @@ -702,12 +703,18 @@ |
702 | 703 | } |
703 | 704 | |
704 | 705 | /* BB check if Unicode and decode strings */ |
705 | - if (smb_buf->Flags2 & SMBFLG2_UNICODE) | |
706 | + if (smb_buf->Flags2 & SMBFLG2_UNICODE) { | |
707 | + /* unicode string area must be word-aligned */ | |
708 | + if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { | |
709 | + ++bcc_ptr; | |
710 | + --bytes_remaining; | |
711 | + } | |
706 | 712 | rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, |
707 | - ses, nls_cp); | |
708 | - else | |
713 | + ses, nls_cp); | |
714 | + } else { | |
709 | 715 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, |
710 | 716 | ses, nls_cp); |
717 | + } | |
711 | 718 | |
712 | 719 | ssetup_exit: |
713 | 720 | if (spnego_key) { |