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:
commit
542dafadd8
@ -340,6 +340,7 @@
|
||||
#define OPEN_NO_RECALL 0x00400000
|
||||
#define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */
|
||||
#define CREATE_OPTIONS_MASK 0x007FFFFF
|
||||
#define CREATE_OPTION_READONLY 0x10000000
|
||||
#define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */
|
||||
|
||||
/* ImpersonationLevel flags */
|
||||
|
@ -1224,11 +1224,8 @@ SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
|
||||
else /* BB FIXME BB */
|
||||
pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
|
||||
|
||||
/* if ((omode & S_IWUGO) == 0)
|
||||
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 */
|
||||
if (create_options & CREATE_OPTION_READONLY)
|
||||
pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
|
||||
|
||||
/* BB FIXME BB */
|
||||
/* pSMB->CreateOptions = cpu_to_le32(create_options &
|
||||
@ -1331,17 +1328,16 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
|
||||
pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
|
||||
else
|
||||
pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
|
||||
|
||||
/* XP does not handle ATTR_POSIX_SEMANTICS */
|
||||
/* but it helps speed up case sensitive checks for other
|
||||
servers such as Samba */
|
||||
if (tcon->ses->capabilities & CAP_UNIX)
|
||||
pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
|
||||
|
||||
/* if ((omode & S_IWUGO) == 0)
|
||||
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 */
|
||||
if (create_options & CREATE_OPTION_READONLY)
|
||||
pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
|
||||
|
||||
pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
|
||||
pSMB->CreateDisposition = cpu_to_le32(openDisposition);
|
||||
pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
|
||||
|
@ -348,7 +348,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
||||
int reconnect;
|
||||
|
||||
current->flags |= PF_MEMALLOC;
|
||||
server->tsk = current; /* save process info to wake at shutdown */
|
||||
cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
atomic_inc(&tcpSesAllocCount);
|
||||
@ -651,10 +650,20 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
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 */
|
||||
/* Note that cifs_max_pending is normally 50, but
|
||||
can be set at module install time to as little as two */
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (atomic_read(&server->inFlight) >= cifs_max_pending)
|
||||
atomic_set(&server->inFlight, cifs_max_pending - 1);
|
||||
/* 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 *
|
||||
cifs_find_tcp_session(struct in_addr *target_ip_addr,
|
||||
struct in6_addr *target_ip6_addr,
|
||||
char *userName, struct TCP_Server_Info **psrvTcp)
|
||||
struct in6_addr *target_ip6_addr,
|
||||
char *userName, struct TCP_Server_Info **psrvTcp)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct cifsSesInfo *ses;
|
||||
*psrvTcp = NULL;
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
|
||||
*psrvTcp = NULL;
|
||||
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
list_for_each(tmp, &GlobalSMBSessionList) {
|
||||
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
|
||||
if (ses->server) {
|
||||
if ((target_ip_addr &&
|
||||
(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?? */
|
||||
if (!ses->server)
|
||||
continue;
|
||||
|
||||
/* found a match on the TCP session */
|
||||
*psrvTcp = ses->server;
|
||||
if (target_ip_addr &&
|
||||
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 */
|
||||
if (strncmp
|
||||
(ses->userName, userName,
|
||||
MAX_USERNAME_SIZE) == 0){
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
/* Found exact match on both TCP and
|
||||
SMB sessions */
|
||||
return ses;
|
||||
}
|
||||
}
|
||||
/* found a match on the TCP session */
|
||||
*psrvTcp = ses->server;
|
||||
|
||||
/* BB check if reconnection needed */
|
||||
if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) {
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
/* Found exact match on both TCP and
|
||||
SMB sessions */
|
||||
return ses;
|
||||
}
|
||||
/* else tcp and smb sessions need reconnection */
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -2186,15 +2196,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
srvTcp->tcpStatus = CifsExiting;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
if (srvTcp->tsk) {
|
||||
struct task_struct *tsk;
|
||||
/* 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);
|
||||
tsk = srvTcp->tsk;
|
||||
if (tsk)
|
||||
kthread_stop(tsk);
|
||||
kthread_stop(srvTcp->tsk);
|
||||
}
|
||||
}
|
||||
/* 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) &&
|
||||
(pSesInfo->server) &&
|
||||
(pSesInfo->server->tsk)) {
|
||||
struct task_struct *tsk;
|
||||
force_sig(SIGKILL,
|
||||
pSesInfo->server->tsk);
|
||||
tsk = pSesInfo->server->tsk;
|
||||
if (tsk)
|
||||
kthread_stop(tsk);
|
||||
kthread_stop(pSesInfo->server->tsk);
|
||||
}
|
||||
} else {
|
||||
cFYI(1, ("No session or bad tcon"));
|
||||
if ((pSesInfo->server) &&
|
||||
(pSesInfo->server->tsk)) {
|
||||
struct task_struct *tsk;
|
||||
force_sig(SIGKILL,
|
||||
pSesInfo->server->tsk);
|
||||
tsk = pSesInfo->server->tsk;
|
||||
if (tsk)
|
||||
kthread_stop(tsk);
|
||||
kthread_stop(pSesInfo->server->tsk);
|
||||
}
|
||||
}
|
||||
sesInfoFree(pSesInfo);
|
||||
|
@ -119,6 +119,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
||||
{
|
||||
int rc = -ENOENT;
|
||||
int xid;
|
||||
int create_options = CREATE_NOT_DIR;
|
||||
int oplock = 0;
|
||||
int desiredAccess = GENERIC_READ | GENERIC_WRITE;
|
||||
__u16 fileHandle;
|
||||
@ -176,9 +177,19 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
||||
FreeXid(xid);
|
||||
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)
|
||||
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
|
||||
desiredAccess, CREATE_NOT_DIR,
|
||||
desiredAccess, create_options,
|
||||
&fileHandle, &oplock, buf, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
else
|
||||
@ -187,7 +198,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
||||
if (rc == -EIO) {
|
||||
/* old server, retry the open legacy style */
|
||||
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
|
||||
desiredAccess, CREATE_NOT_DIR,
|
||||
desiredAccess, create_options,
|
||||
&fileHandle, &oplock, buf, cifs_sb->local_nls,
|
||||
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
|
||||
then we now have to set the mode if possible */
|
||||
if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
|
||||
mode &= ~current->fs->umask;
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
|
||||
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
|
||||
(__u64)current->fsuid,
|
||||
|
@ -974,8 +974,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
||||
* failed to get it from the server or was set bogus */
|
||||
if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
|
||||
direntry->d_inode->i_nlink = 2;
|
||||
mode &= ~current->fs->umask;
|
||||
if (pTcon->unix_ext) {
|
||||
mode &= ~current->fs->umask;
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
|
||||
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
|
||||
mode,
|
||||
@ -994,9 +994,16 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
}
|
||||
} else {
|
||||
/* BB to be implemented via Windows secrty descriptors
|
||||
eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
|
||||
-1, -1, local_nls); */
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
|
||||
(mode & S_IWUGO) == 0) {
|
||||
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) {
|
||||
direntry->d_inode->i_mode = mode;
|
||||
direntry->d_inode->i_mode |= S_IFDIR;
|
||||
@ -1408,18 +1415,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
__u64 uid = 0xFFFFFFFFFFFFFFFFULL;
|
||||
__u64 gid = 0xFFFFFFFFFFFFFFFFULL;
|
||||
struct cifsInodeInfo *cifsInode;
|
||||
struct inode *inode = direntry->d_inode;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
|
||||
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;
|
||||
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
|
||||
/* 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) {
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
@ -1432,7 +1440,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
FreeXid(xid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
cifsInode = CIFS_I(direntry->d_inode);
|
||||
cifsInode = CIFS_I(inode);
|
||||
|
||||
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
|
||||
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) {
|
||||
CIFS_I(direntry->d_inode)->write_behind_rc = rc;
|
||||
cifsInode->write_behind_rc = rc;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
@ -1521,9 +1529,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
*/
|
||||
|
||||
if (rc == 0) {
|
||||
rc = cifs_vmtruncate(direntry->d_inode, attrs->ia_size);
|
||||
cifs_truncate_page(direntry->d_inode->i_mapping,
|
||||
direntry->d_inode->i_size);
|
||||
rc = cifs_vmtruncate(inode, attrs->ia_size);
|
||||
cifs_truncate_page(inode->i_mapping, inode->i_size);
|
||||
} else
|
||||
goto cifs_setattr_exit;
|
||||
}
|
||||
@ -1557,7 +1564,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
rc = 0;
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
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) {
|
||||
@ -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
|
||||
that */
|
||||
if (!rc)
|
||||
rc = inode_setattr(direntry->d_inode, attrs);
|
||||
rc = inode_setattr(inode, attrs);
|
||||
cifs_setattr_exit:
|
||||
kfree(full_path);
|
||||
FreeXid(xid);
|
||||
|
Loading…
Reference in New Issue
Block a user