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] don't allow demultiplex thread to exit until kthread_stop is called
  [CIFS] when not using unix extensions, check for and set ATTR_READONLY on create and mkdir
  [CIFS]  add local struct inode pointer to cifs_setattr
  [CIFS] cifs_find_tcp_session cleanup
This commit is contained in:
Linus Torvalds 2008-05-12 13:29:15 -07:00
commit 542dafadd8
5 changed files with 80 additions and 65 deletions

View File

@ -340,6 +340,7 @@
#define OPEN_NO_RECALL 0x00400000 #define OPEN_NO_RECALL 0x00400000
#define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */ #define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */
#define CREATE_OPTIONS_MASK 0x007FFFFF #define CREATE_OPTIONS_MASK 0x007FFFFF
#define CREATE_OPTION_READONLY 0x10000000
#define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */
/* ImpersonationLevel flags */ /* ImpersonationLevel flags */

View File

@ -1224,11 +1224,8 @@ OldOpenRetry:
else /* BB FIXME BB */ else /* BB FIXME BB */
pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
/* if ((omode & S_IWUGO) == 0) if (create_options & CREATE_OPTION_READONLY)
pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
/* Above line causes problems due to vfs splitting create into two
pieces - need to set mode after file created not while it is
being created */
/* BB FIXME BB */ /* BB FIXME BB */
/* pSMB->CreateOptions = cpu_to_le32(create_options & /* pSMB->CreateOptions = cpu_to_le32(create_options &
@ -1331,17 +1328,16 @@ openRetry:
pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
else else
pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
/* XP does not handle ATTR_POSIX_SEMANTICS */ /* XP does not handle ATTR_POSIX_SEMANTICS */
/* but it helps speed up case sensitive checks for other /* but it helps speed up case sensitive checks for other
servers such as Samba */ servers such as Samba */
if (tcon->ses->capabilities & CAP_UNIX) if (tcon->ses->capabilities & CAP_UNIX)
pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
/* if ((omode & S_IWUGO) == 0) if (create_options & CREATE_OPTION_READONLY)
pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
/* Above line causes problems due to vfs splitting create into two
pieces - need to set mode after file created not while it is
being created */
pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
pSMB->CreateDisposition = cpu_to_le32(openDisposition); pSMB->CreateDisposition = cpu_to_le32(openDisposition);
pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);

View File

@ -348,7 +348,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
int reconnect; int reconnect;
current->flags |= PF_MEMALLOC; current->flags |= PF_MEMALLOC;
server->tsk = current; /* save process info to wake at shutdown */
cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current))); cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
write_lock(&GlobalSMBSeslock); write_lock(&GlobalSMBSeslock);
atomic_inc(&tcpSesAllocCount); atomic_inc(&tcpSesAllocCount);
@ -651,10 +650,20 @@ multi_t2_fnd:
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
server->tcpStatus = CifsExiting; server->tcpStatus = CifsExiting;
server->tsk = NULL; spin_unlock(&GlobalMid_Lock);
/* 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 */
spin_lock(&GlobalMid_Lock);
if (atomic_read(&server->inFlight) >= cifs_max_pending) if (atomic_read(&server->inFlight) >= cifs_max_pending)
atomic_set(&server->inFlight, cifs_max_pending - 1); atomic_set(&server->inFlight, cifs_max_pending - 1);
/* We do not want to set the max_pending too low or we /* We do not want to set the max_pending too low or we
@ -1318,42 +1327,43 @@ cifs_parse_mount_options(char *options, const char *devname,
static struct cifsSesInfo * static struct cifsSesInfo *
cifs_find_tcp_session(struct in_addr *target_ip_addr, cifs_find_tcp_session(struct in_addr *target_ip_addr,
struct in6_addr *target_ip6_addr, struct in6_addr *target_ip6_addr,
char *userName, struct TCP_Server_Info **psrvTcp) char *userName, struct TCP_Server_Info **psrvTcp)
{ {
struct list_head *tmp; struct list_head *tmp;
struct cifsSesInfo *ses; struct cifsSesInfo *ses;
*psrvTcp = NULL;
read_lock(&GlobalSMBSeslock);
*psrvTcp = NULL;
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalSMBSessionList) { list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
if (ses->server) { if (!ses->server)
if ((target_ip_addr && continue;
(ses->server->addr.sockAddr.sin_addr.s_addr
== target_ip_addr->s_addr)) || (target_ip6_addr
&& memcmp(&ses->server->addr.sockAddr6.sin6_addr,
target_ip6_addr, sizeof(*target_ip6_addr)))) {
/* BB lock server and tcp session and increment
use count here?? */
/* found a match on the TCP session */ if (target_ip_addr &&
*psrvTcp = ses->server; ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr)
continue;
else if (target_ip6_addr &&
memcmp(&ses->server->addr.sockAddr6.sin6_addr,
target_ip6_addr, sizeof(*target_ip6_addr)))
continue;
/* BB lock server and tcp session; increment use count here?? */
/* BB check if reconnection needed */ /* found a match on the TCP session */
if (strncmp *psrvTcp = ses->server;
(ses->userName, userName,
MAX_USERNAME_SIZE) == 0){ /* BB check if reconnection needed */
read_unlock(&GlobalSMBSeslock); if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) {
/* Found exact match on both TCP and read_unlock(&GlobalSMBSeslock);
SMB sessions */ /* Found exact match on both TCP and
return ses; SMB sessions */
} return ses;
}
} }
/* else tcp and smb sessions need reconnection */ /* else tcp and smb sessions need reconnection */
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
return NULL; return NULL;
} }
@ -2186,15 +2196,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
srvTcp->tcpStatus = CifsExiting; srvTcp->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
if (srvTcp->tsk) { if (srvTcp->tsk) {
struct task_struct *tsk;
/* If we could verify that kthread_stop would /* If we could verify that kthread_stop would
always wake up processes blocked in always wake up processes blocked in
tcp in recv_mesg then we could remove the tcp in recv_mesg then we could remove the
send_sig call */ send_sig call */
force_sig(SIGKILL, srvTcp->tsk); force_sig(SIGKILL, srvTcp->tsk);
tsk = srvTcp->tsk; kthread_stop(srvTcp->tsk);
if (tsk)
kthread_stop(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 */
@ -2210,23 +2217,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if ((temp_rc == -ESHUTDOWN) && if ((temp_rc == -ESHUTDOWN) &&
(pSesInfo->server) && (pSesInfo->server) &&
(pSesInfo->server->tsk)) { (pSesInfo->server->tsk)) {
struct task_struct *tsk;
force_sig(SIGKILL, force_sig(SIGKILL,
pSesInfo->server->tsk); pSesInfo->server->tsk);
tsk = pSesInfo->server->tsk; kthread_stop(pSesInfo->server->tsk);
if (tsk)
kthread_stop(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)) { (pSesInfo->server->tsk)) {
struct task_struct *tsk;
force_sig(SIGKILL, force_sig(SIGKILL,
pSesInfo->server->tsk); pSesInfo->server->tsk);
tsk = pSesInfo->server->tsk; kthread_stop(pSesInfo->server->tsk);
if (tsk)
kthread_stop(tsk);
} }
} }
sesInfoFree(pSesInfo); sesInfoFree(pSesInfo);

View File

@ -119,6 +119,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
{ {
int rc = -ENOENT; int rc = -ENOENT;
int xid; int xid;
int create_options = CREATE_NOT_DIR;
int oplock = 0; int oplock = 0;
int desiredAccess = GENERIC_READ | GENERIC_WRITE; int desiredAccess = GENERIC_READ | GENERIC_WRITE;
__u16 fileHandle; __u16 fileHandle;
@ -176,9 +177,19 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
mode &= ~current->fs->umask;
/*
* if we're not using unix extensions, see if we need to set
* ATTR_READONLY on the create call
*/
if (!pTcon->unix_ext && (mode & S_IWUGO) == 0)
create_options |= CREATE_OPTION_READONLY;
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, desiredAccess, create_options,
&fileHandle, &oplock, buf, cifs_sb->local_nls, &fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
else else
@ -187,7 +198,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if (rc == -EIO) { if (rc == -EIO) {
/* old server, retry the open legacy style */ /* old server, retry the open legacy style */
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, desiredAccess, create_options,
&fileHandle, &oplock, buf, cifs_sb->local_nls, &fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
@ -197,7 +208,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
/* If Open reported that we actually created a file /* If Open reported that we actually created a file
then we now have to set the mode if possible */ then we now have to set the mode if possible */
if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
(__u64)current->fsuid, (__u64)current->fsuid,

View File

@ -974,8 +974,8 @@ mkdir_get_info:
* failed to get it from the server or was set bogus */ * failed to get it from the server or was set bogus */
if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
direntry->d_inode->i_nlink = 2; direntry->d_inode->i_nlink = 2;
mode &= ~current->fs->umask;
if (pTcon->unix_ext) { if (pTcon->unix_ext) {
mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, CIFSSMBUnixSetPerms(xid, pTcon, full_path,
mode, mode,
@ -994,9 +994,16 @@ mkdir_get_info:
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
} else { } else {
/* BB to be implemented via Windows secrty descriptors if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, (mode & S_IWUGO) == 0) {
-1, -1, local_nls); */ FILE_BASIC_INFO pInfo;
memset(&pInfo, 0, sizeof(pInfo));
pInfo.Attributes = cpu_to_le32(ATTR_READONLY);
CIFSSMBSetTimes(xid, pTcon, full_path,
&pInfo, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
}
if (direntry->d_inode) { if (direntry->d_inode) {
direntry->d_inode->i_mode = mode; direntry->d_inode->i_mode = mode;
direntry->d_inode->i_mode |= S_IFDIR; direntry->d_inode->i_mode |= S_IFDIR;
@ -1408,18 +1415,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
__u64 uid = 0xFFFFFFFFFFFFFFFFULL; __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
__u64 gid = 0xFFFFFFFFFFFFFFFFULL; __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
struct cifsInodeInfo *cifsInode; struct cifsInodeInfo *cifsInode;
struct inode *inode = direntry->d_inode;
xid = GetXid(); xid = GetXid();
cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
direntry->d_name.name, attrs->ia_valid)); direntry->d_name.name, attrs->ia_valid));
cifs_sb = CIFS_SB(direntry->d_inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
/* check if we have permission to change attrs */ /* check if we have permission to change attrs */
rc = inode_change_ok(direntry->d_inode, attrs); rc = inode_change_ok(inode, attrs);
if (rc < 0) { if (rc < 0) {
FreeXid(xid); FreeXid(xid);
return rc; return rc;
@ -1432,7 +1440,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
cifsInode = CIFS_I(direntry->d_inode); cifsInode = CIFS_I(inode);
if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
/* /*
@ -1443,9 +1451,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
will be truncated anyway? Also, should we error out here if will be truncated anyway? Also, should we error out here if
the flush returns error? the flush returns error?
*/ */
rc = filemap_write_and_wait(direntry->d_inode->i_mapping); rc = filemap_write_and_wait(inode->i_mapping);
if (rc != 0) { if (rc != 0) {
CIFS_I(direntry->d_inode)->write_behind_rc = rc; cifsInode->write_behind_rc = rc;
rc = 0; rc = 0;
} }
} }
@ -1521,9 +1529,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
*/ */
if (rc == 0) { if (rc == 0) {
rc = cifs_vmtruncate(direntry->d_inode, attrs->ia_size); rc = cifs_vmtruncate(inode, attrs->ia_size);
cifs_truncate_page(direntry->d_inode->i_mapping, cifs_truncate_page(inode->i_mapping, inode->i_size);
direntry->d_inode->i_size);
} else } else
goto cifs_setattr_exit; goto cifs_setattr_exit;
} }
@ -1557,7 +1564,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
rc = 0; rc = 0;
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
rc = mode_to_acl(direntry->d_inode, full_path, mode); rc = mode_to_acl(inode, full_path, mode);
else if ((mode & S_IWUGO) == 0) { else if ((mode & S_IWUGO) == 0) {
#else #else
if ((mode & S_IWUGO) == 0) { if ((mode & S_IWUGO) == 0) {
@ -1665,7 +1672,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
/* do not need local check to inode_check_ok since the server does /* do not need local check to inode_check_ok since the server does
that */ that */
if (!rc) if (!rc)
rc = inode_setattr(direntry->d_inode, attrs); rc = inode_setattr(inode, attrs);
cifs_setattr_exit: cifs_setattr_exit:
kfree(full_path); kfree(full_path);
FreeXid(xid); FreeXid(xid);