mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 10:57:46 +00:00
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
This commit is contained in:
commit
db563fc2e8
9 changed files with 260 additions and 126 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
Version 1.55
|
||||||
|
------------
|
||||||
|
Various fixes to make delete of open files behavior more predictable
|
||||||
|
(when delete of an open file fails we mark the file as "delete-on-close"
|
||||||
|
in a way that more servers accept, but only if we can first rename the
|
||||||
|
file to a temporary name). Add experimental support for more safely
|
||||||
|
handling fcntl(F_SETLEASE).
|
||||||
|
|
||||||
Version 1.54
|
Version 1.54
|
||||||
------------
|
------------
|
||||||
Fix premature write failure on congested networks (we would give up
|
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
|
||||||
authentication (requires setting SecurityFlags to 0x30030 to enable
|
authentication (requires setting SecurityFlags to 0x30030 to enable
|
||||||
lanman and plain text though). Fix writes to be at correct offset when
|
lanman and plain text though). Fix writes to be at correct offset when
|
||||||
file is open with O_APPEND and file is on a directio (forcediretio) mount.
|
file is open with O_APPEND and file is on a directio (forcediretio) mount.
|
||||||
|
Fix bug in rewinding readdir directory searches. Add nodfs mount option.
|
||||||
|
|
||||||
Version 1.53
|
Version 1.53
|
||||||
------------
|
------------
|
||||||
|
|
|
@ -463,6 +463,9 @@ A partial list of the supported mount options follows:
|
||||||
with cifs style mandatory byte range locks (and most
|
with cifs style mandatory byte range locks (and most
|
||||||
cifs servers do not yet support requesting advisory
|
cifs servers do not yet support requesting advisory
|
||||||
byte range locks).
|
byte range locks).
|
||||||
|
nodfs Disable DFS (global name space support) even if the
|
||||||
|
server claims to support it. This can help work around
|
||||||
|
a problem with parsing of DFS paths with Samba 3.0.24 server.
|
||||||
remount remount the share (often used to change from ro to rw mounts
|
remount remount the share (often used to change from ro to rw mounts
|
||||||
or vice versa)
|
or vice versa)
|
||||||
cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for
|
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:
|
||||||
Note that this differs from the sign mount option in that it
|
Note that this differs from the sign mount option in that it
|
||||||
causes encryption of data sent over this mounted share but other
|
causes encryption of data sent over this mounted share but other
|
||||||
shares mounted to the same server are unaffected.
|
shares mounted to the same server are unaffected.
|
||||||
|
locallease This option is rarely needed. Fcntl F_SETLEASE is
|
||||||
|
used by some applications such as Samba and NFSv4 server to
|
||||||
|
check to see whether a file is cacheable. CIFS has no way
|
||||||
|
to explicitly request a lease, but can check whether a file
|
||||||
|
is cacheable (oplocked). Unfortunately, even if a file
|
||||||
|
is not oplocked, it could still be cacheable (ie cifs client
|
||||||
|
could grant fcntl leases if no other local processes are using
|
||||||
|
the file) for cases for example such as when the server does not
|
||||||
|
support oplocks and the user is sure that the only updates to
|
||||||
|
the file will be from this client. Specifying this mount option
|
||||||
|
will allow the cifs client to check for leases (only) locally
|
||||||
|
for files which are not oplocked instead of denying leases
|
||||||
|
in that case. (EXPERIMENTAL)
|
||||||
sec Security mode. Allowed values are:
|
sec Security mode. Allowed values are:
|
||||||
none attempt to connection as a null user (no name)
|
none attempt to connection as a null user (no name)
|
||||||
krb5 Use Kerberos version 5 authentication
|
krb5 Use Kerberos version 5 authentication
|
||||||
|
@ -638,6 +654,9 @@ requires enabling CONFIG_CIFS_EXPERIMENTAL
|
||||||
cifsacl support needed to retrieve approximated mode bits based on
|
cifsacl support needed to retrieve approximated mode bits based on
|
||||||
the contents on the CIFS ACL.
|
the contents on the CIFS ACL.
|
||||||
|
|
||||||
|
lease support: cifs will check the oplock state before calling into
|
||||||
|
the vfs to see if we can grant a lease on a file.
|
||||||
|
|
||||||
DNOTIFY fcntl: needed for support of directory change
|
DNOTIFY fcntl: needed for support of directory change
|
||||||
notification and perhaps later for file leases)
|
notification and perhaps later for file leases)
|
||||||
|
|
||||||
|
|
|
@ -312,6 +312,7 @@ cifs_alloc_inode(struct super_block *sb)
|
||||||
file data or metadata */
|
file data or metadata */
|
||||||
cifs_inode->clientCanCacheRead = false;
|
cifs_inode->clientCanCacheRead = false;
|
||||||
cifs_inode->clientCanCacheAll = false;
|
cifs_inode->clientCanCacheAll = false;
|
||||||
|
cifs_inode->delete_pending = false;
|
||||||
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
|
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
|
||||||
|
|
||||||
/* Can not set i_flags here - they get immediately overwritten
|
/* 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)
|
||||||
return generic_file_llseek_unlocked(file, offset, origin);
|
return generic_file_llseek_unlocked(file, offset, origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
|
static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
|
||||||
|
{
|
||||||
|
/* note that this is called by vfs setlease with the BKL held
|
||||||
|
although I doubt that BKL is needed here in cifs */
|
||||||
|
struct inode *inode = file->f_path.dentry->d_inode;
|
||||||
|
|
||||||
|
if (!(S_ISREG(inode->i_mode)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* check if file is oplocked */
|
||||||
|
if (((arg == F_RDLCK) &&
|
||||||
|
(CIFS_I(inode)->clientCanCacheRead)) ||
|
||||||
|
((arg == F_WRLCK) &&
|
||||||
|
(CIFS_I(inode)->clientCanCacheAll)))
|
||||||
|
return generic_setlease(file, arg, lease);
|
||||||
|
else if (CIFS_SB(inode->i_sb)->tcon->local_lease &&
|
||||||
|
!CIFS_I(inode)->clientCanCacheRead)
|
||||||
|
/* If the server claims to support oplock on this
|
||||||
|
file, then we still need to check oplock even
|
||||||
|
if the local_lease mount option is set, but there
|
||||||
|
are servers which do not support oplock for which
|
||||||
|
this mount option may be useful if the user
|
||||||
|
knows that the file won't be changed on the server
|
||||||
|
by anyone else */
|
||||||
|
return generic_setlease(file, arg, lease);
|
||||||
|
else
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct file_system_type cifs_fs_type = {
|
struct file_system_type cifs_fs_type = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "cifs",
|
.name = "cifs",
|
||||||
|
@ -698,6 +730,7 @@ const struct file_operations cifs_file_ops = {
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
.dir_notify = cifs_dir_notify,
|
.dir_notify = cifs_dir_notify,
|
||||||
|
.setlease = cifs_setlease,
|
||||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -718,6 +751,7 @@ const struct file_operations cifs_file_direct_ops = {
|
||||||
.llseek = cifs_llseek,
|
.llseek = cifs_llseek,
|
||||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
.dir_notify = cifs_dir_notify,
|
.dir_notify = cifs_dir_notify,
|
||||||
|
.setlease = cifs_setlease,
|
||||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||||
};
|
};
|
||||||
const struct file_operations cifs_file_nobrl_ops = {
|
const struct file_operations cifs_file_nobrl_ops = {
|
||||||
|
@ -738,6 +772,7 @@ const struct file_operations cifs_file_nobrl_ops = {
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
.dir_notify = cifs_dir_notify,
|
.dir_notify = cifs_dir_notify,
|
||||||
|
.setlease = cifs_setlease,
|
||||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -757,6 +792,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
|
||||||
.llseek = cifs_llseek,
|
.llseek = cifs_llseek,
|
||||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
.dir_notify = cifs_dir_notify,
|
.dir_notify = cifs_dir_notify,
|
||||||
|
.setlease = cifs_setlease,
|
||||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -949,6 +985,12 @@ static int cifs_oplock_thread(void *dummyarg)
|
||||||
the call */
|
the call */
|
||||||
/* mutex_lock(&inode->i_mutex);*/
|
/* mutex_lock(&inode->i_mutex);*/
|
||||||
if (S_ISREG(inode->i_mode)) {
|
if (S_ISREG(inode->i_mode)) {
|
||||||
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
|
if (CIFS_I(inode)->clientCanCacheAll == 0)
|
||||||
|
break_lease(inode, FMODE_READ);
|
||||||
|
else if (CIFS_I(inode)->clientCanCacheRead == 0)
|
||||||
|
break_lease(inode, FMODE_WRITE);
|
||||||
|
#endif
|
||||||
rc = filemap_fdatawrite(inode->i_mapping);
|
rc = filemap_fdatawrite(inode->i_mapping);
|
||||||
if (CIFS_I(inode)->clientCanCacheRead == 0) {
|
if (CIFS_I(inode)->clientCanCacheRead == 0) {
|
||||||
waitrc = filemap_fdatawait(
|
waitrc = filemap_fdatawait(
|
||||||
|
|
|
@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||||
extern const struct export_operations cifs_export_ops;
|
extern const struct export_operations cifs_export_ops;
|
||||||
#endif /* EXPERIMENTAL */
|
#endif /* EXPERIMENTAL */
|
||||||
|
|
||||||
#define CIFS_VERSION "1.54"
|
#define CIFS_VERSION "1.55"
|
||||||
#endif /* _CIFSFS_H */
|
#endif /* _CIFSFS_H */
|
||||||
|
|
|
@ -285,6 +285,7 @@ struct cifsTconInfo {
|
||||||
bool seal:1; /* transport encryption for this mounted share */
|
bool seal:1; /* transport encryption for this mounted share */
|
||||||
bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol
|
bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol
|
||||||
for this mount even if server would support */
|
for this mount even if server would support */
|
||||||
|
bool local_lease:1; /* check leases (only) on local system not remote */
|
||||||
/* BB add field for back pointer to sb struct(s)? */
|
/* BB add field for back pointer to sb struct(s)? */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -353,6 +354,7 @@ struct cifsInodeInfo {
|
||||||
bool clientCanCacheRead:1; /* read oplock */
|
bool clientCanCacheRead:1; /* read oplock */
|
||||||
bool clientCanCacheAll:1; /* read and writebehind oplock */
|
bool clientCanCacheAll:1; /* read and writebehind oplock */
|
||||||
bool oplockPending:1;
|
bool oplockPending:1;
|
||||||
|
bool delete_pending:1; /* DELETE_ON_CLOSE is set */
|
||||||
struct inode vfs_inode;
|
struct inode vfs_inode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1309,6 +1309,7 @@ SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
|
||||||
cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
|
cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
|
||||||
pfile_info->EndOfFile = pfile_info->AllocationSize;
|
pfile_info->EndOfFile = pfile_info->AllocationSize;
|
||||||
pfile_info->NumberOfLinks = cpu_to_le32(1);
|
pfile_info->NumberOfLinks = cpu_to_le32(1);
|
||||||
|
pfile_info->DeletePending = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1410,6 +1411,7 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
|
||||||
pfile_info->AllocationSize = pSMBr->AllocationSize;
|
pfile_info->AllocationSize = pSMBr->AllocationSize;
|
||||||
pfile_info->EndOfFile = pSMBr->EndOfFile;
|
pfile_info->EndOfFile = pSMBr->EndOfFile;
|
||||||
pfile_info->NumberOfLinks = cpu_to_le32(1);
|
pfile_info->NumberOfLinks = cpu_to_le32(1);
|
||||||
|
pfile_info->DeletePending = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,8 @@ struct smb_vol {
|
||||||
bool nocase:1; /* request case insensitive filenames */
|
bool nocase:1; /* request case insensitive filenames */
|
||||||
bool nobrl:1; /* disable sending byte range locks to srv */
|
bool nobrl:1; /* disable sending byte range locks to srv */
|
||||||
bool seal:1; /* request transport encryption on share */
|
bool seal:1; /* request transport encryption on share */
|
||||||
|
bool nodfs:1; /* Do not request DFS, even if available */
|
||||||
|
bool local_lease:1; /* check leases only on local system, not remote */
|
||||||
unsigned int rsize;
|
unsigned int rsize;
|
||||||
unsigned int wsize;
|
unsigned int wsize;
|
||||||
unsigned int sockopt;
|
unsigned int sockopt;
|
||||||
|
@ -124,7 +126,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
||||||
struct mid_q_entry *mid_entry;
|
struct mid_q_entry *mid_entry;
|
||||||
|
|
||||||
spin_lock(&GlobalMid_Lock);
|
spin_lock(&GlobalMid_Lock);
|
||||||
if (kthread_should_stop()) {
|
if (server->tcpStatus == CifsExiting) {
|
||||||
/* the demux thread will exit normally
|
/* the demux thread will exit normally
|
||||||
next time through the loop */
|
next time through the loop */
|
||||||
spin_unlock(&GlobalMid_Lock);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
|
@ -184,7 +186,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
||||||
spin_unlock(&GlobalMid_Lock);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
up(&server->tcpSem);
|
up(&server->tcpSem);
|
||||||
|
|
||||||
while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
|
while ((server->tcpStatus != CifsExiting) &&
|
||||||
|
(server->tcpStatus != CifsGood)) {
|
||||||
try_to_freeze();
|
try_to_freeze();
|
||||||
if (server->protocolType == IPV6) {
|
if (server->protocolType == IPV6) {
|
||||||
rc = ipv6_connect(&server->addr.sockAddr6,
|
rc = ipv6_connect(&server->addr.sockAddr6,
|
||||||
|
@ -201,7 +204,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
||||||
} else {
|
} else {
|
||||||
atomic_inc(&tcpSesReconnectCount);
|
atomic_inc(&tcpSesReconnectCount);
|
||||||
spin_lock(&GlobalMid_Lock);
|
spin_lock(&GlobalMid_Lock);
|
||||||
if (!kthread_should_stop())
|
if (server->tcpStatus != CifsExiting)
|
||||||
server->tcpStatus = CifsGood;
|
server->tcpStatus = CifsGood;
|
||||||
server->sequence_number = 0;
|
server->sequence_number = 0;
|
||||||
spin_unlock(&GlobalMid_Lock);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
|
@ -356,7 +359,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
|
||||||
set_freezable();
|
set_freezable();
|
||||||
while (!kthread_should_stop()) {
|
while (server->tcpStatus != CifsExiting) {
|
||||||
if (try_to_freeze())
|
if (try_to_freeze())
|
||||||
continue;
|
continue;
|
||||||
if (bigbuf == NULL) {
|
if (bigbuf == NULL) {
|
||||||
|
@ -397,7 +400,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
||||||
kernel_recvmsg(csocket, &smb_msg,
|
kernel_recvmsg(csocket, &smb_msg,
|
||||||
&iov, 1, pdu_length, 0 /* BB other flags? */);
|
&iov, 1, pdu_length, 0 /* BB other flags? */);
|
||||||
|
|
||||||
if (kthread_should_stop()) {
|
if (server->tcpStatus == CifsExiting) {
|
||||||
break;
|
break;
|
||||||
} else if (server->tcpStatus == CifsNeedReconnect) {
|
} else if (server->tcpStatus == CifsNeedReconnect) {
|
||||||
cFYI(1, ("Reconnect after server stopped responding"));
|
cFYI(1, ("Reconnect after server stopped responding"));
|
||||||
|
@ -522,7 +525,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
||||||
total_read += length) {
|
total_read += length) {
|
||||||
length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
|
length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
|
||||||
pdu_length - total_read, 0);
|
pdu_length - total_read, 0);
|
||||||
if (kthread_should_stop() ||
|
if ((server->tcpStatus == CifsExiting) ||
|
||||||
(length == -EINTR)) {
|
(length == -EINTR)) {
|
||||||
/* then will exit */
|
/* then will exit */
|
||||||
reconnect = 2;
|
reconnect = 2;
|
||||||
|
@ -651,14 +654,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
||||||
spin_unlock(&GlobalMid_Lock);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
wake_up_all(&server->response_q);
|
wake_up_all(&server->response_q);
|
||||||
|
|
||||||
/* don't exit until kthread_stop is called */
|
|
||||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
||||||
while (!kthread_should_stop()) {
|
|
||||||
schedule();
|
|
||||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
||||||
}
|
|
||||||
set_current_state(TASK_RUNNING);
|
|
||||||
|
|
||||||
/* check if we have blocked requests that need to free */
|
/* check if we have blocked requests that need to free */
|
||||||
/* Note that cifs_max_pending is normally 50, but
|
/* Note that cifs_max_pending is normally 50, but
|
||||||
can be set at module install time to as little as two */
|
can be set at module install time to as little as two */
|
||||||
|
@ -755,6 +750,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
||||||
write_unlock(&GlobalSMBSeslock);
|
write_unlock(&GlobalSMBSeslock);
|
||||||
|
|
||||||
kfree(server->hostname);
|
kfree(server->hostname);
|
||||||
|
task_to_wake = xchg(&server->tsk, NULL);
|
||||||
kfree(server);
|
kfree(server);
|
||||||
|
|
||||||
length = atomic_dec_return(&tcpSesAllocCount);
|
length = atomic_dec_return(&tcpSesAllocCount);
|
||||||
|
@ -762,6 +758,16 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
||||||
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
|
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
|
||||||
|
/* if server->tsk was NULL then wait for a signal before exiting */
|
||||||
|
if (!task_to_wake) {
|
||||||
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
|
while (!signal_pending(current)) {
|
||||||
|
schedule();
|
||||||
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
|
}
|
||||||
|
set_current_state(TASK_RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1218,6 +1224,8 @@ cifs_parse_mount_options(char *options, const char *devname,
|
||||||
vol->sfu_emul = 1;
|
vol->sfu_emul = 1;
|
||||||
} else if (strnicmp(data, "nosfu", 5) == 0) {
|
} else if (strnicmp(data, "nosfu", 5) == 0) {
|
||||||
vol->sfu_emul = 0;
|
vol->sfu_emul = 0;
|
||||||
|
} else if (strnicmp(data, "nodfs", 5) == 0) {
|
||||||
|
vol->nodfs = 1;
|
||||||
} else if (strnicmp(data, "posixpaths", 10) == 0) {
|
} else if (strnicmp(data, "posixpaths", 10) == 0) {
|
||||||
vol->posix_paths = 1;
|
vol->posix_paths = 1;
|
||||||
} else if (strnicmp(data, "noposixpaths", 12) == 0) {
|
} else if (strnicmp(data, "noposixpaths", 12) == 0) {
|
||||||
|
@ -1268,6 +1276,10 @@ cifs_parse_mount_options(char *options, const char *devname,
|
||||||
vol->no_psx_acl = 0;
|
vol->no_psx_acl = 0;
|
||||||
} else if (strnicmp(data, "noacl", 5) == 0) {
|
} else if (strnicmp(data, "noacl", 5) == 0) {
|
||||||
vol->no_psx_acl = 1;
|
vol->no_psx_acl = 1;
|
||||||
|
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||||
|
} else if (strnicmp(data, "locallease", 6) == 0) {
|
||||||
|
vol->local_lease = 1;
|
||||||
|
#endif
|
||||||
} else if (strnicmp(data, "sign", 4) == 0) {
|
} else if (strnicmp(data, "sign", 4) == 0) {
|
||||||
vol->secFlg |= CIFSSEC_MUST_SIGN;
|
vol->secFlg |= CIFSSEC_MUST_SIGN;
|
||||||
} else if (strnicmp(data, "seal", 4) == 0) {
|
} else if (strnicmp(data, "seal", 4) == 0) {
|
||||||
|
@ -1845,6 +1857,16 @@ convert_delimiter(char *path, char delim)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
kill_cifsd(struct TCP_Server_Info *server)
|
||||||
|
{
|
||||||
|
struct task_struct *task;
|
||||||
|
|
||||||
|
task = xchg(&server->tsk, NULL);
|
||||||
|
if (task)
|
||||||
|
force_sig(SIGKILL, task);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||||
char *mount_data, const char *devname)
|
char *mount_data, const char *devname)
|
||||||
|
@ -2166,6 +2188,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||||
for the retry flag is used */
|
for the retry flag is used */
|
||||||
tcon->retry = volume_info.retry;
|
tcon->retry = volume_info.retry;
|
||||||
tcon->nocase = volume_info.nocase;
|
tcon->nocase = volume_info.nocase;
|
||||||
|
tcon->local_lease = volume_info.local_lease;
|
||||||
if (tcon->seal != volume_info.seal)
|
if (tcon->seal != volume_info.seal)
|
||||||
cERROR(1, ("transport encryption setting "
|
cERROR(1, ("transport encryption setting "
|
||||||
"conflicts with existing tid"));
|
"conflicts with existing tid"));
|
||||||
|
@ -2197,6 +2220,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||||
volume_info.UNC,
|
volume_info.UNC,
|
||||||
tcon, cifs_sb->local_nls);
|
tcon, cifs_sb->local_nls);
|
||||||
cFYI(1, ("CIFS Tcon rc = %d", rc));
|
cFYI(1, ("CIFS Tcon rc = %d", rc));
|
||||||
|
if (volume_info.nodfs) {
|
||||||
|
tcon->Flags &=
|
||||||
|
~SMB_SHARE_IS_IN_DFS;
|
||||||
|
cFYI(1, ("DFS disabled (%d)",
|
||||||
|
tcon->Flags));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
atomic_inc(&pSesInfo->inUse);
|
atomic_inc(&pSesInfo->inUse);
|
||||||
|
@ -2225,14 +2254,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||||
spin_lock(&GlobalMid_Lock);
|
spin_lock(&GlobalMid_Lock);
|
||||||
srvTcp->tcpStatus = CifsExiting;
|
srvTcp->tcpStatus = CifsExiting;
|
||||||
spin_unlock(&GlobalMid_Lock);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
if (srvTcp->tsk) {
|
kill_cifsd(srvTcp);
|
||||||
/* If we could verify that kthread_stop would
|
|
||||||
always wake up processes blocked in
|
|
||||||
tcp in recv_mesg then we could remove the
|
|
||||||
send_sig call */
|
|
||||||
force_sig(SIGKILL, srvTcp->tsk);
|
|
||||||
kthread_stop(srvTcp->tsk);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* If find_unc succeeded then rc == 0 so we can not end */
|
/* If find_unc succeeded then rc == 0 so we can not end */
|
||||||
if (tcon) /* up accidently freeing someone elses tcon struct */
|
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,
|
||||||
temp_rc = CIFSSMBLogoff(xid, pSesInfo);
|
temp_rc = CIFSSMBLogoff(xid, pSesInfo);
|
||||||
/* if the socketUseCount is now zero */
|
/* if the socketUseCount is now zero */
|
||||||
if ((temp_rc == -ESHUTDOWN) &&
|
if ((temp_rc == -ESHUTDOWN) &&
|
||||||
(pSesInfo->server) &&
|
(pSesInfo->server))
|
||||||
(pSesInfo->server->tsk)) {
|
kill_cifsd(pSesInfo->server);
|
||||||
force_sig(SIGKILL,
|
|
||||||
pSesInfo->server->tsk);
|
|
||||||
kthread_stop(pSesInfo->server->tsk);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
cFYI(1, ("No session or bad tcon"));
|
cFYI(1, ("No session or bad tcon"));
|
||||||
if ((pSesInfo->server) &&
|
if (pSesInfo->server) {
|
||||||
(pSesInfo->server->tsk)) {
|
spin_lock(&GlobalMid_Lock);
|
||||||
force_sig(SIGKILL,
|
srvTcp->tcpStatus = CifsExiting;
|
||||||
pSesInfo->server->tsk);
|
spin_unlock(&GlobalMid_Lock);
|
||||||
kthread_stop(pSesInfo->server->tsk);
|
kill_cifsd(pSesInfo->server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sesInfoFree(pSesInfo);
|
sesInfoFree(pSesInfo);
|
||||||
|
@ -3544,7 +3562,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int xid;
|
int xid;
|
||||||
struct cifsSesInfo *ses = NULL;
|
struct cifsSesInfo *ses = NULL;
|
||||||
struct task_struct *cifsd_task;
|
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
xid = GetXid();
|
xid = GetXid();
|
||||||
|
@ -3560,7 +3577,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
|
||||||
tconInfoFree(cifs_sb->tcon);
|
tconInfoFree(cifs_sb->tcon);
|
||||||
if ((ses) && (ses->server)) {
|
if ((ses) && (ses->server)) {
|
||||||
/* save off task so we do not refer to ses later */
|
/* save off task so we do not refer to ses later */
|
||||||
cifsd_task = ses->server->tsk;
|
|
||||||
cFYI(1, ("About to do SMBLogoff "));
|
cFYI(1, ("About to do SMBLogoff "));
|
||||||
rc = CIFSSMBLogoff(xid, ses);
|
rc = CIFSSMBLogoff(xid, ses);
|
||||||
if (rc == -EBUSY) {
|
if (rc == -EBUSY) {
|
||||||
|
@ -3568,10 +3584,8 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
|
||||||
return 0;
|
return 0;
|
||||||
} else if (rc == -ESHUTDOWN) {
|
} else if (rc == -ESHUTDOWN) {
|
||||||
cFYI(1, ("Waking up socket by sending signal"));
|
cFYI(1, ("Waking up socket by sending signal"));
|
||||||
if (cifsd_task) {
|
if (ses->server)
|
||||||
force_sig(SIGKILL, cifsd_task);
|
kill_cifsd(ses->server);
|
||||||
kthread_stop(cifsd_task);
|
|
||||||
}
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
} /* else - we have an smb session
|
} /* else - we have an smb session
|
||||||
left on this socket do not kill cifsd */
|
left on this socket do not kill cifsd */
|
||||||
|
@ -3701,7 +3715,9 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
|
||||||
cERROR(1, ("Send error in SessSetup = %d", rc));
|
cERROR(1, ("Send error in SessSetup = %d", rc));
|
||||||
} else {
|
} else {
|
||||||
cFYI(1, ("CIFS Session Established successfully"));
|
cFYI(1, ("CIFS Session Established successfully"));
|
||||||
|
spin_lock(&GlobalMid_Lock);
|
||||||
pSesInfo->status = CifsGood;
|
pSesInfo->status = CifsGood;
|
||||||
|
spin_unlock(&GlobalMid_Lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
ss_err_exit:
|
ss_err_exit:
|
||||||
|
|
141
fs/cifs/inode.c
141
fs/cifs/inode.c
|
@ -506,6 +506,7 @@ int cifs_get_inode_info(struct inode **pinode,
|
||||||
inode = *pinode;
|
inode = *pinode;
|
||||||
cifsInfo = CIFS_I(inode);
|
cifsInfo = CIFS_I(inode);
|
||||||
cifsInfo->cifsAttrs = attr;
|
cifsInfo->cifsAttrs = attr;
|
||||||
|
cifsInfo->delete_pending = pfindData->DeletePending ? true : false;
|
||||||
cFYI(1, ("Old time %ld", cifsInfo->time));
|
cFYI(1, ("Old time %ld", cifsInfo->time));
|
||||||
cifsInfo->time = jiffies;
|
cifsInfo->time = jiffies;
|
||||||
cFYI(1, ("New time %ld", cifsInfo->time));
|
cFYI(1, ("New time %ld", cifsInfo->time));
|
||||||
|
@ -772,63 +773,106 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
|
||||||
* anything else.
|
* anything else.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
cifs_rename_pending_delete(char *full_path, struct inode *inode, int xid)
|
cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
|
||||||
{
|
{
|
||||||
int oplock = 0;
|
int oplock = 0;
|
||||||
int rc;
|
int rc;
|
||||||
__u16 netfid;
|
__u16 netfid;
|
||||||
|
struct inode *inode = dentry->d_inode;
|
||||||
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
|
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
|
||||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||||
struct cifsTconInfo *tcon = cifs_sb->tcon;
|
struct cifsTconInfo *tcon = cifs_sb->tcon;
|
||||||
__u32 dosattr;
|
__u32 dosattr, origattr;
|
||||||
FILE_BASIC_INFO *info_buf;
|
FILE_BASIC_INFO *info_buf = NULL;
|
||||||
|
|
||||||
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
|
rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
|
||||||
DELETE|FILE_WRITE_ATTRIBUTES,
|
DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
|
||||||
CREATE_NOT_DIR|CREATE_DELETE_ON_CLOSE,
|
|
||||||
&netfid, &oplock, NULL, cifs_sb->local_nls,
|
&netfid, &oplock, NULL, cifs_sb->local_nls,
|
||||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* set ATTR_HIDDEN and clear ATTR_READONLY */
|
origattr = cifsInode->cifsAttrs;
|
||||||
cifsInode = CIFS_I(inode);
|
if (origattr == 0)
|
||||||
dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
|
origattr |= ATTR_NORMAL;
|
||||||
|
|
||||||
|
dosattr = origattr & ~ATTR_READONLY;
|
||||||
if (dosattr == 0)
|
if (dosattr == 0)
|
||||||
dosattr |= ATTR_NORMAL;
|
dosattr |= ATTR_NORMAL;
|
||||||
dosattr |= ATTR_HIDDEN;
|
dosattr |= ATTR_HIDDEN;
|
||||||
|
|
||||||
|
/* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
|
||||||
|
if (dosattr != origattr) {
|
||||||
info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
|
info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
|
||||||
if (info_buf == NULL) {
|
if (info_buf == NULL) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out_close;
|
goto out_close;
|
||||||
}
|
}
|
||||||
info_buf->Attributes = cpu_to_le32(dosattr);
|
info_buf->Attributes = cpu_to_le32(dosattr);
|
||||||
rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid, current->tgid);
|
rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
|
||||||
kfree(info_buf);
|
current->tgid);
|
||||||
|
/* although we would like to mark the file hidden
|
||||||
|
if that fails we will still try to rename it */
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
goto out_close;
|
|
||||||
cifsInode->cifsAttrs = dosattr;
|
cifsInode->cifsAttrs = dosattr;
|
||||||
|
else
|
||||||
|
dosattr = origattr; /* since not able to change them */
|
||||||
|
}
|
||||||
|
|
||||||
/* silly-rename the file */
|
/* rename the file */
|
||||||
CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
|
rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
|
||||||
cifs_sb->mnt_cifs_flags &
|
cifs_sb->mnt_cifs_flags &
|
||||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
|
if (rc != 0) {
|
||||||
|
rc = -ETXTBSY;
|
||||||
|
goto undo_setattr;
|
||||||
|
}
|
||||||
|
|
||||||
/* set DELETE_ON_CLOSE */
|
/* try to set DELETE_ON_CLOSE */
|
||||||
rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid, current->tgid);
|
if (!cifsInode->delete_pending) {
|
||||||
|
rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
|
||||||
|
current->tgid);
|
||||||
/*
|
/*
|
||||||
* some samba versions return -ENOENT when we try to set the file
|
* some samba versions return -ENOENT when we try to set the
|
||||||
* disposition here. Likely a samba bug, but work around it for now
|
* file disposition here. Likely a samba bug, but work around
|
||||||
|
* it for now. This means that some cifsXXX files may hang
|
||||||
|
* around after they shouldn't.
|
||||||
|
*
|
||||||
|
* BB: remove this hack after more servers have the fix
|
||||||
*/
|
*/
|
||||||
if (rc == -ENOENT)
|
if (rc == -ENOENT)
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
else if (rc != 0) {
|
||||||
|
rc = -ETXTBSY;
|
||||||
|
goto undo_rename;
|
||||||
|
}
|
||||||
|
cifsInode->delete_pending = true;
|
||||||
|
}
|
||||||
|
|
||||||
out_close:
|
out_close:
|
||||||
CIFSSMBClose(xid, tcon, netfid);
|
CIFSSMBClose(xid, tcon, netfid);
|
||||||
out:
|
out:
|
||||||
|
kfree(info_buf);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reset everything back to the original state. Don't bother
|
||||||
|
* dealing with errors here since we can't do anything about
|
||||||
|
* them anyway.
|
||||||
|
*/
|
||||||
|
undo_rename:
|
||||||
|
CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name,
|
||||||
|
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||||
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
|
undo_setattr:
|
||||||
|
if (dosattr != origattr) {
|
||||||
|
info_buf->Attributes = cpu_to_le32(origattr);
|
||||||
|
if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
|
||||||
|
current->tgid))
|
||||||
|
cifsInode->cifsAttrs = origattr;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto out_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
|
@ -878,7 +922,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
} else if (rc == -ENOENT) {
|
} else if (rc == -ENOENT) {
|
||||||
d_drop(dentry);
|
d_drop(dentry);
|
||||||
} else if (rc == -ETXTBSY) {
|
} else if (rc == -ETXTBSY) {
|
||||||
rc = cifs_rename_pending_delete(full_path, inode, xid);
|
rc = cifs_rename_pending_delete(full_path, dentry, xid);
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
drop_nlink(inode);
|
drop_nlink(inode);
|
||||||
} else if (rc == -EACCES && dosattr == 0) {
|
} else if (rc == -EACCES && dosattr == 0) {
|
||||||
|
@ -1241,22 +1285,21 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
|
int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
|
||||||
struct inode *target_inode, struct dentry *target_direntry)
|
struct inode *target_dir, struct dentry *target_dentry)
|
||||||
{
|
{
|
||||||
char *fromName = NULL;
|
char *fromName = NULL;
|
||||||
char *toName = NULL;
|
char *toName = NULL;
|
||||||
struct cifs_sb_info *cifs_sb_source;
|
struct cifs_sb_info *cifs_sb_source;
|
||||||
struct cifs_sb_info *cifs_sb_target;
|
struct cifs_sb_info *cifs_sb_target;
|
||||||
struct cifsTconInfo *pTcon;
|
struct cifsTconInfo *tcon;
|
||||||
FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
|
FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
|
||||||
FILE_UNIX_BASIC_INFO *info_buf_target;
|
FILE_UNIX_BASIC_INFO *info_buf_target;
|
||||||
int xid;
|
int xid, rc, tmprc;
|
||||||
int rc;
|
|
||||||
|
|
||||||
cifs_sb_target = CIFS_SB(target_inode->i_sb);
|
cifs_sb_target = CIFS_SB(target_dir->i_sb);
|
||||||
cifs_sb_source = CIFS_SB(source_inode->i_sb);
|
cifs_sb_source = CIFS_SB(source_dir->i_sb);
|
||||||
pTcon = cifs_sb_source->tcon;
|
tcon = cifs_sb_source->tcon;
|
||||||
|
|
||||||
xid = GetXid();
|
xid = GetXid();
|
||||||
|
|
||||||
|
@ -1264,7 +1307,7 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
|
||||||
* BB: this might be allowed if same server, but different share.
|
* BB: this might be allowed if same server, but different share.
|
||||||
* Consider adding support for this
|
* Consider adding support for this
|
||||||
*/
|
*/
|
||||||
if (pTcon != cifs_sb_target->tcon) {
|
if (tcon != cifs_sb_target->tcon) {
|
||||||
rc = -EXDEV;
|
rc = -EXDEV;
|
||||||
goto cifs_rename_exit;
|
goto cifs_rename_exit;
|
||||||
}
|
}
|
||||||
|
@ -1273,23 +1316,22 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
|
||||||
* we already have the rename sem so we do not need to
|
* we already have the rename sem so we do not need to
|
||||||
* grab it again here to protect the path integrity
|
* grab it again here to protect the path integrity
|
||||||
*/
|
*/
|
||||||
fromName = build_path_from_dentry(source_direntry);
|
fromName = build_path_from_dentry(source_dentry);
|
||||||
if (fromName == NULL) {
|
if (fromName == NULL) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto cifs_rename_exit;
|
goto cifs_rename_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
toName = build_path_from_dentry(target_direntry);
|
toName = build_path_from_dentry(target_dentry);
|
||||||
if (toName == NULL) {
|
if (toName == NULL) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto cifs_rename_exit;
|
goto cifs_rename_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = cifs_do_rename(xid, source_direntry, fromName,
|
rc = cifs_do_rename(xid, source_dentry, fromName,
|
||||||
target_direntry, toName);
|
target_dentry, toName);
|
||||||
|
|
||||||
if (rc == -EEXIST) {
|
if (rc == -EEXIST && tcon->unix_ext) {
|
||||||
if (pTcon->unix_ext) {
|
|
||||||
/*
|
/*
|
||||||
* Are src and dst hardlinks of same inode? We can
|
* Are src and dst hardlinks of same inode? We can
|
||||||
* only tell with unix extensions enabled
|
* only tell with unix extensions enabled
|
||||||
|
@ -1297,41 +1339,42 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
|
||||||
info_buf_source =
|
info_buf_source =
|
||||||
kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
|
kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (info_buf_source == NULL)
|
if (info_buf_source == NULL) {
|
||||||
goto unlink_target;
|
rc = -ENOMEM;
|
||||||
|
goto cifs_rename_exit;
|
||||||
|
}
|
||||||
|
|
||||||
info_buf_target = info_buf_source + 1;
|
info_buf_target = info_buf_source + 1;
|
||||||
rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
|
tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
|
||||||
info_buf_source,
|
info_buf_source,
|
||||||
cifs_sb_source->local_nls,
|
cifs_sb_source->local_nls,
|
||||||
cifs_sb_source->mnt_cifs_flags &
|
cifs_sb_source->mnt_cifs_flags &
|
||||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
if (rc != 0)
|
if (tmprc != 0)
|
||||||
goto unlink_target;
|
goto unlink_target;
|
||||||
|
|
||||||
rc = CIFSSMBUnixQPathInfo(xid, pTcon,
|
tmprc = CIFSSMBUnixQPathInfo(xid, tcon,
|
||||||
toName, info_buf_target,
|
toName, info_buf_target,
|
||||||
cifs_sb_target->local_nls,
|
cifs_sb_target->local_nls,
|
||||||
/* remap based on source sb */
|
/* remap based on source sb */
|
||||||
cifs_sb_source->mnt_cifs_flags &
|
cifs_sb_source->mnt_cifs_flags &
|
||||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||||
|
|
||||||
if (rc == 0 && (info_buf_source->UniqueId ==
|
if (tmprc == 0 && (info_buf_source->UniqueId ==
|
||||||
info_buf_target->UniqueId))
|
info_buf_target->UniqueId))
|
||||||
/* same file, POSIX says that this is a noop */
|
/* same file, POSIX says that this is a noop */
|
||||||
goto cifs_rename_exit;
|
goto cifs_rename_exit;
|
||||||
} /* else ... BB we could add the same check for Windows by
|
} /* else ... BB we could add the same check for Windows by
|
||||||
checking the UniqueId via FILE_INTERNAL_INFO */
|
checking the UniqueId via FILE_INTERNAL_INFO */
|
||||||
|
|
||||||
unlink_target:
|
unlink_target:
|
||||||
/*
|
if ((rc == -EACCES) || (rc == -EEXIST)) {
|
||||||
* we either can not tell the files are hardlinked (as with
|
tmprc = cifs_unlink(target_dir, target_dentry);
|
||||||
* Windows servers) or files are not hardlinked. Delete the
|
if (tmprc)
|
||||||
* target manually before renaming to follow POSIX rather than
|
goto cifs_rename_exit;
|
||||||
* Windows semantics
|
|
||||||
*/
|
rc = cifs_do_rename(xid, source_dentry, fromName,
|
||||||
cifs_unlink(target_inode, target_direntry);
|
target_dentry, toName);
|
||||||
rc = cifs_do_rename(xid, source_direntry, fromName,
|
|
||||||
target_direntry, toName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cifs_rename_exit:
|
cifs_rename_exit:
|
||||||
|
|
|
@ -762,14 +762,15 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
|
||||||
rc));
|
rc));
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
|
while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
|
||||||
(rc == 0) && !cifsFile->srch_inf.endOfSearch) {
|
(rc == 0) && !cifsFile->srch_inf.endOfSearch) {
|
||||||
cFYI(1, ("calling findnext2"));
|
cFYI(1, ("calling findnext2"));
|
||||||
cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
|
|
||||||
rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
|
rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
|
||||||
&cifsFile->srch_inf);
|
&cifsFile->srch_inf);
|
||||||
|
cifs_save_resume_key(cifsFile->srch_inf.last_entry, cifsFile);
|
||||||
if (rc)
|
if (rc)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue