Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: cifs: when renaming don't try to unlink negative dentry cifs: remove unneeded bcc_ptr update in CIFSTCon cifs: add cFYI messages with some of the saved strings from ssetup/tcon cifs: fix buffer size for tcon->nativeFileSystem field cifs: fix unicode string area word alignment in session setup [CIFS] Fix build break caused by change to new current_umask helper function [CIFS] Fix sparse warnings [CIFS] Add support for posix open during lookup cifs: no need to use rcu_assign_pointer on immutable keys cifs: remove dnotify thread code [CIFS] remove some build warnings cifs: vary timeout on writes past EOF based on offset (try #5) [CIFS] Fix build break from recent DFS patch when DFS support not enabled Remote DFS root support. [CIFS] Endian convert UniqueId when reporting inode numbers from server files cifs: remove some pointless conditionals before kfree() cifs: flush data on any setattr
This commit is contained in:
commit
8d4ab5daca
13 changed files with 405 additions and 270 deletions
|
@ -15,7 +15,8 @@ Posix file open support added (turned off after one attempt if server
|
|||
fails to support it properly, as with Samba server versions prior to 3.3.2)
|
||||
Fix "redzone overwritten" bug in cifs_put_tcon (CIFSTcon may allocate too
|
||||
little memory for the "nativeFileSystem" field returned by the server
|
||||
during mount).
|
||||
during mount). Endian convert inode numbers if necessary (makes it easier
|
||||
to compare inode numbers on network files from big endian systems).
|
||||
|
||||
Version 1.56
|
||||
------------
|
||||
|
|
|
@ -41,7 +41,7 @@ cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen)
|
|||
|
||||
/* attach the data */
|
||||
memcpy(payload, data, datalen);
|
||||
rcu_assign_pointer(key->payload.data, payload);
|
||||
key->payload.data = payload;
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
|
|
|
@ -66,9 +66,6 @@ unsigned int sign_CIFS_PDUs = 1;
|
|||
extern struct task_struct *oplockThread; /* remove sparse warning */
|
||||
struct task_struct *oplockThread = NULL;
|
||||
/* extern struct task_struct * dnotifyThread; remove sparse warning */
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
static struct task_struct *dnotifyThread = NULL;
|
||||
#endif
|
||||
static const struct super_operations cifs_super_ops;
|
||||
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
|
||||
module_param(CIFSMaxBufSize, int, 0);
|
||||
|
@ -316,6 +313,7 @@ cifs_alloc_inode(struct super_block *sb)
|
|||
cifs_inode->clientCanCacheAll = false;
|
||||
cifs_inode->delete_pending = false;
|
||||
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
|
||||
cifs_inode->server_eof = 0;
|
||||
|
||||
/* Can not set i_flags here - they get immediately overwritten
|
||||
to zero by the VFS */
|
||||
|
@ -1040,34 +1038,6 @@ static int cifs_oplock_thread(void *dummyarg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
static int cifs_dnotify_thread(void *dummyarg)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct TCP_Server_Info *server;
|
||||
|
||||
do {
|
||||
if (try_to_freeze())
|
||||
continue;
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(15*HZ);
|
||||
/* check if any stuck requests that need
|
||||
to be woken up and wakeq so the
|
||||
thread can wake up and error out */
|
||||
read_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each(tmp, &cifs_tcp_ses_list) {
|
||||
server = list_entry(tmp, struct TCP_Server_Info,
|
||||
tcp_ses_list);
|
||||
if (atomic_read(&server->inFlight))
|
||||
wake_up_all(&server->response_q);
|
||||
}
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
} while (!kthread_should_stop());
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init
|
||||
init_cifs(void)
|
||||
{
|
||||
|
@ -1144,21 +1114,8 @@ init_cifs(void)
|
|||
goto out_unregister_dfs_key_type;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
|
||||
if (IS_ERR(dnotifyThread)) {
|
||||
rc = PTR_ERR(dnotifyThread);
|
||||
cERROR(1, ("error %d create dnotify thread", rc));
|
||||
goto out_stop_oplock_thread;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
out_stop_oplock_thread:
|
||||
#endif
|
||||
kthread_stop(oplockThread);
|
||||
out_unregister_dfs_key_type:
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
unregister_key_type(&key_type_dns_resolver);
|
||||
|
@ -1196,9 +1153,6 @@ exit_cifs(void)
|
|||
cifs_destroy_inodecache();
|
||||
cifs_destroy_mids();
|
||||
cifs_destroy_request_bufs();
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
kthread_stop(dnotifyThread);
|
||||
#endif
|
||||
kthread_stop(oplockThread);
|
||||
}
|
||||
|
||||
|
|
|
@ -350,7 +350,7 @@ struct cifsFileInfo {
|
|||
bool invalidHandle:1; /* file closed via session abend */
|
||||
bool messageMode:1; /* for pipes: message vs byte mode */
|
||||
atomic_t wrtPending; /* handle in use - defer close */
|
||||
struct semaphore fh_sem; /* prevents reopen race after dead ses*/
|
||||
struct mutex fh_mutex; /* prevents reopen race after dead ses*/
|
||||
struct cifs_search_info srch_inf;
|
||||
};
|
||||
|
||||
|
@ -370,6 +370,7 @@ struct cifsInodeInfo {
|
|||
bool clientCanCacheAll:1; /* read and writebehind oplock */
|
||||
bool oplockPending:1;
|
||||
bool delete_pending:1; /* DELETE_ON_CLOSE is set */
|
||||
u64 server_eof; /* current file size on server */
|
||||
struct inode vfs_inode;
|
||||
};
|
||||
|
||||
|
|
|
@ -2163,7 +2163,7 @@ typedef struct {
|
|||
__le32 Type;
|
||||
__le64 DevMajor;
|
||||
__le64 DevMinor;
|
||||
__u64 UniqueId;
|
||||
__le64 UniqueId;
|
||||
__le64 Permissions;
|
||||
__le64 Nlinks;
|
||||
} __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */
|
||||
|
@ -2308,7 +2308,7 @@ struct unlink_psx_rq { /* level 0x20a SetPathInfo */
|
|||
} __attribute__((packed));
|
||||
|
||||
struct file_internal_info {
|
||||
__u64 UniqueId; /* inode number */
|
||||
__le64 UniqueId; /* inode number */
|
||||
} __attribute__((packed)); /* level 0x3ee */
|
||||
|
||||
struct file_mode_info {
|
||||
|
@ -2338,7 +2338,7 @@ typedef struct {
|
|||
__le32 Type;
|
||||
__le64 DevMajor;
|
||||
__le64 DevMinor;
|
||||
__u64 UniqueId;
|
||||
__le64 UniqueId;
|
||||
__le64 Permissions;
|
||||
__le64 Nlinks;
|
||||
char FileName[1];
|
||||
|
@ -2386,7 +2386,7 @@ typedef struct {
|
|||
__le32 FileNameLength;
|
||||
__le32 EaSize; /* EA size */
|
||||
__le32 Reserved;
|
||||
__u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/
|
||||
__le64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/
|
||||
char FileName[1];
|
||||
} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */
|
||||
|
||||
|
|
|
@ -1626,6 +1626,8 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
|
|||
int smb_hdr_len;
|
||||
int resp_buf_type = 0;
|
||||
|
||||
*nbytes = 0;
|
||||
|
||||
cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
|
||||
|
||||
if (tcon->ses->capabilities & CAP_LARGE_FILES) {
|
||||
|
@ -1682,11 +1684,9 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
|
|||
cifs_stats_inc(&tcon->num_writes);
|
||||
if (rc) {
|
||||
cFYI(1, ("Send error Write2 = %d", rc));
|
||||
*nbytes = 0;
|
||||
} else if (resp_buf_type == 0) {
|
||||
/* presumably this can not happen, but best to be safe */
|
||||
rc = -EIO;
|
||||
*nbytes = 0;
|
||||
} else {
|
||||
WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
|
||||
*nbytes = le16_to_cpu(pSMBr->CountHigh);
|
||||
|
@ -3918,7 +3918,7 @@ CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
|
|||
}
|
||||
pfinfo = (struct file_internal_info *)
|
||||
(data_offset + (char *) &pSMBr->hdr.Protocol);
|
||||
*inode_number = pfinfo->UniqueId;
|
||||
*inode_number = le64_to_cpu(pfinfo->UniqueId);
|
||||
}
|
||||
}
|
||||
GetInodeNumOut:
|
||||
|
|
|
@ -2214,9 +2214,58 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_volume_info(struct smb_vol **pvolume_info)
|
||||
{
|
||||
struct smb_vol *volume_info;
|
||||
|
||||
if (!pvolume_info && !*pvolume_info)
|
||||
return;
|
||||
|
||||
volume_info = *pvolume_info;
|
||||
kzfree(volume_info->password);
|
||||
kfree(volume_info->UNC);
|
||||
kfree(volume_info->prepath);
|
||||
kfree(volume_info);
|
||||
*pvolume_info = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
/* build_path_to_root returns full path to root when
|
||||
* we do not have an exiting connection (tcon) */
|
||||
static char *
|
||||
build_unc_path_to_root(const struct smb_vol *volume_info,
|
||||
const struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
char *full_path;
|
||||
|
||||
int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1);
|
||||
full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL);
|
||||
if (full_path == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
strncpy(full_path, volume_info->UNC, unc_len);
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
|
||||
int i;
|
||||
for (i = 0; i < unc_len; i++) {
|
||||
if (full_path[i] == '\\')
|
||||
full_path[i] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
if (cifs_sb->prepathlen)
|
||||
strncpy(full_path + unc_len, cifs_sb->prepath,
|
||||
cifs_sb->prepathlen);
|
||||
|
||||
full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */
|
||||
return full_path;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
char *mount_data, const char *devname)
|
||||
char *mount_data_global, const char *devname)
|
||||
{
|
||||
int rc = 0;
|
||||
int xid;
|
||||
|
@ -2225,6 +2274,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
struct cifsTconInfo *tcon = NULL;
|
||||
struct TCP_Server_Info *srvTcp = NULL;
|
||||
char *full_path;
|
||||
char *mount_data = mount_data_global;
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
struct dfs_info3_param *referrals = NULL;
|
||||
unsigned int num_referrals = 0;
|
||||
try_mount_again:
|
||||
#endif
|
||||
full_path = NULL;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
|
@ -2371,11 +2427,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
}
|
||||
}
|
||||
|
||||
/* check for null share name ie connect to dfs root */
|
||||
if ((strchr(volume_info->UNC + 3, '\\') == NULL)
|
||||
&& (strchr(volume_info->UNC + 3, '/') == NULL)) {
|
||||
/* rc = connect_to_dfs_path(...) */
|
||||
cFYI(1, ("DFS root not supported"));
|
||||
cERROR(1, ("Missing share name"));
|
||||
rc = -ENODEV;
|
||||
goto mount_fail_check;
|
||||
} else {
|
||||
|
@ -2392,7 +2446,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
}
|
||||
}
|
||||
if (rc)
|
||||
goto mount_fail_check;
|
||||
goto remote_path_check;
|
||||
tcon->seal = volume_info->seal;
|
||||
write_lock(&cifs_tcp_ses_lock);
|
||||
list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
|
||||
|
@ -2417,19 +2471,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
/* BB FIXME fix time_gran to be larger for LANMAN sessions */
|
||||
sb->s_time_gran = 100;
|
||||
|
||||
mount_fail_check:
|
||||
/* on error free sesinfo and tcon struct if needed */
|
||||
if (rc) {
|
||||
/* If find_unc succeeded then rc == 0 so we can not end */
|
||||
/* up accidently freeing someone elses tcon struct */
|
||||
if (tcon)
|
||||
cifs_put_tcon(tcon);
|
||||
else if (pSesInfo)
|
||||
cifs_put_smb_ses(pSesInfo);
|
||||
else
|
||||
cifs_put_tcp_session(srvTcp);
|
||||
goto out;
|
||||
}
|
||||
if (rc)
|
||||
goto remote_path_check;
|
||||
|
||||
cifs_sb->tcon = tcon;
|
||||
|
||||
/* do not care if following two calls succeed - informational */
|
||||
|
@ -2461,7 +2505,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
cifs_sb->rsize = min(cifs_sb->rsize,
|
||||
(tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
|
||||
|
||||
if (!rc && cifs_sb->prepathlen) {
|
||||
remote_path_check:
|
||||
/* check if a whole path (including prepath) is not remote */
|
||||
if (!rc && cifs_sb->prepathlen && tcon) {
|
||||
/* build_path_to_root works only when we have a valid tcon */
|
||||
full_path = cifs_build_path_to_root(cifs_sb);
|
||||
if (full_path == NULL) {
|
||||
|
@ -2469,31 +2515,79 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
goto mount_fail_check;
|
||||
}
|
||||
rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
|
||||
if (rc) {
|
||||
cERROR(1, ("Path %s in not accessible: %d",
|
||||
full_path, rc));
|
||||
if (rc != -EREMOTE) {
|
||||
kfree(full_path);
|
||||
goto mount_fail_check;
|
||||
}
|
||||
kfree(full_path);
|
||||
}
|
||||
|
||||
/* get referral if needed */
|
||||
if (rc == -EREMOTE) {
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
/* convert forward to back slashes in prepath here if needed */
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
|
||||
convert_delimiter(cifs_sb->prepath,
|
||||
CIFS_DIR_SEP(cifs_sb));
|
||||
full_path = build_unc_path_to_root(volume_info, cifs_sb);
|
||||
if (IS_ERR(full_path)) {
|
||||
rc = PTR_ERR(full_path);
|
||||
goto mount_fail_check;
|
||||
}
|
||||
|
||||
cFYI(1, ("Getting referral for: %s", full_path));
|
||||
rc = get_dfs_path(xid, pSesInfo , full_path + 1,
|
||||
cifs_sb->local_nls, &num_referrals, &referrals,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (!rc && num_referrals > 0) {
|
||||
char *fake_devname = NULL;
|
||||
|
||||
if (mount_data != mount_data_global)
|
||||
kfree(mount_data);
|
||||
mount_data = cifs_compose_mount_options(
|
||||
cifs_sb->mountdata, full_path + 1,
|
||||
referrals, &fake_devname);
|
||||
kfree(fake_devname);
|
||||
free_dfs_info_array(referrals, num_referrals);
|
||||
|
||||
if (tcon)
|
||||
cifs_put_tcon(tcon);
|
||||
else if (pSesInfo)
|
||||
cifs_put_smb_ses(pSesInfo);
|
||||
|
||||
cleanup_volume_info(&volume_info);
|
||||
FreeXid(xid);
|
||||
kfree(full_path);
|
||||
goto try_mount_again;
|
||||
}
|
||||
#else /* No DFS support, return error on mount */
|
||||
rc = -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
|
||||
mount_fail_check:
|
||||
/* on error free sesinfo and tcon struct if needed */
|
||||
if (rc) {
|
||||
if (mount_data != mount_data_global)
|
||||
kfree(mount_data);
|
||||
/* If find_unc succeeded then rc == 0 so we can not end */
|
||||
/* up accidently freeing someone elses tcon struct */
|
||||
if (tcon)
|
||||
cifs_put_tcon(tcon);
|
||||
else if (pSesInfo)
|
||||
cifs_put_smb_ses(pSesInfo);
|
||||
else
|
||||
cifs_put_tcp_session(srvTcp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* volume_info->password is freed above when existing session found
|
||||
(in which case it is not needed anymore) but when new sesion is created
|
||||
the password ptr is put in the new session structure (in which case the
|
||||
password will be freed at unmount time) */
|
||||
out:
|
||||
/* zero out password before freeing */
|
||||
if (volume_info) {
|
||||
if (volume_info->password != NULL) {
|
||||
memset(volume_info->password, 0,
|
||||
strlen(volume_info->password));
|
||||
kfree(volume_info->password);
|
||||
}
|
||||
kfree(volume_info->UNC);
|
||||
kfree(volume_info->prepath);
|
||||
kfree(volume_info);
|
||||
}
|
||||
cleanup_volume_info(&volume_info);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
@ -2673,8 +2767,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
/* We look for obvious messed up bcc or strings in response so we do not go off
|
||||
the end since (at least) WIN2K and Windows XP have a major bug in not null
|
||||
terminating last Unicode string in response */
|
||||
if (ses->serverOS)
|
||||
kfree(ses->serverOS);
|
||||
kfree(ses->serverOS);
|
||||
ses->serverOS = kzalloc(2 * (len + 1),
|
||||
GFP_KERNEL);
|
||||
if (ses->serverOS == NULL)
|
||||
|
@ -2710,8 +2803,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
|
||||
/* last string is not always null terminated
|
||||
(for e.g. for Windows XP & 2000) */
|
||||
if (ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain =
|
||||
kzalloc(2*(len+1),
|
||||
GFP_KERNEL);
|
||||
|
@ -2725,8 +2817,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
ses->serverDomain[1+(2*len)] = 0;
|
||||
} else { /* else no more room so create
|
||||
dummy domain string */
|
||||
if (ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain =
|
||||
kzalloc(2, GFP_KERNEL);
|
||||
}
|
||||
|
@ -2772,8 +2863,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
bcc_ptr++;
|
||||
|
||||
len = strnlen(bcc_ptr, 1024);
|
||||
if (ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain = kzalloc(len + 1,
|
||||
GFP_KERNEL);
|
||||
if (ses->serverDomain == NULL)
|
||||
|
@ -3013,8 +3103,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
|||
/* We look for obvious messed up bcc or strings in response so we do not go off
|
||||
the end since (at least) WIN2K and Windows XP have a major bug in not null
|
||||
terminating last Unicode string in response */
|
||||
if (ses->serverOS)
|
||||
kfree(ses->serverOS);
|
||||
kfree(ses->serverOS);
|
||||
ses->serverOS =
|
||||
kzalloc(2 * (len + 1), GFP_KERNEL);
|
||||
cifs_strfromUCS_le(ses->serverOS,
|
||||
|
@ -3086,8 +3175,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
|||
if (((long) bcc_ptr + len) - (long)
|
||||
pByteArea(smb_buffer_response)
|
||||
<= BCC(smb_buffer_response)) {
|
||||
if (ses->serverOS)
|
||||
kfree(ses->serverOS);
|
||||
kfree(ses->serverOS);
|
||||
ses->serverOS =
|
||||
kzalloc(len + 1,
|
||||
GFP_KERNEL);
|
||||
|
@ -3414,8 +3502,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
/* We look for obvious messed up bcc or strings in response so we do not go off
|
||||
the end since (at least) WIN2K and Windows XP have a major bug in not null
|
||||
terminating last Unicode string in response */
|
||||
if (ses->serverOS)
|
||||
kfree(ses->serverOS);
|
||||
kfree(ses->serverOS);
|
||||
ses->serverOS =
|
||||
kzalloc(2 * (len + 1), GFP_KERNEL);
|
||||
cifs_strfromUCS_le(ses->serverOS,
|
||||
|
@ -3448,8 +3535,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
if (remaining_words > 0) {
|
||||
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
|
||||
/* last string not always null terminated (e.g. for Windows XP & 2000) */
|
||||
if (ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain =
|
||||
kzalloc(2 *
|
||||
(len +
|
||||
|
@ -3476,13 +3562,11 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
= 0;
|
||||
} /* else no more room so create dummy domain string */
|
||||
else {
|
||||
if (ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain = kzalloc(2,GFP_KERNEL);
|
||||
}
|
||||
} else { /* no room so create dummy domain and NOS string */
|
||||
if (ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain = kzalloc(2, GFP_KERNEL);
|
||||
kfree(ses->serverNOS);
|
||||
ses->serverNOS = kzalloc(2, GFP_KERNEL);
|
||||
|
@ -3492,8 +3576,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
if (((long) bcc_ptr + len) -
|
||||
(long) pByteArea(smb_buffer_response)
|
||||
<= BCC(smb_buffer_response)) {
|
||||
if (ses->serverOS)
|
||||
kfree(ses->serverOS);
|
||||
kfree(ses->serverOS);
|
||||
ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
|
||||
strncpy(ses->serverOS,bcc_ptr, len);
|
||||
|
||||
|
@ -3512,8 +3595,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
bcc_ptr++;
|
||||
|
||||
len = strnlen(bcc_ptr, 1024);
|
||||
if (ses->serverDomain)
|
||||
kfree(ses->serverDomain);
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain =
|
||||
kzalloc(len+1,
|
||||
GFP_KERNEL);
|
||||
|
@ -3674,16 +3756,15 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
|
|||
BCC(smb_buffer_response)) {
|
||||
kfree(tcon->nativeFileSystem);
|
||||
tcon->nativeFileSystem =
|
||||
kzalloc(2*(length + 1), GFP_KERNEL);
|
||||
if (tcon->nativeFileSystem)
|
||||
kzalloc((4 * length) + 2, GFP_KERNEL);
|
||||
if (tcon->nativeFileSystem) {
|
||||
cifs_strfromUCS_le(
|
||||
tcon->nativeFileSystem,
|
||||
(__le16 *) bcc_ptr,
|
||||
length, nls_codepage);
|
||||
bcc_ptr += 2 * length;
|
||||
bcc_ptr[0] = 0; /* null terminate the string */
|
||||
bcc_ptr[1] = 0;
|
||||
bcc_ptr += 2;
|
||||
cFYI(1, ("nativeFileSystem=%s",
|
||||
tcon->nativeFileSystem));
|
||||
}
|
||||
}
|
||||
/* else do not bother copying these information fields*/
|
||||
} else {
|
||||
|
|
145
fs/cifs/dir.c
145
fs/cifs/dir.c
|
@ -129,12 +129,62 @@ build_path_from_dentry(struct dentry *direntry)
|
|||
return full_path;
|
||||
}
|
||||
|
||||
static void
|
||||
cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle,
|
||||
struct cifsTconInfo *tcon, bool write_only)
|
||||
{
|
||||
int oplock = 0;
|
||||
struct cifsFileInfo *pCifsFile;
|
||||
struct cifsInodeInfo *pCifsInode;
|
||||
|
||||
pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
||||
|
||||
if (pCifsFile == NULL)
|
||||
return;
|
||||
|
||||
if (oplockEnabled)
|
||||
oplock = REQ_OPLOCK;
|
||||
|
||||
pCifsFile->netfid = fileHandle;
|
||||
pCifsFile->pid = current->tgid;
|
||||
pCifsFile->pInode = newinode;
|
||||
pCifsFile->invalidHandle = false;
|
||||
pCifsFile->closePend = false;
|
||||
mutex_init(&pCifsFile->fh_mutex);
|
||||
mutex_init(&pCifsFile->lock_mutex);
|
||||
INIT_LIST_HEAD(&pCifsFile->llist);
|
||||
atomic_set(&pCifsFile->wrtPending, 0);
|
||||
|
||||
/* set the following in open now
|
||||
pCifsFile->pfile = file; */
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_add(&pCifsFile->tlist, &tcon->openFileList);
|
||||
pCifsInode = CIFS_I(newinode);
|
||||
if (pCifsInode) {
|
||||
/* if readable file instance put first in list*/
|
||||
if (write_only)
|
||||
list_add_tail(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
else
|
||||
list_add(&pCifsFile->flist, &pCifsInode->openFileList);
|
||||
|
||||
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
|
||||
pCifsInode->clientCanCacheAll = true;
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
cFYI(1, ("Exclusive Oplock inode %p", newinode));
|
||||
} else if ((oplock & 0xF) == OPLOCK_READ)
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
}
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
}
|
||||
|
||||
int cifs_posix_open(char *full_path, struct inode **pinode,
|
||||
struct super_block *sb, int mode, int oflags,
|
||||
int *poplock, __u16 *pnetfid, int xid)
|
||||
{
|
||||
int rc;
|
||||
__u32 oplock;
|
||||
bool write_only = false;
|
||||
FILE_UNIX_BASIC_INFO *presp_data;
|
||||
__u32 posix_flags = 0;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
|
@ -172,6 +222,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
|
|||
if (oflags & O_DIRECT)
|
||||
posix_flags |= SMB_O_DIRECT;
|
||||
|
||||
if (!(oflags & FMODE_READ))
|
||||
write_only = true;
|
||||
|
||||
rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
|
||||
pnetfid, presp_data, &oplock, full_path,
|
||||
|
@ -187,8 +239,10 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
|
|||
if (!pinode)
|
||||
goto posix_open_ret; /* caller does not need info */
|
||||
|
||||
if (*pinode == NULL)
|
||||
*pinode = cifs_new_inode(sb, &presp_data->UniqueId);
|
||||
if (*pinode == NULL) {
|
||||
__u64 unique_id = le64_to_cpu(presp_data->UniqueId);
|
||||
*pinode = cifs_new_inode(sb, &unique_id);
|
||||
}
|
||||
/* else an inode was passed in. Update its info, don't create one */
|
||||
|
||||
/* We do not need to close the file if new_inode fails since
|
||||
|
@ -198,6 +252,8 @@ int cifs_posix_open(char *full_path, struct inode **pinode,
|
|||
|
||||
posix_fill_in_inode(*pinode, presp_data, 1);
|
||||
|
||||
cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only);
|
||||
|
||||
posix_open_ret:
|
||||
kfree(presp_data);
|
||||
return rc;
|
||||
|
@ -239,7 +295,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
char *full_path = NULL;
|
||||
FILE_ALL_INFO *buf = NULL;
|
||||
struct inode *newinode = NULL;
|
||||
struct cifsInodeInfo *pCifsInode;
|
||||
int disposition = FILE_OVERWRITE_IF;
|
||||
bool write_only = false;
|
||||
|
||||
|
@ -410,44 +465,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
/* mknod case - do not leave file open */
|
||||
CIFSSMBClose(xid, tcon, fileHandle);
|
||||
} else if (newinode) {
|
||||
struct cifsFileInfo *pCifsFile =
|
||||
kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
||||
|
||||
if (pCifsFile == NULL)
|
||||
goto cifs_create_out;
|
||||
pCifsFile->netfid = fileHandle;
|
||||
pCifsFile->pid = current->tgid;
|
||||
pCifsFile->pInode = newinode;
|
||||
pCifsFile->invalidHandle = false;
|
||||
pCifsFile->closePend = false;
|
||||
init_MUTEX(&pCifsFile->fh_sem);
|
||||
mutex_init(&pCifsFile->lock_mutex);
|
||||
INIT_LIST_HEAD(&pCifsFile->llist);
|
||||
atomic_set(&pCifsFile->wrtPending, 0);
|
||||
|
||||
/* set the following in open now
|
||||
pCifsFile->pfile = file; */
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_add(&pCifsFile->tlist, &tcon->openFileList);
|
||||
pCifsInode = CIFS_I(newinode);
|
||||
if (pCifsInode) {
|
||||
/* if readable file instance put first in list*/
|
||||
if (write_only) {
|
||||
list_add_tail(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
} else {
|
||||
list_add(&pCifsFile->flist,
|
||||
&pCifsInode->openFileList);
|
||||
}
|
||||
if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
|
||||
pCifsInode->clientCanCacheAll = true;
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
cFYI(1, ("Exclusive Oplock inode %p",
|
||||
newinode));
|
||||
} else if ((oplock & 0xF) == OPLOCK_READ)
|
||||
pCifsInode->clientCanCacheRead = true;
|
||||
}
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
cifs_fill_fileinfo(newinode, fileHandle,
|
||||
cifs_sb->tcon, write_only);
|
||||
}
|
||||
cifs_create_out:
|
||||
kfree(buf);
|
||||
|
@ -580,17 +599,21 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
|
|||
return rc;
|
||||
}
|
||||
|
||||
|
||||
struct dentry *
|
||||
cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||
struct nameidata *nd)
|
||||
{
|
||||
int xid;
|
||||
int rc = 0; /* to get around spurious gcc warning, set to zero here */
|
||||
int oplock = 0;
|
||||
int mode;
|
||||
__u16 fileHandle = 0;
|
||||
bool posix_open = false;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
struct inode *newInode = NULL;
|
||||
char *full_path = NULL;
|
||||
struct file *filp;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
|
@ -632,12 +655,37 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
|||
}
|
||||
cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
|
||||
|
||||
if (pTcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&newInode, full_path,
|
||||
parent_dir_inode->i_sb, xid);
|
||||
else
|
||||
if (pTcon->unix_ext) {
|
||||
if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) &&
|
||||
(nd->flags & LOOKUP_OPEN)) {
|
||||
if (!((nd->intent.open.flags & O_CREAT) &&
|
||||
(nd->intent.open.flags & O_EXCL))) {
|
||||
mode = nd->intent.open.create_mode &
|
||||
~current_umask();
|
||||
rc = cifs_posix_open(full_path, &newInode,
|
||||
parent_dir_inode->i_sb, mode,
|
||||
nd->intent.open.flags, &oplock,
|
||||
&fileHandle, xid);
|
||||
/*
|
||||
* This code works around a bug in
|
||||
* samba posix open in samba versions 3.3.1
|
||||
* and earlier where create works
|
||||
* but open fails with invalid parameter.
|
||||
* If either of these error codes are
|
||||
* returned, follow the normal lookup.
|
||||
* Otherwise, the error during posix open
|
||||
* is handled.
|
||||
*/
|
||||
if ((rc != -EINVAL) && (rc != -EOPNOTSUPP))
|
||||
posix_open = true;
|
||||
}
|
||||
}
|
||||
if (!posix_open)
|
||||
rc = cifs_get_inode_info_unix(&newInode, full_path,
|
||||
parent_dir_inode->i_sb, xid);
|
||||
} else
|
||||
rc = cifs_get_inode_info(&newInode, full_path, NULL,
|
||||
parent_dir_inode->i_sb, xid, NULL);
|
||||
parent_dir_inode->i_sb, xid, NULL);
|
||||
|
||||
if ((rc == 0) && (newInode != NULL)) {
|
||||
if (pTcon->nocase)
|
||||
|
@ -645,7 +693,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
|||
else
|
||||
direntry->d_op = &cifs_dentry_ops;
|
||||
d_add(direntry, newInode);
|
||||
|
||||
if (posix_open)
|
||||
filp = lookup_instantiate_filp(nd, direntry, NULL);
|
||||
/* since paths are not looked up by component - the parent
|
||||
directories are presumed to be good here */
|
||||
renew_parental_timestamps(direntry);
|
||||
|
|
|
@ -78,7 +78,7 @@ dns_resolver_instantiate(struct key *key, const void *data,
|
|||
}
|
||||
|
||||
key->type_data.x[0] = datalen;
|
||||
rcu_assign_pointer(key->payload.data, ip);
|
||||
key->payload.data = ip;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
123
fs/cifs/file.c
123
fs/cifs/file.c
|
@ -46,7 +46,7 @@ static inline struct cifsFileInfo *cifs_init_private(
|
|||
memset(private_data, 0, sizeof(struct cifsFileInfo));
|
||||
private_data->netfid = netfid;
|
||||
private_data->pid = current->tgid;
|
||||
init_MUTEX(&private_data->fh_sem);
|
||||
mutex_init(&private_data->fh_mutex);
|
||||
mutex_init(&private_data->lock_mutex);
|
||||
INIT_LIST_HEAD(&private_data->llist);
|
||||
private_data->pfile = file; /* needed for writepage */
|
||||
|
@ -284,35 +284,32 @@ int cifs_open(struct inode *inode, struct file *file)
|
|||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
tcon = cifs_sb->tcon;
|
||||
|
||||
if (file->f_flags & O_CREAT) {
|
||||
/* search inode for this file and fill in file->private_data */
|
||||
pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
list_for_each(tmp, &pCifsInode->openFileList) {
|
||||
pCifsFile = list_entry(tmp, struct cifsFileInfo,
|
||||
flist);
|
||||
if ((pCifsFile->pfile == NULL) &&
|
||||
(pCifsFile->pid == current->tgid)) {
|
||||
/* mode set in cifs_create */
|
||||
/* search inode for this file and fill in file->private_data */
|
||||
pCifsInode = CIFS_I(file->f_path.dentry->d_inode);
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
list_for_each(tmp, &pCifsInode->openFileList) {
|
||||
pCifsFile = list_entry(tmp, struct cifsFileInfo,
|
||||
flist);
|
||||
if ((pCifsFile->pfile == NULL) &&
|
||||
(pCifsFile->pid == current->tgid)) {
|
||||
/* mode set in cifs_create */
|
||||
|
||||
/* needed for writepage */
|
||||
pCifsFile->pfile = file;
|
||||
/* needed for writepage */
|
||||
pCifsFile->pfile = file;
|
||||
|
||||
file->private_data = pCifsFile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
if (file->private_data != NULL) {
|
||||
rc = 0;
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
} else {
|
||||
if (file->f_flags & O_EXCL)
|
||||
cERROR(1, ("could not find file instance for "
|
||||
"new file %p", file));
|
||||
file->private_data = pCifsFile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
|
||||
if (file->private_data != NULL) {
|
||||
rc = 0;
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
} else if ((file->f_flags & O_CREAT) && (file->f_flags & O_EXCL))
|
||||
cERROR(1, ("could not find file instance for "
|
||||
"new file %p", file));
|
||||
|
||||
full_path = build_path_from_dentry(file->f_path.dentry);
|
||||
if (full_path == NULL) {
|
||||
|
@ -500,9 +497,9 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
|
|||
return -EBADF;
|
||||
|
||||
xid = GetXid();
|
||||
down(&pCifsFile->fh_sem);
|
||||
mutex_unlock(&pCifsFile->fh_mutex);
|
||||
if (!pCifsFile->invalidHandle) {
|
||||
up(&pCifsFile->fh_sem);
|
||||
mutex_lock(&pCifsFile->fh_mutex);
|
||||
FreeXid(xid);
|
||||
return 0;
|
||||
}
|
||||
|
@ -533,7 +530,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
|
|||
if (full_path == NULL) {
|
||||
rc = -ENOMEM;
|
||||
reopen_error_exit:
|
||||
up(&pCifsFile->fh_sem);
|
||||
mutex_lock(&pCifsFile->fh_mutex);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
@ -575,14 +572,14 @@ static int cifs_reopen_file(struct file *file, bool can_flush)
|
|||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc) {
|
||||
up(&pCifsFile->fh_sem);
|
||||
mutex_lock(&pCifsFile->fh_mutex);
|
||||
cFYI(1, ("cifs_open returned 0x%x", rc));
|
||||
cFYI(1, ("oplock: %d", oplock));
|
||||
} else {
|
||||
reopen_success:
|
||||
pCifsFile->netfid = netfid;
|
||||
pCifsFile->invalidHandle = false;
|
||||
up(&pCifsFile->fh_sem);
|
||||
mutex_lock(&pCifsFile->fh_mutex);
|
||||
pCifsInode = CIFS_I(inode);
|
||||
if (pCifsInode) {
|
||||
if (can_flush) {
|
||||
|
@ -971,6 +968,40 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the timeout on write requests past EOF. For some servers (Windows)
|
||||
* these calls can be very long.
|
||||
*
|
||||
* If we're writing >10M past the EOF we give a 180s timeout. Anything less
|
||||
* than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
|
||||
* The 10M cutoff is totally arbitrary. A better scheme for this would be
|
||||
* welcome if someone wants to suggest one.
|
||||
*
|
||||
* We may be able to do a better job with this if there were some way to
|
||||
* declare that a file should be sparse.
|
||||
*/
|
||||
static int
|
||||
cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
|
||||
{
|
||||
if (offset <= cifsi->server_eof)
|
||||
return CIFS_STD_OP;
|
||||
else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
|
||||
return CIFS_VLONG_OP;
|
||||
else
|
||||
return CIFS_LONG_OP;
|
||||
}
|
||||
|
||||
/* update the file size (if needed) after a write */
|
||||
static void
|
||||
cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
|
||||
unsigned int bytes_written)
|
||||
{
|
||||
loff_t end_of_write = offset + bytes_written;
|
||||
|
||||
if (end_of_write > cifsi->server_eof)
|
||||
cifsi->server_eof = end_of_write;
|
||||
}
|
||||
|
||||
ssize_t cifs_user_write(struct file *file, const char __user *write_data,
|
||||
size_t write_size, loff_t *poffset)
|
||||
{
|
||||
|
@ -981,6 +1012,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
|
|||
struct cifsTconInfo *pTcon;
|
||||
int xid, long_op;
|
||||
struct cifsFileInfo *open_file;
|
||||
struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
|
||||
|
||||
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
||||
|
||||
|
@ -1000,11 +1032,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
|
|||
|
||||
xid = GetXid();
|
||||
|
||||
if (*poffset > file->f_path.dentry->d_inode->i_size)
|
||||
long_op = CIFS_VLONG_OP; /* writes past EOF take long time */
|
||||
else
|
||||
long_op = CIFS_LONG_OP;
|
||||
|
||||
long_op = cifs_write_timeout(cifsi, *poffset);
|
||||
for (total_written = 0; write_size > total_written;
|
||||
total_written += bytes_written) {
|
||||
rc = -EAGAIN;
|
||||
|
@ -1048,8 +1076,10 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
|
|||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
cifs_update_eof(cifsi, *poffset, bytes_written);
|
||||
*poffset += bytes_written;
|
||||
}
|
||||
long_op = CIFS_STD_OP; /* subsequent writes fast -
|
||||
15 seconds is plenty */
|
||||
}
|
||||
|
@ -1085,6 +1115,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
|
|||
struct cifsTconInfo *pTcon;
|
||||
int xid, long_op;
|
||||
struct cifsFileInfo *open_file;
|
||||
struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
|
||||
|
||||
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
||||
|
||||
|
@ -1099,11 +1130,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
|
|||
|
||||
xid = GetXid();
|
||||
|
||||
if (*poffset > file->f_path.dentry->d_inode->i_size)
|
||||
long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */
|
||||
else
|
||||
long_op = CIFS_LONG_OP;
|
||||
|
||||
long_op = cifs_write_timeout(cifsi, *poffset);
|
||||
for (total_written = 0; write_size > total_written;
|
||||
total_written += bytes_written) {
|
||||
rc = -EAGAIN;
|
||||
|
@ -1166,8 +1193,10 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
|
|||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
cifs_update_eof(cifsi, *poffset, bytes_written);
|
||||
*poffset += bytes_written;
|
||||
}
|
||||
long_op = CIFS_STD_OP; /* subsequent writes fast -
|
||||
15 seconds is plenty */
|
||||
}
|
||||
|
@ -1380,11 +1409,12 @@ static int cifs_writepages(struct address_space *mapping,
|
|||
int nr_pages;
|
||||
__u64 offset = 0;
|
||||
struct cifsFileInfo *open_file;
|
||||
struct cifsInodeInfo *cifsi = CIFS_I(mapping->host);
|
||||
struct page *page;
|
||||
struct pagevec pvec;
|
||||
int rc = 0;
|
||||
int scanned = 0;
|
||||
int xid;
|
||||
int xid, long_op;
|
||||
|
||||
cifs_sb = CIFS_SB(mapping->host->i_sb);
|
||||
|
||||
|
@ -1528,12 +1558,15 @@ static int cifs_writepages(struct address_space *mapping,
|
|||
cERROR(1, ("No writable handles for inode"));
|
||||
rc = -EBADF;
|
||||
} else {
|
||||
long_op = cifs_write_timeout(cifsi, offset);
|
||||
rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
|
||||
open_file->netfid,
|
||||
bytes_to_write, offset,
|
||||
&bytes_written, iov, n_iov,
|
||||
CIFS_LONG_OP);
|
||||
long_op);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
cifs_update_eof(cifsi, offset, bytes_written);
|
||||
|
||||
if (rc || bytes_written < bytes_to_write) {
|
||||
cERROR(1, ("Write2 ret %d, wrote %d",
|
||||
rc, bytes_written));
|
||||
|
|
|
@ -143,6 +143,7 @@ static void cifs_unix_info_to_inode(struct inode *inode,
|
|||
|
||||
inode->i_nlink = le64_to_cpu(info->Nlinks);
|
||||
|
||||
cifsInfo->server_eof = end_of_file;
|
||||
spin_lock(&inode->i_lock);
|
||||
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
|
||||
/*
|
||||
|
@ -276,7 +277,8 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|||
|
||||
/* get new inode */
|
||||
if (*pinode == NULL) {
|
||||
*pinode = cifs_new_inode(sb, &find_data.UniqueId);
|
||||
__u64 unique_id = le64_to_cpu(find_data.UniqueId);
|
||||
*pinode = cifs_new_inode(sb, &unique_id);
|
||||
if (*pinode == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cgiiu_exit;
|
||||
|
@ -605,12 +607,12 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
inode->i_mode |= S_IFREG;
|
||||
}
|
||||
|
||||
cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile);
|
||||
spin_lock(&inode->i_lock);
|
||||
if (is_size_safe_to_change(cifsInfo,
|
||||
le64_to_cpu(pfindData->EndOfFile))) {
|
||||
if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) {
|
||||
/* can not safely shrink the file size here if the
|
||||
client is writing to it due to potential races */
|
||||
i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
|
||||
i_size_write(inode, cifsInfo->server_eof);
|
||||
|
||||
/* 512 bytes (2**9) is the fake blocksize that must be
|
||||
used for this calculation */
|
||||
|
@ -1138,6 +1140,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|||
cFYI(1, ("posix mkdir returned 0x%x", rc));
|
||||
d_drop(direntry);
|
||||
} else {
|
||||
__u64 unique_id;
|
||||
if (pInfo->Type == cpu_to_le32(-1)) {
|
||||
/* no return info, go query for it */
|
||||
kfree(pInfo);
|
||||
|
@ -1151,8 +1154,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|||
else
|
||||
direntry->d_op = &cifs_dentry_ops;
|
||||
|
||||
newinode = cifs_new_inode(inode->i_sb,
|
||||
&pInfo->UniqueId);
|
||||
unique_id = le64_to_cpu(pInfo->UniqueId);
|
||||
newinode = cifs_new_inode(inode->i_sb, &unique_id);
|
||||
if (newinode == NULL) {
|
||||
kfree(pInfo);
|
||||
goto mkdir_get_info;
|
||||
|
@ -1450,7 +1453,8 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
|
|||
checking the UniqueId via FILE_INTERNAL_INFO */
|
||||
|
||||
unlink_target:
|
||||
if ((rc == -EACCES) || (rc == -EEXIST)) {
|
||||
/* Try unlinking the target dentry if it's not negative */
|
||||
if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) {
|
||||
tmprc = cifs_unlink(target_dir, target_dentry);
|
||||
if (tmprc)
|
||||
goto cifs_rename_exit;
|
||||
|
@ -1753,6 +1757,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
|
|||
}
|
||||
|
||||
if (rc == 0) {
|
||||
cifsInode->server_eof = attrs->ia_size;
|
||||
rc = cifs_vmtruncate(inode, attrs->ia_size);
|
||||
cifs_truncate_page(inode->i_mapping, inode->i_size);
|
||||
}
|
||||
|
@ -1792,20 +1797,21 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
|
||||
/*
|
||||
Flush data before changing file size or changing the last
|
||||
write time of the file on the server. If the
|
||||
flush returns error, store it to report later and continue.
|
||||
BB: This should be smarter. Why bother flushing pages that
|
||||
will be truncated anyway? Also, should we error out here if
|
||||
the flush returns error?
|
||||
*/
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
if (rc != 0) {
|
||||
cifsInode->write_behind_rc = rc;
|
||||
rc = 0;
|
||||
}
|
||||
/*
|
||||
* Attempt to flush data before changing attributes. We need to do
|
||||
* this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
|
||||
* ownership or mode then we may also need to do this. Here, we take
|
||||
* the safe way out and just do the flush on all setattr requests. If
|
||||
* the flush returns error, store it to report later and continue.
|
||||
*
|
||||
* BB: This should be smarter. Why bother flushing pages that
|
||||
* will be truncated anyway? Also, should we error out here if
|
||||
* the flush returns error?
|
||||
*/
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
if (rc != 0) {
|
||||
cifsInode->write_behind_rc = rc;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
if (attrs->ia_valid & ATTR_SIZE) {
|
||||
|
@ -1903,20 +1909,21 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) {
|
||||
/*
|
||||
Flush data before changing file size or changing the last
|
||||
write time of the file on the server. If the
|
||||
flush returns error, store it to report later and continue.
|
||||
BB: This should be smarter. Why bother flushing pages that
|
||||
will be truncated anyway? Also, should we error out here if
|
||||
the flush returns error?
|
||||
*/
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
if (rc != 0) {
|
||||
cifsInode->write_behind_rc = rc;
|
||||
rc = 0;
|
||||
}
|
||||
/*
|
||||
* Attempt to flush data before changing attributes. We need to do
|
||||
* this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
|
||||
* ownership or mode then we may also need to do this. Here, we take
|
||||
* the safe way out and just do the flush on all setattr requests. If
|
||||
* the flush returns error, store it to report later and continue.
|
||||
*
|
||||
* BB: This should be smarter. Why bother flushing pages that
|
||||
* will be truncated anyway? Also, should we error out here if
|
||||
* the flush returns error?
|
||||
*/
|
||||
rc = filemap_write_and_wait(inode->i_mapping);
|
||||
if (rc != 0) {
|
||||
cifsInode->write_behind_rc = rc;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
if (attrs->ia_valid & ATTR_SIZE) {
|
||||
|
|
|
@ -239,6 +239,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
|
|||
if (atomic_read(&cifsInfo->inUse) == 0)
|
||||
atomic_set(&cifsInfo->inUse, 1);
|
||||
|
||||
cifsInfo->server_eof = end_of_file;
|
||||
spin_lock(&tmp_inode->i_lock);
|
||||
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
|
||||
/* can not safely change the file size here if the
|
||||
|
@ -375,6 +376,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
|
|||
tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
|
||||
tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
|
||||
|
||||
cifsInfo->server_eof = end_of_file;
|
||||
spin_lock(&tmp_inode->i_lock);
|
||||
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
|
||||
/* can not safely change the file size here if the
|
||||
|
@ -840,7 +842,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
|||
len = strnlen(filename, PATH_MAX);
|
||||
}
|
||||
|
||||
*pinum = pFindData->UniqueId;
|
||||
*pinum = le64_to_cpu(pFindData->UniqueId);
|
||||
} else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
|
||||
FILE_DIRECTORY_INFO *pFindData =
|
||||
(FILE_DIRECTORY_INFO *)current_entry;
|
||||
|
@ -856,7 +858,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
|
|||
(SEARCH_ID_FULL_DIR_INFO *)current_entry;
|
||||
filename = &pFindData->FileName[0];
|
||||
len = le32_to_cpu(pFindData->FileNameLength);
|
||||
*pinum = pFindData->UniqueId;
|
||||
*pinum = le64_to_cpu(pFindData->UniqueId);
|
||||
} else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
|
||||
FILE_BOTH_DIRECTORY_INFO *pFindData =
|
||||
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
|
||||
|
|
|
@ -285,35 +285,36 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
|
|||
int words_left, len;
|
||||
char *data = *pbcc_area;
|
||||
|
||||
|
||||
|
||||
cFYI(1, ("bleft %d", bleft));
|
||||
|
||||
|
||||
/* SMB header is unaligned, so cifs servers word align start of
|
||||
Unicode strings */
|
||||
data++;
|
||||
bleft--; /* Windows servers do not always double null terminate
|
||||
their final Unicode string - in which case we
|
||||
now will not attempt to decode the byte of junk
|
||||
which follows it */
|
||||
/*
|
||||
* Windows servers do not always double null terminate their final
|
||||
* Unicode string. Check to see if there are an uneven number of bytes
|
||||
* left. If so, then add an extra NULL pad byte to the end of the
|
||||
* response.
|
||||
*
|
||||
* See section 2.7.2 in "Implementing CIFS" for details
|
||||
*/
|
||||
if (bleft % 2) {
|
||||
data[bleft] = 0;
|
||||
++bleft;
|
||||
}
|
||||
|
||||
words_left = bleft / 2;
|
||||
|
||||
/* save off server operating system */
|
||||
len = UniStrnlen((wchar_t *) data, words_left);
|
||||
|
||||
/* We look for obvious messed up bcc or strings in response so we do not go off
|
||||
the end since (at least) WIN2K and Windows XP have a major bug in not null
|
||||
terminating last Unicode string in response */
|
||||
if (len >= words_left)
|
||||
return rc;
|
||||
|
||||
kfree(ses->serverOS);
|
||||
/* UTF-8 string will not grow more than four times as big as UCS-16 */
|
||||
ses->serverOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL);
|
||||
if (ses->serverOS != NULL)
|
||||
if (ses->serverOS != NULL) {
|
||||
cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp);
|
||||
cFYI(1, ("serverOS=%s", ses->serverOS));
|
||||
}
|
||||
data += 2 * (len + 1);
|
||||
words_left -= len + 1;
|
||||
|
||||
|
@ -328,6 +329,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
|
|||
if (ses->serverNOS != NULL) {
|
||||
cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
|
||||
nls_cp);
|
||||
cFYI(1, ("serverNOS=%s", ses->serverNOS));
|
||||
if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) {
|
||||
cFYI(1, ("NT4 server"));
|
||||
ses->flags |= CIFS_SES_NT4;
|
||||
|
@ -343,12 +345,11 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
|
|||
return rc;
|
||||
|
||||
kfree(ses->serverDomain);
|
||||
ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
|
||||
ses->serverDomain = kzalloc((4 * len) + 2, GFP_KERNEL);
|
||||
if (ses->serverDomain != NULL) {
|
||||
cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
|
||||
nls_cp);
|
||||
ses->serverDomain[2*len] = 0;
|
||||
ses->serverDomain[(2*len) + 1] = 0;
|
||||
cFYI(1, ("serverDomain=%s", ses->serverDomain));
|
||||
}
|
||||
data += 2 * (len + 1);
|
||||
words_left -= len + 1;
|
||||
|
@ -702,12 +703,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
|||
}
|
||||
|
||||
/* BB check if Unicode and decode strings */
|
||||
if (smb_buf->Flags2 & SMBFLG2_UNICODE)
|
||||
if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
|
||||
/* unicode string area must be word-aligned */
|
||||
if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) {
|
||||
++bcc_ptr;
|
||||
--bytes_remaining;
|
||||
}
|
||||
rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
|
||||
ses, nls_cp);
|
||||
else
|
||||
ses, nls_cp);
|
||||
} else {
|
||||
rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining,
|
||||
ses, nls_cp);
|
||||
}
|
||||
|
||||
ssetup_exit:
|
||||
if (spnego_key) {
|
||||
|
|
Loading…
Reference in a new issue