diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-23 13:43:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-23 13:43:36 -0400 |
commit | db563fc2e80534f98c7f9121a6f7dfe41f177a79 (patch) | |
tree | c97acbb983530b070e28c70825e0eedbbdb97ab2 /fs/cifs | |
parent | eb81071584bed0b04adcaf57e525638d0f92e1e1 (diff) | |
parent | b1c8d2b421376bc941823ee93e36cb491609b02c (diff) |
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: handle the TCP_Server_Info->tsk field more carefully
cifs: fix unlinking of rename target when server doesn't support open file renames
[CIFS] improve setlease handling
[CIFS] fix saving of resume key before CIFSFindNext
cifs: make cifs_rename handle -EACCES errors
[CIFS] fix build error
[CIFS] undo changes in cifs_rename_pending_delete if it errors out
cifs: track DeletePending flag in cifsInodeInfo
cifs: don't use CREATE_DELETE_ON_CLOSE in cifs_rename_pending_delete
[CIFS] eliminate usage of kthread_stop for cifsd
[CIFS] Add nodfs mount option
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/CHANGES | 9 | ||||
-rw-r--r-- | fs/cifs/README | 19 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 42 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 2 | ||||
-rw-r--r-- | fs/cifs/connect.c | 94 | ||||
-rw-r--r-- | fs/cifs/inode.c | 211 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 3 |
9 files changed, 259 insertions, 125 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 06e521a945c3..8f528ea24c48 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,3 +1,11 @@ | |||
1 | Version 1.55 | ||
2 | ------------ | ||
3 | Various fixes to make delete of open files behavior more predictable | ||
4 | (when delete of an open file fails we mark the file as "delete-on-close" | ||
5 | in a way that more servers accept, but only if we can first rename the | ||
6 | file to a temporary name). Add experimental support for more safely | ||
7 | handling fcntl(F_SETLEASE). | ||
8 | |||
1 | Version 1.54 | 9 | Version 1.54 |
2 | ------------ | 10 | ------------ |
3 | Fix premature write failure on congested networks (we would give up | 11 | Fix premature write failure on congested networks (we would give up |
@@ -13,6 +21,7 @@ on dns_upcall (resolving DFS referralls). Fix plain text password | |||
13 | authentication (requires setting SecurityFlags to 0x30030 to enable | 21 | authentication (requires setting SecurityFlags to 0x30030 to enable |
14 | lanman and plain text though). Fix writes to be at correct offset when | 22 | lanman and plain text though). Fix writes to be at correct offset when |
15 | file is open with O_APPEND and file is on a directio (forcediretio) mount. | 23 | file is open with O_APPEND and file is on a directio (forcediretio) mount. |
24 | Fix bug in rewinding readdir directory searches. Add nodfs mount option. | ||
16 | 25 | ||
17 | Version 1.53 | 26 | Version 1.53 |
18 | ------------ | 27 | ------------ |
diff --git a/fs/cifs/README b/fs/cifs/README index bd2343d4c6a6..a439dc1739b3 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -463,6 +463,9 @@ A partial list of the supported mount options follows: | |||
463 | with cifs style mandatory byte range locks (and most | 463 | with cifs style mandatory byte range locks (and most |
464 | cifs servers do not yet support requesting advisory | 464 | cifs servers do not yet support requesting advisory |
465 | byte range locks). | 465 | byte range locks). |
466 | nodfs Disable DFS (global name space support) even if the | ||
467 | server claims to support it. This can help work around | ||
468 | a problem with parsing of DFS paths with Samba 3.0.24 server. | ||
466 | remount remount the share (often used to change from ro to rw mounts | 469 | remount remount the share (often used to change from ro to rw mounts |
467 | or vice versa) | 470 | or vice versa) |
468 | cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for | 471 | cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for |
@@ -488,6 +491,19 @@ A partial list of the supported mount options follows: | |||
488 | Note that this differs from the sign mount option in that it | 491 | Note that this differs from the sign mount option in that it |
489 | causes encryption of data sent over this mounted share but other | 492 | causes encryption of data sent over this mounted share but other |
490 | shares mounted to the same server are unaffected. | 493 | shares mounted to the same server are unaffected. |
494 | locallease This option is rarely needed. Fcntl F_SETLEASE is | ||
495 | used by some applications such as Samba and NFSv4 server to | ||
496 | check to see whether a file is cacheable. CIFS has no way | ||
497 | to explicitly request a lease, but can check whether a file | ||
498 | is cacheable (oplocked). Unfortunately, even if a file | ||
499 | is not oplocked, it could still be cacheable (ie cifs client | ||
500 | could grant fcntl leases if no other local processes are using | ||
501 | the file) for cases for example such as when the server does not | ||
502 | support oplocks and the user is sure that the only updates to | ||
503 | the file will be from this client. Specifying this mount option | ||
504 | will allow the cifs client to check for leases (only) locally | ||
505 | for files which are not oplocked instead of denying leases | ||
506 | in that case. (EXPERIMENTAL) | ||
491 | sec Security mode. Allowed values are: | 507 | sec Security mode. Allowed values are: |
492 | none attempt to connection as a null user (no name) | 508 | none attempt to connection as a null user (no name) |
493 | krb5 Use Kerberos version 5 authentication | 509 | krb5 Use Kerberos version 5 authentication |
@@ -638,6 +654,9 @@ requires enabling CONFIG_CIFS_EXPERIMENTAL | |||
638 | cifsacl support needed to retrieve approximated mode bits based on | 654 | cifsacl support needed to retrieve approximated mode bits based on |
639 | the contents on the CIFS ACL. | 655 | the contents on the CIFS ACL. |
640 | 656 | ||
657 | lease support: cifs will check the oplock state before calling into | ||
658 | the vfs to see if we can grant a lease on a file. | ||
659 | |||
641 | DNOTIFY fcntl: needed for support of directory change | 660 | DNOTIFY fcntl: needed for support of directory change |
642 | notification and perhaps later for file leases) | 661 | notification and perhaps later for file leases) |
643 | 662 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 84cc011a16e4..ac5915d61dca 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -312,6 +312,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
312 | file data or metadata */ | 312 | file data or metadata */ |
313 | cifs_inode->clientCanCacheRead = false; | 313 | cifs_inode->clientCanCacheRead = false; |
314 | cifs_inode->clientCanCacheAll = false; | 314 | cifs_inode->clientCanCacheAll = false; |
315 | cifs_inode->delete_pending = false; | ||
315 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 316 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
316 | 317 | ||
317 | /* Can not set i_flags here - they get immediately overwritten | 318 | /* Can not set i_flags here - they get immediately overwritten |
@@ -620,6 +621,37 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) | |||
620 | return generic_file_llseek_unlocked(file, offset, origin); | 621 | return generic_file_llseek_unlocked(file, offset, origin); |
621 | } | 622 | } |
622 | 623 | ||
624 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
625 | static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) | ||
626 | { | ||
627 | /* note that this is called by vfs setlease with the BKL held | ||
628 | although I doubt that BKL is needed here in cifs */ | ||
629 | struct inode *inode = file->f_path.dentry->d_inode; | ||
630 | |||
631 | if (!(S_ISREG(inode->i_mode))) | ||
632 | return -EINVAL; | ||
633 | |||
634 | /* check if file is oplocked */ | ||
635 | if (((arg == F_RDLCK) && | ||
636 | (CIFS_I(inode)->clientCanCacheRead)) || | ||
637 | ((arg == F_WRLCK) && | ||
638 | (CIFS_I(inode)->clientCanCacheAll))) | ||
639 | return generic_setlease(file, arg, lease); | ||
640 | else if (CIFS_SB(inode->i_sb)->tcon->local_lease && | ||
641 | !CIFS_I(inode)->clientCanCacheRead) | ||
642 | /* If the server claims to support oplock on this | ||
643 | file, then we still need to check oplock even | ||
644 | if the local_lease mount option is set, but there | ||
645 | are servers which do not support oplock for which | ||
646 | this mount option may be useful if the user | ||
647 | knows that the file won't be changed on the server | ||
648 | by anyone else */ | ||
649 | return generic_setlease(file, arg, lease); | ||
650 | else | ||
651 | return -EAGAIN; | ||
652 | } | ||
653 | #endif | ||
654 | |||
623 | struct file_system_type cifs_fs_type = { | 655 | struct file_system_type cifs_fs_type = { |
624 | .owner = THIS_MODULE, | 656 | .owner = THIS_MODULE, |
625 | .name = "cifs", | 657 | .name = "cifs", |
@@ -698,6 +730,7 @@ const struct file_operations cifs_file_ops = { | |||
698 | 730 | ||
699 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 731 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
700 | .dir_notify = cifs_dir_notify, | 732 | .dir_notify = cifs_dir_notify, |
733 | .setlease = cifs_setlease, | ||
701 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 734 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ |
702 | }; | 735 | }; |
703 | 736 | ||
@@ -718,6 +751,7 @@ const struct file_operations cifs_file_direct_ops = { | |||
718 | .llseek = cifs_llseek, | 751 | .llseek = cifs_llseek, |
719 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 752 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
720 | .dir_notify = cifs_dir_notify, | 753 | .dir_notify = cifs_dir_notify, |
754 | .setlease = cifs_setlease, | ||
721 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 755 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ |
722 | }; | 756 | }; |
723 | const struct file_operations cifs_file_nobrl_ops = { | 757 | const struct file_operations cifs_file_nobrl_ops = { |
@@ -738,6 +772,7 @@ const struct file_operations cifs_file_nobrl_ops = { | |||
738 | 772 | ||
739 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 773 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
740 | .dir_notify = cifs_dir_notify, | 774 | .dir_notify = cifs_dir_notify, |
775 | .setlease = cifs_setlease, | ||
741 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 776 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ |
742 | }; | 777 | }; |
743 | 778 | ||
@@ -757,6 +792,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = { | |||
757 | .llseek = cifs_llseek, | 792 | .llseek = cifs_llseek, |
758 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 793 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
759 | .dir_notify = cifs_dir_notify, | 794 | .dir_notify = cifs_dir_notify, |
795 | .setlease = cifs_setlease, | ||
760 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 796 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ |
761 | }; | 797 | }; |
762 | 798 | ||
@@ -949,6 +985,12 @@ static int cifs_oplock_thread(void *dummyarg) | |||
949 | the call */ | 985 | the call */ |
950 | /* mutex_lock(&inode->i_mutex);*/ | 986 | /* mutex_lock(&inode->i_mutex);*/ |
951 | if (S_ISREG(inode->i_mode)) { | 987 | if (S_ISREG(inode->i_mode)) { |
988 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
989 | if (CIFS_I(inode)->clientCanCacheAll == 0) | ||
990 | break_lease(inode, FMODE_READ); | ||
991 | else if (CIFS_I(inode)->clientCanCacheRead == 0) | ||
992 | break_lease(inode, FMODE_WRITE); | ||
993 | #endif | ||
952 | rc = filemap_fdatawrite(inode->i_mapping); | 994 | rc = filemap_fdatawrite(inode->i_mapping); |
953 | if (CIFS_I(inode)->clientCanCacheRead == 0) { | 995 | if (CIFS_I(inode)->clientCanCacheRead == 0) { |
954 | waitrc = filemap_fdatawait( | 996 | waitrc = filemap_fdatawait( |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index f7b4a5cd837b..074de0b5064d 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
101 | extern const struct export_operations cifs_export_ops; | 101 | extern const struct export_operations cifs_export_ops; |
102 | #endif /* EXPERIMENTAL */ | 102 | #endif /* EXPERIMENTAL */ |
103 | 103 | ||
104 | #define CIFS_VERSION "1.54" | 104 | #define CIFS_VERSION "1.55" |
105 | #endif /* _CIFSFS_H */ | 105 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 0d22479d99b7..c791e5b5a914 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -285,6 +285,7 @@ struct cifsTconInfo { | |||
285 | bool seal:1; /* transport encryption for this mounted share */ | 285 | bool seal:1; /* transport encryption for this mounted share */ |
286 | bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol | 286 | bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol |
287 | for this mount even if server would support */ | 287 | for this mount even if server would support */ |
288 | bool local_lease:1; /* check leases (only) on local system not remote */ | ||
288 | /* BB add field for back pointer to sb struct(s)? */ | 289 | /* BB add field for back pointer to sb struct(s)? */ |
289 | }; | 290 | }; |
290 | 291 | ||
@@ -353,6 +354,7 @@ struct cifsInodeInfo { | |||
353 | bool clientCanCacheRead:1; /* read oplock */ | 354 | bool clientCanCacheRead:1; /* read oplock */ |
354 | bool clientCanCacheAll:1; /* read and writebehind oplock */ | 355 | bool clientCanCacheAll:1; /* read and writebehind oplock */ |
355 | bool oplockPending:1; | 356 | bool oplockPending:1; |
357 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ | ||
356 | struct inode vfs_inode; | 358 | struct inode vfs_inode; |
357 | }; | 359 | }; |
358 | 360 | ||
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6f4ffe15d68d..843a85fb8b9a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -1309,6 +1309,7 @@ OldOpenRetry: | |||
1309 | cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile)); | 1309 | cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile)); |
1310 | pfile_info->EndOfFile = pfile_info->AllocationSize; | 1310 | pfile_info->EndOfFile = pfile_info->AllocationSize; |
1311 | pfile_info->NumberOfLinks = cpu_to_le32(1); | 1311 | pfile_info->NumberOfLinks = cpu_to_le32(1); |
1312 | pfile_info->DeletePending = 0; | ||
1312 | } | 1313 | } |
1313 | } | 1314 | } |
1314 | 1315 | ||
@@ -1410,6 +1411,7 @@ openRetry: | |||
1410 | pfile_info->AllocationSize = pSMBr->AllocationSize; | 1411 | pfile_info->AllocationSize = pSMBr->AllocationSize; |
1411 | pfile_info->EndOfFile = pSMBr->EndOfFile; | 1412 | pfile_info->EndOfFile = pSMBr->EndOfFile; |
1412 | pfile_info->NumberOfLinks = cpu_to_le32(1); | 1413 | pfile_info->NumberOfLinks = cpu_to_le32(1); |
1414 | pfile_info->DeletePending = 0; | ||
1413 | } | 1415 | } |
1414 | } | 1416 | } |
1415 | 1417 | ||
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 4c13bcdb92a5..71b7661e2260 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -90,6 +90,8 @@ struct smb_vol { | |||
90 | bool nocase:1; /* request case insensitive filenames */ | 90 | bool nocase:1; /* request case insensitive filenames */ |
91 | bool nobrl:1; /* disable sending byte range locks to srv */ | 91 | bool nobrl:1; /* disable sending byte range locks to srv */ |
92 | bool seal:1; /* request transport encryption on share */ | 92 | bool seal:1; /* request transport encryption on share */ |
93 | bool nodfs:1; /* Do not request DFS, even if available */ | ||
94 | bool local_lease:1; /* check leases only on local system, not remote */ | ||
93 | unsigned int rsize; | 95 | unsigned int rsize; |
94 | unsigned int wsize; | 96 | unsigned int wsize; |
95 | unsigned int sockopt; | 97 | unsigned int sockopt; |
@@ -124,7 +126,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
124 | struct mid_q_entry *mid_entry; | 126 | struct mid_q_entry *mid_entry; |
125 | 127 | ||
126 | spin_lock(&GlobalMid_Lock); | 128 | spin_lock(&GlobalMid_Lock); |
127 | if (kthread_should_stop()) { | 129 | if (server->tcpStatus == CifsExiting) { |
128 | /* the demux thread will exit normally | 130 | /* the demux thread will exit normally |
129 | next time through the loop */ | 131 | next time through the loop */ |
130 | spin_unlock(&GlobalMid_Lock); | 132 | spin_unlock(&GlobalMid_Lock); |
@@ -184,7 +186,8 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
184 | spin_unlock(&GlobalMid_Lock); | 186 | spin_unlock(&GlobalMid_Lock); |
185 | up(&server->tcpSem); | 187 | up(&server->tcpSem); |
186 | 188 | ||
187 | while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) { | 189 | while ((server->tcpStatus != CifsExiting) && |
190 | (server->tcpStatus != CifsGood)) { | ||
188 | try_to_freeze(); | 191 | try_to_freeze(); |
189 | if (server->protocolType == IPV6) { | 192 | if (server->protocolType == IPV6) { |
190 | rc = ipv6_connect(&server->addr.sockAddr6, | 193 | rc = ipv6_connect(&server->addr.sockAddr6, |
@@ -201,7 +204,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
201 | } else { | 204 | } else { |
202 | atomic_inc(&tcpSesReconnectCount); | 205 | atomic_inc(&tcpSesReconnectCount); |
203 | spin_lock(&GlobalMid_Lock); | 206 | spin_lock(&GlobalMid_Lock); |
204 | if (!kthread_should_stop()) | 207 | if (server->tcpStatus != CifsExiting) |
205 | server->tcpStatus = CifsGood; | 208 | server->tcpStatus = CifsGood; |
206 | server->sequence_number = 0; | 209 | server->sequence_number = 0; |
207 | spin_unlock(&GlobalMid_Lock); | 210 | spin_unlock(&GlobalMid_Lock); |
@@ -356,7 +359,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
356 | GFP_KERNEL); | 359 | GFP_KERNEL); |
357 | 360 | ||
358 | set_freezable(); | 361 | set_freezable(); |
359 | while (!kthread_should_stop()) { | 362 | while (server->tcpStatus != CifsExiting) { |
360 | if (try_to_freeze()) | 363 | if (try_to_freeze()) |
361 | continue; | 364 | continue; |
362 | if (bigbuf == NULL) { | 365 | if (bigbuf == NULL) { |
@@ -397,7 +400,7 @@ incomplete_rcv: | |||
397 | kernel_recvmsg(csocket, &smb_msg, | 400 | kernel_recvmsg(csocket, &smb_msg, |
398 | &iov, 1, pdu_length, 0 /* BB other flags? */); | 401 | &iov, 1, pdu_length, 0 /* BB other flags? */); |
399 | 402 | ||
400 | if (kthread_should_stop()) { | 403 | if (server->tcpStatus == CifsExiting) { |
401 | break; | 404 | break; |
402 | } else if (server->tcpStatus == CifsNeedReconnect) { | 405 | } else if (server->tcpStatus == CifsNeedReconnect) { |
403 | cFYI(1, ("Reconnect after server stopped responding")); | 406 | cFYI(1, ("Reconnect after server stopped responding")); |
@@ -522,7 +525,7 @@ incomplete_rcv: | |||
522 | total_read += length) { | 525 | total_read += length) { |
523 | length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, | 526 | length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, |
524 | pdu_length - total_read, 0); | 527 | pdu_length - total_read, 0); |
525 | if (kthread_should_stop() || | 528 | if ((server->tcpStatus == CifsExiting) || |
526 | (length == -EINTR)) { | 529 | (length == -EINTR)) { |
527 | /* then will exit */ | 530 | /* then will exit */ |
528 | reconnect = 2; | 531 | reconnect = 2; |
@@ -651,14 +654,6 @@ multi_t2_fnd: | |||
651 | spin_unlock(&GlobalMid_Lock); | 654 | spin_unlock(&GlobalMid_Lock); |
652 | wake_up_all(&server->response_q); | 655 | wake_up_all(&server->response_q); |
653 | 656 | ||
654 | /* don't exit until kthread_stop is called */ | ||
655 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
656 | while (!kthread_should_stop()) { | ||
657 | schedule(); | ||
658 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
659 | } | ||
660 | set_current_state(TASK_RUNNING); | ||
661 | |||
662 | /* check if we have blocked requests that need to free */ | 657 | /* check if we have blocked requests that need to free */ |
663 | /* Note that cifs_max_pending is normally 50, but | 658 | /* Note that cifs_max_pending is normally 50, but |
664 | can be set at module install time to as little as two */ | 659 | can be set at module install time to as little as two */ |
@@ -755,6 +750,7 @@ multi_t2_fnd: | |||
755 | write_unlock(&GlobalSMBSeslock); | 750 | write_unlock(&GlobalSMBSeslock); |
756 | 751 | ||
757 | kfree(server->hostname); | 752 | kfree(server->hostname); |
753 | task_to_wake = xchg(&server->tsk, NULL); | ||
758 | kfree(server); | 754 | kfree(server); |
759 | 755 | ||
760 | length = atomic_dec_return(&tcpSesAllocCount); | 756 | length = atomic_dec_return(&tcpSesAllocCount); |
@@ -762,6 +758,16 @@ multi_t2_fnd: | |||
762 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv, | 758 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv, |
763 | GFP_KERNEL); | 759 | GFP_KERNEL); |
764 | 760 | ||
761 | /* if server->tsk was NULL then wait for a signal before exiting */ | ||
762 | if (!task_to_wake) { | ||
763 | set_current_state(TASK_INTERRUPTIBLE); | ||
764 | while (!signal_pending(current)) { | ||
765 | schedule(); | ||
766 | set_current_state(TASK_INTERRUPTIBLE); | ||
767 | } | ||
768 | set_current_state(TASK_RUNNING); | ||
769 | } | ||
770 | |||
765 | return 0; | 771 | return 0; |
766 | } | 772 | } |
767 | 773 | ||
@@ -1218,6 +1224,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1218 | vol->sfu_emul = 1; | 1224 | vol->sfu_emul = 1; |
1219 | } else if (strnicmp(data, "nosfu", 5) == 0) { | 1225 | } else if (strnicmp(data, "nosfu", 5) == 0) { |
1220 | vol->sfu_emul = 0; | 1226 | vol->sfu_emul = 0; |
1227 | } else if (strnicmp(data, "nodfs", 5) == 0) { | ||
1228 | vol->nodfs = 1; | ||
1221 | } else if (strnicmp(data, "posixpaths", 10) == 0) { | 1229 | } else if (strnicmp(data, "posixpaths", 10) == 0) { |
1222 | vol->posix_paths = 1; | 1230 | vol->posix_paths = 1; |
1223 | } else if (strnicmp(data, "noposixpaths", 12) == 0) { | 1231 | } else if (strnicmp(data, "noposixpaths", 12) == 0) { |
@@ -1268,6 +1276,10 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1268 | vol->no_psx_acl = 0; | 1276 | vol->no_psx_acl = 0; |
1269 | } else if (strnicmp(data, "noacl", 5) == 0) { | 1277 | } else if (strnicmp(data, "noacl", 5) == 0) { |
1270 | vol->no_psx_acl = 1; | 1278 | vol->no_psx_acl = 1; |
1279 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1280 | } else if (strnicmp(data, "locallease", 6) == 0) { | ||
1281 | vol->local_lease = 1; | ||
1282 | #endif | ||
1271 | } else if (strnicmp(data, "sign", 4) == 0) { | 1283 | } else if (strnicmp(data, "sign", 4) == 0) { |
1272 | vol->secFlg |= CIFSSEC_MUST_SIGN; | 1284 | vol->secFlg |= CIFSSEC_MUST_SIGN; |
1273 | } else if (strnicmp(data, "seal", 4) == 0) { | 1285 | } else if (strnicmp(data, "seal", 4) == 0) { |
@@ -1845,6 +1857,16 @@ convert_delimiter(char *path, char delim) | |||
1845 | } | 1857 | } |
1846 | } | 1858 | } |
1847 | 1859 | ||
1860 | static void | ||
1861 | kill_cifsd(struct TCP_Server_Info *server) | ||
1862 | { | ||
1863 | struct task_struct *task; | ||
1864 | |||
1865 | task = xchg(&server->tsk, NULL); | ||
1866 | if (task) | ||
1867 | force_sig(SIGKILL, task); | ||
1868 | } | ||
1869 | |||
1848 | int | 1870 | int |
1849 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | 1871 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, |
1850 | char *mount_data, const char *devname) | 1872 | char *mount_data, const char *devname) |
@@ -2166,6 +2188,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2166 | for the retry flag is used */ | 2188 | for the retry flag is used */ |
2167 | tcon->retry = volume_info.retry; | 2189 | tcon->retry = volume_info.retry; |
2168 | tcon->nocase = volume_info.nocase; | 2190 | tcon->nocase = volume_info.nocase; |
2191 | tcon->local_lease = volume_info.local_lease; | ||
2169 | if (tcon->seal != volume_info.seal) | 2192 | if (tcon->seal != volume_info.seal) |
2170 | cERROR(1, ("transport encryption setting " | 2193 | cERROR(1, ("transport encryption setting " |
2171 | "conflicts with existing tid")); | 2194 | "conflicts with existing tid")); |
@@ -2197,6 +2220,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2197 | volume_info.UNC, | 2220 | volume_info.UNC, |
2198 | tcon, cifs_sb->local_nls); | 2221 | tcon, cifs_sb->local_nls); |
2199 | cFYI(1, ("CIFS Tcon rc = %d", rc)); | 2222 | cFYI(1, ("CIFS Tcon rc = %d", rc)); |
2223 | if (volume_info.nodfs) { | ||
2224 | tcon->Flags &= | ||
2225 | ~SMB_SHARE_IS_IN_DFS; | ||
2226 | cFYI(1, ("DFS disabled (%d)", | ||
2227 | tcon->Flags)); | ||
2228 | } | ||
2200 | } | 2229 | } |
2201 | if (!rc) { | 2230 | if (!rc) { |
2202 | atomic_inc(&pSesInfo->inUse); | 2231 | atomic_inc(&pSesInfo->inUse); |
@@ -2225,14 +2254,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2225 | spin_lock(&GlobalMid_Lock); | 2254 | spin_lock(&GlobalMid_Lock); |
2226 | srvTcp->tcpStatus = CifsExiting; | 2255 | srvTcp->tcpStatus = CifsExiting; |
2227 | spin_unlock(&GlobalMid_Lock); | 2256 | spin_unlock(&GlobalMid_Lock); |
2228 | if (srvTcp->tsk) { | 2257 | kill_cifsd(srvTcp); |
2229 | /* If we could verify that kthread_stop would | ||
2230 | always wake up processes blocked in | ||
2231 | tcp in recv_mesg then we could remove the | ||
2232 | send_sig call */ | ||
2233 | force_sig(SIGKILL, srvTcp->tsk); | ||
2234 | kthread_stop(srvTcp->tsk); | ||
2235 | } | ||
2236 | } | 2258 | } |
2237 | /* If find_unc succeeded then rc == 0 so we can not end */ | 2259 | /* If find_unc succeeded then rc == 0 so we can not end */ |
2238 | if (tcon) /* up accidently freeing someone elses tcon struct */ | 2260 | if (tcon) /* up accidently freeing someone elses tcon struct */ |
@@ -2245,19 +2267,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2245 | temp_rc = CIFSSMBLogoff(xid, pSesInfo); | 2267 | temp_rc = CIFSSMBLogoff(xid, pSesInfo); |
2246 | /* if the socketUseCount is now zero */ | 2268 | /* if the socketUseCount is now zero */ |
2247 | if ((temp_rc == -ESHUTDOWN) && | 2269 | if ((temp_rc == -ESHUTDOWN) && |
2248 | (pSesInfo->server) && | 2270 | (pSesInfo->server)) |
2249 | (pSesInfo->server->tsk)) { | 2271 | kill_cifsd(pSesInfo->server); |
2250 | force_sig(SIGKILL, | ||
2251 | pSesInfo->server->tsk); | ||
2252 | kthread_stop(pSesInfo->server->tsk); | ||
2253 | } | ||
2254 | } else { | 2272 | } else { |
2255 | cFYI(1, ("No session or bad tcon")); | 2273 | cFYI(1, ("No session or bad tcon")); |
2256 | if ((pSesInfo->server) && | 2274 | if (pSesInfo->server) { |
2257 | (pSesInfo->server->tsk)) { | 2275 | spin_lock(&GlobalMid_Lock); |
2258 | force_sig(SIGKILL, | 2276 | srvTcp->tcpStatus = CifsExiting; |
2259 | pSesInfo->server->tsk); | 2277 | spin_unlock(&GlobalMid_Lock); |
2260 | kthread_stop(pSesInfo->server->tsk); | 2278 | kill_cifsd(pSesInfo->server); |
2261 | } | 2279 | } |
2262 | } | 2280 | } |
2263 | sesInfoFree(pSesInfo); | 2281 | sesInfoFree(pSesInfo); |
@@ -3544,7 +3562,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | |||
3544 | int rc = 0; | 3562 | int rc = 0; |
3545 | int xid; | 3563 | int xid; |
3546 | struct cifsSesInfo *ses = NULL; | 3564 | struct cifsSesInfo *ses = NULL; |
3547 | struct task_struct *cifsd_task; | ||
3548 | char *tmp; | 3565 | char *tmp; |
3549 | 3566 | ||
3550 | xid = GetXid(); | 3567 | xid = GetXid(); |
@@ -3560,7 +3577,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | |||
3560 | tconInfoFree(cifs_sb->tcon); | 3577 | tconInfoFree(cifs_sb->tcon); |
3561 | if ((ses) && (ses->server)) { | 3578 | if ((ses) && (ses->server)) { |
3562 | /* save off task so we do not refer to ses later */ | 3579 | /* save off task so we do not refer to ses later */ |
3563 | cifsd_task = ses->server->tsk; | ||
3564 | cFYI(1, ("About to do SMBLogoff ")); | 3580 | cFYI(1, ("About to do SMBLogoff ")); |
3565 | rc = CIFSSMBLogoff(xid, ses); | 3581 | rc = CIFSSMBLogoff(xid, ses); |
3566 | if (rc == -EBUSY) { | 3582 | if (rc == -EBUSY) { |
@@ -3568,10 +3584,8 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | |||
3568 | return 0; | 3584 | return 0; |
3569 | } else if (rc == -ESHUTDOWN) { | 3585 | } else if (rc == -ESHUTDOWN) { |
3570 | cFYI(1, ("Waking up socket by sending signal")); | 3586 | cFYI(1, ("Waking up socket by sending signal")); |
3571 | if (cifsd_task) { | 3587 | if (ses->server) |
3572 | force_sig(SIGKILL, cifsd_task); | 3588 | kill_cifsd(ses->server); |
3573 | kthread_stop(cifsd_task); | ||
3574 | } | ||
3575 | rc = 0; | 3589 | rc = 0; |
3576 | } /* else - we have an smb session | 3590 | } /* else - we have an smb session |
3577 | left on this socket do not kill cifsd */ | 3591 | left on this socket do not kill cifsd */ |
@@ -3701,7 +3715,9 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3701 | cERROR(1, ("Send error in SessSetup = %d", rc)); | 3715 | cERROR(1, ("Send error in SessSetup = %d", rc)); |
3702 | } else { | 3716 | } else { |
3703 | cFYI(1, ("CIFS Session Established successfully")); | 3717 | cFYI(1, ("CIFS Session Established successfully")); |
3718 | spin_lock(&GlobalMid_Lock); | ||
3704 | pSesInfo->status = CifsGood; | 3719 | pSesInfo->status = CifsGood; |
3720 | spin_unlock(&GlobalMid_Lock); | ||
3705 | } | 3721 | } |
3706 | 3722 | ||
3707 | ss_err_exit: | 3723 | ss_err_exit: |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a8c833345fc9..d54fa8aeaea9 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -506,6 +506,7 @@ int cifs_get_inode_info(struct inode **pinode, | |||
506 | inode = *pinode; | 506 | inode = *pinode; |
507 | cifsInfo = CIFS_I(inode); | 507 | cifsInfo = CIFS_I(inode); |
508 | cifsInfo->cifsAttrs = attr; | 508 | cifsInfo->cifsAttrs = attr; |
509 | cifsInfo->delete_pending = pfindData->DeletePending ? true : false; | ||
509 | cFYI(1, ("Old time %ld", cifsInfo->time)); | 510 | cFYI(1, ("Old time %ld", cifsInfo->time)); |
510 | cifsInfo->time = jiffies; | 511 | cifsInfo->time = jiffies; |
511 | cFYI(1, ("New time %ld", cifsInfo->time)); | 512 | cFYI(1, ("New time %ld", cifsInfo->time)); |
@@ -772,63 +773,106 @@ out: | |||
772 | * anything else. | 773 | * anything else. |
773 | */ | 774 | */ |
774 | static int | 775 | static int |
775 | cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid) | 776 | cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid) |
776 | { | 777 | { |
777 | int oplock = 0; | 778 | int oplock = 0; |
778 | int rc; | 779 | int rc; |
779 | __u16 netfid; | 780 | __u16 netfid; |
781 | struct inode *inode = dentry->d_inode; | ||
780 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | 782 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); |
781 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 783 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
782 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 784 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
783 | __u32 dosattr; | 785 | __u32 dosattr, origattr; |
784 | FILE_BASIC_INFO *info_buf; | 786 | FILE_BASIC_INFO *info_buf = NULL; |
785 | 787 | ||
786 | rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, | 788 | rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, |
787 | DELETE|FILE_WRITE_ATTRIBUTES, | 789 | DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, |
788 | CREATE_NOT_DIR|CREATE_DELETE_ON_CLOSE, | ||
789 | &netfid, &oplock, NULL, cifs_sb->local_nls, | 790 | &netfid, &oplock, NULL, cifs_sb->local_nls, |
790 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 791 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
791 | if (rc != 0) | 792 | if (rc != 0) |
792 | goto out; | 793 | goto out; |
793 | 794 | ||
794 | /* set ATTR_HIDDEN and clear ATTR_READONLY */ | 795 | origattr = cifsInode->cifsAttrs; |
795 | cifsInode = CIFS_I(inode); | 796 | if (origattr == 0) |
796 | dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY; | 797 | origattr |= ATTR_NORMAL; |
798 | |||
799 | dosattr = origattr & ~ATTR_READONLY; | ||
797 | if (dosattr == 0) | 800 | if (dosattr == 0) |
798 | dosattr |= ATTR_NORMAL; | 801 | dosattr |= ATTR_NORMAL; |
799 | dosattr |= ATTR_HIDDEN; | 802 | dosattr |= ATTR_HIDDEN; |
800 | 803 | ||
801 | info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL); | 804 | /* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */ |
802 | if (info_buf == NULL) { | 805 | if (dosattr != origattr) { |
803 | rc = -ENOMEM; | 806 | info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL); |
804 | goto out_close; | 807 | if (info_buf == NULL) { |
808 | rc = -ENOMEM; | ||
809 | goto out_close; | ||
810 | } | ||
811 | info_buf->Attributes = cpu_to_le32(dosattr); | ||
812 | rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, | ||
813 | current->tgid); | ||
814 | /* although we would like to mark the file hidden | ||
815 | if that fails we will still try to rename it */ | ||
816 | if (rc != 0) | ||
817 | cifsInode->cifsAttrs = dosattr; | ||
818 | else | ||
819 | dosattr = origattr; /* since not able to change them */ | ||
805 | } | 820 | } |
806 | info_buf->Attributes = cpu_to_le32(dosattr); | ||
807 | rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, current->tgid); | ||
808 | kfree(info_buf); | ||
809 | if (rc != 0) | ||
810 | goto out_close; | ||
811 | cifsInode->cifsAttrs = dosattr; | ||
812 | 821 | ||
813 | /* silly-rename the file */ | 822 | /* rename the file */ |
814 | CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls, | 823 | rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls, |
815 | cifs_sb->mnt_cifs_flags & | 824 | cifs_sb->mnt_cifs_flags & |
816 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 825 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
826 | if (rc != 0) { | ||
827 | rc = -ETXTBSY; | ||
828 | goto undo_setattr; | ||
829 | } | ||
817 | 830 | ||
818 | /* set DELETE_ON_CLOSE */ | 831 | /* try to set DELETE_ON_CLOSE */ |
819 | rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid); | 832 | if (!cifsInode->delete_pending) { |
820 | 833 | rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, | |
821 | /* | 834 | current->tgid); |
822 | * some samba versions return -ENOENT when we try to set the file | 835 | /* |
823 | * disposition here. Likely a samba bug, but work around it for now | 836 | * some samba versions return -ENOENT when we try to set the |
824 | */ | 837 | * file disposition here. Likely a samba bug, but work around |
825 | if (rc == -ENOENT) | 838 | * it for now. This means that some cifsXXX files may hang |
826 | rc = 0; | 839 | * around after they shouldn't. |
840 | * | ||
841 | * BB: remove this hack after more servers have the fix | ||
842 | */ | ||
843 | if (rc == -ENOENT) | ||
844 | rc = 0; | ||
845 | else if (rc != 0) { | ||
846 | rc = -ETXTBSY; | ||
847 | goto undo_rename; | ||
848 | } | ||
849 | cifsInode->delete_pending = true; | ||
850 | } | ||
827 | 851 | ||
828 | out_close: | 852 | out_close: |
829 | CIFSSMBClose(xid, tcon, netfid); | 853 | CIFSSMBClose(xid, tcon, netfid); |
830 | out: | 854 | out: |
855 | kfree(info_buf); | ||
831 | return rc; | 856 | return rc; |
857 | |||
858 | /* | ||
859 | * reset everything back to the original state. Don't bother | ||
860 | * dealing with errors here since we can't do anything about | ||
861 | * them anyway. | ||
862 | */ | ||
863 | undo_rename: | ||
864 | CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name, | ||
865 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | ||
866 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
867 | undo_setattr: | ||
868 | if (dosattr != origattr) { | ||
869 | info_buf->Attributes = cpu_to_le32(origattr); | ||
870 | if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, | ||
871 | current->tgid)) | ||
872 | cifsInode->cifsAttrs = origattr; | ||
873 | } | ||
874 | |||
875 | goto out_close; | ||
832 | } | 876 | } |
833 | 877 | ||
834 | int cifs_unlink(struct inode *dir, struct dentry *dentry) | 878 | int cifs_unlink(struct inode *dir, struct dentry *dentry) |
@@ -878,7 +922,7 @@ psx_del_no_retry: | |||
878 | } else if (rc == -ENOENT) { | 922 | } else if (rc == -ENOENT) { |
879 | d_drop(dentry); | 923 | d_drop(dentry); |
880 | } else if (rc == -ETXTBSY) { | 924 | } else if (rc == -ETXTBSY) { |
881 | rc = cifs_rename_pending_delete(full_path, inode, xid); | 925 | rc = cifs_rename_pending_delete(full_path, dentry, xid); |
882 | if (rc == 0) | 926 | if (rc == 0) |
883 | drop_nlink(inode); | 927 | drop_nlink(inode); |
884 | } else if (rc == -EACCES && dosattr == 0) { | 928 | } else if (rc == -EACCES && dosattr == 0) { |
@@ -1241,22 +1285,21 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath, | |||
1241 | return rc; | 1285 | return rc; |
1242 | } | 1286 | } |
1243 | 1287 | ||
1244 | int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, | 1288 | int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, |
1245 | struct inode *target_inode, struct dentry *target_direntry) | 1289 | struct inode *target_dir, struct dentry *target_dentry) |
1246 | { | 1290 | { |
1247 | char *fromName = NULL; | 1291 | char *fromName = NULL; |
1248 | char *toName = NULL; | 1292 | char *toName = NULL; |
1249 | struct cifs_sb_info *cifs_sb_source; | 1293 | struct cifs_sb_info *cifs_sb_source; |
1250 | struct cifs_sb_info *cifs_sb_target; | 1294 | struct cifs_sb_info *cifs_sb_target; |
1251 | struct cifsTconInfo *pTcon; | 1295 | struct cifsTconInfo *tcon; |
1252 | FILE_UNIX_BASIC_INFO *info_buf_source = NULL; | 1296 | FILE_UNIX_BASIC_INFO *info_buf_source = NULL; |
1253 | FILE_UNIX_BASIC_INFO *info_buf_target; | 1297 | FILE_UNIX_BASIC_INFO *info_buf_target; |
1254 | int xid; | 1298 | int xid, rc, tmprc; |
1255 | int rc; | ||
1256 | 1299 | ||
1257 | cifs_sb_target = CIFS_SB(target_inode->i_sb); | 1300 | cifs_sb_target = CIFS_SB(target_dir->i_sb); |
1258 | cifs_sb_source = CIFS_SB(source_inode->i_sb); | 1301 | cifs_sb_source = CIFS_SB(source_dir->i_sb); |
1259 | pTcon = cifs_sb_source->tcon; | 1302 | tcon = cifs_sb_source->tcon; |
1260 | 1303 | ||
1261 | xid = GetXid(); | 1304 | xid = GetXid(); |
1262 | 1305 | ||
@@ -1264,7 +1307,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, | |||
1264 | * BB: this might be allowed if same server, but different share. | 1307 | * BB: this might be allowed if same server, but different share. |
1265 | * Consider adding support for this | 1308 | * Consider adding support for this |
1266 | */ | 1309 | */ |
1267 | if (pTcon != cifs_sb_target->tcon) { | 1310 | if (tcon != cifs_sb_target->tcon) { |
1268 | rc = -EXDEV; | 1311 | rc = -EXDEV; |
1269 | goto cifs_rename_exit; | 1312 | goto cifs_rename_exit; |
1270 | } | 1313 | } |
@@ -1273,65 +1316,65 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry, | |||
1273 | * we already have the rename sem so we do not need to | 1316 | * we already have the rename sem so we do not need to |
1274 | * grab it again here to protect the path integrity | 1317 | * grab it again here to protect the path integrity |
1275 | */ | 1318 | */ |
1276 | fromName = build_path_from_dentry(source_direntry); | 1319 | fromName = build_path_from_dentry(source_dentry); |
1277 | if (fromName == NULL) { | 1320 | if (fromName == NULL) { |
1278 | rc = -ENOMEM; | 1321 | rc = -ENOMEM; |
1279 | goto cifs_rename_exit; | 1322 | goto cifs_rename_exit; |
1280 | } | 1323 | } |
1281 | 1324 | ||
1282 | toName = build_path_from_dentry(target_direntry); | 1325 | toName = build_path_from_dentry(target_dentry); |
1283 | if (toName == NULL) { | 1326 | if (toName == NULL) { |
1284 | rc = -ENOMEM; | 1327 | rc = -ENOMEM; |
1285 | goto cifs_rename_exit; | 1328 | goto cifs_rename_exit; |
1286 | } | 1329 | } |
1287 | 1330 | ||
1288 | rc = cifs_do_rename(xid, source_direntry, fromName, | 1331 | rc = cifs_do_rename(xid, source_dentry, fromName, |
1289 | target_direntry, toName); | 1332 | target_dentry, toName); |
1290 | 1333 | ||
1291 | if (rc == -EEXIST) { | 1334 | if (rc == -EEXIST && tcon->unix_ext) { |
1292 | if (pTcon->unix_ext) { | 1335 | /* |
1293 | /* | 1336 | * Are src and dst hardlinks of same inode? We can |
1294 | * Are src and dst hardlinks of same inode? We can | 1337 | * only tell with unix extensions enabled |
1295 | * only tell with unix extensions enabled | 1338 | */ |
1296 | */ | 1339 | info_buf_source = |
1297 | info_buf_source = | 1340 | kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), |
1298 | kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), | 1341 | GFP_KERNEL); |
1299 | GFP_KERNEL); | 1342 | if (info_buf_source == NULL) { |
1300 | if (info_buf_source == NULL) | 1343 | rc = -ENOMEM; |
1301 | goto unlink_target; | 1344 | goto cifs_rename_exit; |
1302 | 1345 | } | |
1303 | info_buf_target = info_buf_source + 1; | ||
1304 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, | ||
1305 | info_buf_source, | ||
1306 | cifs_sb_source->local_nls, | ||
1307 | cifs_sb_source->mnt_cifs_flags & | ||
1308 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1309 | if (rc != 0) | ||
1310 | goto unlink_target; | ||
1311 | |||
1312 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, | ||
1313 | toName, info_buf_target, | ||
1314 | cifs_sb_target->local_nls, | ||
1315 | /* remap based on source sb */ | ||
1316 | cifs_sb_source->mnt_cifs_flags & | ||
1317 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1318 | 1346 | ||
1319 | if (rc == 0 && (info_buf_source->UniqueId == | 1347 | info_buf_target = info_buf_source + 1; |
1320 | info_buf_target->UniqueId)) | 1348 | tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName, |
1321 | /* same file, POSIX says that this is a noop */ | 1349 | info_buf_source, |
1322 | goto cifs_rename_exit; | 1350 | cifs_sb_source->local_nls, |
1323 | } /* else ... BB we could add the same check for Windows by | 1351 | cifs_sb_source->mnt_cifs_flags & |
1352 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1353 | if (tmprc != 0) | ||
1354 | goto unlink_target; | ||
1355 | |||
1356 | tmprc = CIFSSMBUnixQPathInfo(xid, tcon, | ||
1357 | toName, info_buf_target, | ||
1358 | cifs_sb_target->local_nls, | ||
1359 | /* remap based on source sb */ | ||
1360 | cifs_sb_source->mnt_cifs_flags & | ||
1361 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1362 | |||
1363 | if (tmprc == 0 && (info_buf_source->UniqueId == | ||
1364 | info_buf_target->UniqueId)) | ||
1365 | /* same file, POSIX says that this is a noop */ | ||
1366 | goto cifs_rename_exit; | ||
1367 | } /* else ... BB we could add the same check for Windows by | ||
1324 | checking the UniqueId via FILE_INTERNAL_INFO */ | 1368 | checking the UniqueId via FILE_INTERNAL_INFO */ |
1369 | |||
1325 | unlink_target: | 1370 | unlink_target: |
1326 | /* | 1371 | if ((rc == -EACCES) || (rc == -EEXIST)) { |
1327 | * we either can not tell the files are hardlinked (as with | 1372 | tmprc = cifs_unlink(target_dir, target_dentry); |
1328 | * Windows servers) or files are not hardlinked. Delete the | 1373 | if (tmprc) |
1329 | * target manually before renaming to follow POSIX rather than | 1374 | goto cifs_rename_exit; |
1330 | * Windows semantics | 1375 | |
1331 | */ | 1376 | rc = cifs_do_rename(xid, source_dentry, fromName, |
1332 | cifs_unlink(target_inode, target_direntry); | 1377 | target_dentry, toName); |
1333 | rc = cifs_do_rename(xid, source_direntry, fromName, | ||
1334 | target_direntry, toName); | ||
1335 | } | 1378 | } |
1336 | 1379 | ||
1337 | cifs_rename_exit: | 1380 | cifs_rename_exit: |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 765adf12d54f..58d57299f2a0 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -762,14 +762,15 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
762 | rc)); | 762 | rc)); |
763 | return rc; | 763 | return rc; |
764 | } | 764 | } |
765 | cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile); | ||
765 | } | 766 | } |
766 | 767 | ||
767 | while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && | 768 | while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && |
768 | (rc == 0) && !cifsFile->srch_inf.endOfSearch) { | 769 | (rc == 0) && !cifsFile->srch_inf.endOfSearch) { |
769 | cFYI(1, ("calling findnext2")); | 770 | cFYI(1, ("calling findnext2")); |
770 | cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile); | ||
771 | rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, | 771 | rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, |
772 | &cifsFile->srch_inf); | 772 | &cifsFile->srch_inf); |
773 | cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile); | ||
773 | if (rc) | 774 | if (rc) |
774 | return -ENOENT; | 775 | return -ENOENT; |
775 | } | 776 | } |