Commit eb3138e4 authored by Pavel Shilovsky's avatar Pavel Shilovsky

Update 3.16 sources from stable (v3.16.7)

parent 0ad3dea7
...@@ -70,11 +70,6 @@ ...@@ -70,11 +70,6 @@
#define SERVER_NAME_LENGTH 40 #define SERVER_NAME_LENGTH 40
#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) #define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
/* used to define string lengths for reversing unicode strings */
/* (256+1)*2 = 514 */
/* (max path length + 1 for null) * 2 for unicode */
#define MAX_NAME 514
/* SMB echo "timeout" -- FIXME: tunable? */ /* SMB echo "timeout" -- FIXME: tunable? */
#define SMB_ECHO_INTERVAL (60 * HZ) #define SMB_ECHO_INTERVAL (60 * HZ)
...@@ -404,6 +399,8 @@ struct smb_version_operations { ...@@ -404,6 +399,8 @@ struct smb_version_operations {
const struct cifs_fid *, u32 *); const struct cifs_fid *, u32 *);
int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *, int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
int); int);
/* check if we need to issue closedir */
bool (*dir_needs_close)(struct cifsFileInfo *);
}; };
struct smb_version_values { struct smb_version_values {
......
...@@ -770,7 +770,7 @@ int cifs_closedir(struct inode *inode, struct file *file) ...@@ -770,7 +770,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
cifs_dbg(FYI, "Freeing private data in close dir\n"); cifs_dbg(FYI, "Freeing private data in close dir\n");
spin_lock(&cifs_file_list_lock); spin_lock(&cifs_file_list_lock);
if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { if (server->ops->dir_needs_close(cfile)) {
cfile->invalidHandle = true; cfile->invalidHandle = true;
spin_unlock(&cifs_file_list_lock); spin_unlock(&cifs_file_list_lock);
if (server->ops->close_dir) if (server->ops->close_dir)
...@@ -2831,7 +2831,7 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server, ...@@ -2831,7 +2831,7 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
total_read += result; total_read += result;
} }
return total_read > 0 ? total_read : result; return total_read > 0 && result != -EAGAIN ? total_read : result;
} }
ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to) ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to)
...@@ -3239,7 +3239,7 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server, ...@@ -3239,7 +3239,7 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
total_read += result; total_read += result;
} }
return total_read > 0 ? total_read : result; return total_read > 0 && result != -EAGAIN ? total_read : result;
} }
static int cifs_readpages(struct file *file, struct address_space *mapping, static int cifs_readpages(struct file *file, struct address_space *mapping,
......
...@@ -1715,13 +1715,22 @@ cifs_rename(struct inode *source_dir, struct dentry *source_dentry, ...@@ -1715,13 +1715,22 @@ cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
unlink_target: unlink_target:
/* Try unlinking the target dentry if it's not negative */ /* Try unlinking the target dentry if it's not negative */
if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) { if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) {
tmprc = cifs_unlink(target_dir, target_dentry); if (d_is_dir(target_dentry))
tmprc = cifs_rmdir(target_dir, target_dentry);
else
tmprc = cifs_unlink(target_dir, target_dentry);
if (tmprc) if (tmprc)
goto cifs_rename_exit; goto cifs_rename_exit;
rc = cifs_do_rename(xid, source_dentry, from_name, rc = cifs_do_rename(xid, source_dentry, from_name,
target_dentry, to_name); target_dentry, to_name);
} }
/* force revalidate to go get info when needed */
CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
source_dir->i_ctime = source_dir->i_mtime = target_dir->i_ctime =
target_dir->i_mtime = current_fs_time(source_dir->i_sb);
cifs_rename_exit: cifs_rename_exit:
kfree(info_buf_source); kfree(info_buf_source);
kfree(from_name); kfree(from_name);
......
...@@ -213,8 +213,12 @@ create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -213,8 +213,12 @@ create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
if (rc) if (rc)
goto out; goto out;
rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon, cifs_sb, if (tcon->ses->server->ops->create_mf_symlink)
fromName, buf, &bytes_written); rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon,
cifs_sb, fromName, buf, &bytes_written);
else
rc = -EOPNOTSUPP;
if (rc) if (rc)
goto out; goto out;
......
...@@ -593,11 +593,11 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos, ...@@ -593,11 +593,11 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
/* close and restart search */ /* close and restart search */
cifs_dbg(FYI, "search backing up - close and restart search\n"); cifs_dbg(FYI, "search backing up - close and restart search\n");
spin_lock(&cifs_file_list_lock); spin_lock(&cifs_file_list_lock);
if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { if (server->ops->dir_needs_close(cfile)) {
cfile->invalidHandle = true; cfile->invalidHandle = true;
spin_unlock(&cifs_file_list_lock); spin_unlock(&cifs_file_list_lock);
if (server->ops->close) if (server->ops->close_dir)
server->ops->close(xid, tcon, &cfile->fid); server->ops->close_dir(xid, tcon, &cfile->fid);
} else } else
spin_unlock(&cifs_file_list_lock); spin_unlock(&cifs_file_list_lock);
if (cfile->srch_inf.ntwrk_buf_start) { if (cfile->srch_inf.ntwrk_buf_start) {
......
...@@ -587,7 +587,7 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -587,7 +587,7 @@ cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
tmprc = CIFS_open(xid, &oparms, &oplock, NULL); tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
if (tmprc == -EOPNOTSUPP) if (tmprc == -EOPNOTSUPP)
*symlink = true; *symlink = true;
else else if (tmprc == 0)
CIFSSMBClose(xid, tcon, fid.netfid); CIFSSMBClose(xid, tcon, fid.netfid);
} }
...@@ -1012,6 +1012,12 @@ cifs_is_read_op(__u32 oplock) ...@@ -1012,6 +1012,12 @@ cifs_is_read_op(__u32 oplock)
return oplock == OPLOCK_READ; return oplock == OPLOCK_READ;
} }
static bool
cifs_dir_needs_close(struct cifsFileInfo *cfile)
{
return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
}
struct smb_version_operations smb1_operations = { struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel, .send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids, .compare_fids = cifs_compare_fids,
...@@ -1081,6 +1087,7 @@ struct smb_version_operations smb1_operations = { ...@@ -1081,6 +1087,7 @@ struct smb_version_operations smb1_operations = {
.query_mf_symlink = cifs_query_mf_symlink, .query_mf_symlink = cifs_query_mf_symlink,
.create_mf_symlink = cifs_create_mf_symlink, .create_mf_symlink = cifs_create_mf_symlink,
.is_read_op = cifs_is_read_op, .is_read_op = cifs_is_read_op,
.dir_needs_close = cifs_dir_needs_close,
#ifdef CONFIG_CIFS_XATTR #ifdef CONFIG_CIFS_XATTR
.query_all_EAs = CIFSSMBQAllEAs, .query_all_EAs = CIFSSMBQAllEAs,
.set_EA = CIFSSMBSetEA, .set_EA = CIFSSMBSetEA,
......
...@@ -50,7 +50,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, ...@@ -50,7 +50,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
goto out; goto out;
} }
smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2, smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
GFP_KERNEL); GFP_KERNEL);
if (smb2_data == NULL) { if (smb2_data == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
......
...@@ -132,7 +132,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -132,7 +132,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
*adjust_tz = false; *adjust_tz = false;
*symlink = false; *symlink = false;
smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2, smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
GFP_KERNEL); GFP_KERNEL);
if (smb2_data == NULL) if (smb2_data == NULL)
return -ENOMEM; return -ENOMEM;
......
...@@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = { ...@@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
{STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"}, {STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
{STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"}, {STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"},
{STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"}, {STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"},
{STATUS_NO_MORE_FILES, -EIO, "STATUS_NO_MORE_FILES"}, {STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"},
{STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"}, {STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
{STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"}, {STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
{STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"}, {STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"},
...@@ -256,6 +256,8 @@ static const struct status_to_posix_error smb2_error_map_table[] = { ...@@ -256,6 +256,8 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
{STATUS_DLL_MIGHT_BE_INCOMPATIBLE, -EIO, {STATUS_DLL_MIGHT_BE_INCOMPATIBLE, -EIO,
"STATUS_DLL_MIGHT_BE_INCOMPATIBLE"}, "STATUS_DLL_MIGHT_BE_INCOMPATIBLE"},
{STATUS_STOPPED_ON_SYMLINK, -EOPNOTSUPP, "STATUS_STOPPED_ON_SYMLINK"}, {STATUS_STOPPED_ON_SYMLINK, -EOPNOTSUPP, "STATUS_STOPPED_ON_SYMLINK"},
{STATUS_IO_REPARSE_TAG_NOT_HANDLED, -EOPNOTSUPP,
"STATUS_REPARSE_NOT_HANDLED"},
{STATUS_DEVICE_REQUIRES_CLEANING, -EIO, {STATUS_DEVICE_REQUIRES_CLEANING, -EIO,
"STATUS_DEVICE_REQUIRES_CLEANING"}, "STATUS_DEVICE_REQUIRES_CLEANING"},
{STATUS_DEVICE_DOOR_OPEN, -EIO, "STATUS_DEVICE_DOOR_OPEN"}, {STATUS_DEVICE_DOOR_OPEN, -EIO, "STATUS_DEVICE_DOOR_OPEN"},
...@@ -605,7 +607,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = { ...@@ -605,7 +607,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
{STATUS_MAPPED_FILE_SIZE_ZERO, -EIO, "STATUS_MAPPED_FILE_SIZE_ZERO"}, {STATUS_MAPPED_FILE_SIZE_ZERO, -EIO, "STATUS_MAPPED_FILE_SIZE_ZERO"},
{STATUS_TOO_MANY_OPENED_FILES, -EMFILE, "STATUS_TOO_MANY_OPENED_FILES"}, {STATUS_TOO_MANY_OPENED_FILES, -EMFILE, "STATUS_TOO_MANY_OPENED_FILES"},
{STATUS_CANCELLED, -EIO, "STATUS_CANCELLED"}, {STATUS_CANCELLED, -EIO, "STATUS_CANCELLED"},
{STATUS_CANNOT_DELETE, -EIO, "STATUS_CANNOT_DELETE"}, {STATUS_CANNOT_DELETE, -EACCES, "STATUS_CANNOT_DELETE"},
{STATUS_INVALID_COMPUTER_NAME, -EIO, "STATUS_INVALID_COMPUTER_NAME"}, {STATUS_INVALID_COMPUTER_NAME, -EIO, "STATUS_INVALID_COMPUTER_NAME"},
{STATUS_FILE_DELETED, -EIO, "STATUS_FILE_DELETED"}, {STATUS_FILE_DELETED, -EIO, "STATUS_FILE_DELETED"},
{STATUS_SPECIAL_ACCOUNT, -EIO, "STATUS_SPECIAL_ACCOUNT"}, {STATUS_SPECIAL_ACCOUNT, -EIO, "STATUS_SPECIAL_ACCOUNT"},
......
...@@ -342,7 +342,7 @@ smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -342,7 +342,7 @@ smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
int rc; int rc;
struct smb2_file_all_info *smb2_data; struct smb2_file_all_info *smb2_data;
smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2, smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
GFP_KERNEL); GFP_KERNEL);
if (smb2_data == NULL) if (smb2_data == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -1110,6 +1110,12 @@ smb3_parse_lease_buf(void *buf, unsigned int *epoch) ...@@ -1110,6 +1110,12 @@ smb3_parse_lease_buf(void *buf, unsigned int *epoch)
return le32_to_cpu(lc->lcontext.LeaseState); return le32_to_cpu(lc->lcontext.LeaseState);
} }
static bool
smb2_dir_needs_close(struct cifsFileInfo *cfile)
{
return !cfile->invalidHandle;
}
struct smb_version_operations smb20_operations = { struct smb_version_operations smb20_operations = {
.compare_fids = smb2_compare_fids, .compare_fids = smb2_compare_fids,
.setup_request = smb2_setup_request, .setup_request = smb2_setup_request,
...@@ -1183,6 +1189,7 @@ struct smb_version_operations smb20_operations = { ...@@ -1183,6 +1189,7 @@ struct smb_version_operations smb20_operations = {
.create_lease_buf = smb2_create_lease_buf, .create_lease_buf = smb2_create_lease_buf,
.parse_lease_buf = smb2_parse_lease_buf, .parse_lease_buf = smb2_parse_lease_buf,
.clone_range = smb2_clone_range, .clone_range = smb2_clone_range,
.dir_needs_close = smb2_dir_needs_close,
}; };
struct smb_version_operations smb21_operations = { struct smb_version_operations smb21_operations = {
...@@ -1258,6 +1265,7 @@ struct smb_version_operations smb21_operations = { ...@@ -1258,6 +1265,7 @@ struct smb_version_operations smb21_operations = {
.create_lease_buf = smb2_create_lease_buf, .create_lease_buf = smb2_create_lease_buf,
.parse_lease_buf = smb2_parse_lease_buf, .parse_lease_buf = smb2_parse_lease_buf,
.clone_range = smb2_clone_range, .clone_range = smb2_clone_range,
.dir_needs_close = smb2_dir_needs_close,
}; };
struct smb_version_operations smb30_operations = { struct smb_version_operations smb30_operations = {
...@@ -1336,6 +1344,7 @@ struct smb_version_operations smb30_operations = { ...@@ -1336,6 +1344,7 @@ struct smb_version_operations smb30_operations = {
.parse_lease_buf = smb3_parse_lease_buf, .parse_lease_buf = smb3_parse_lease_buf,
.clone_range = smb2_clone_range, .clone_range = smb2_clone_range,
.validate_negotiate = smb3_validate_negotiate, .validate_negotiate = smb3_validate_negotiate,
.dir_needs_close = smb2_dir_needs_close,
}; };
struct smb_version_values smb20_values = { struct smb_version_values smb20_values = {
......
...@@ -922,7 +922,8 @@ tcon_exit: ...@@ -922,7 +922,8 @@ tcon_exit:
tcon_error_exit: tcon_error_exit:
if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree); cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
tcon->bad_network_name = true; if (tcon)
tcon->bad_network_name = true;
} }
goto tcon_exit; goto tcon_exit;
} }
...@@ -1545,7 +1546,7 @@ SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1545,7 +1546,7 @@ SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
{ {
return query_info(xid, tcon, persistent_fid, volatile_fid, return query_info(xid, tcon, persistent_fid, volatile_fid,
FILE_ALL_INFORMATION, FILE_ALL_INFORMATION,
sizeof(struct smb2_file_all_info) + MAX_NAME * 2, sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
sizeof(struct smb2_file_all_info), data); sizeof(struct smb2_file_all_info), data);
} }
...@@ -2141,6 +2142,10 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2141,6 +2142,10 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base; rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base;
if (rc) { if (rc) {
if (rc == -ENODATA && rsp->hdr.Status == STATUS_NO_MORE_FILES) {
srch_inf->endOfSearch = true;
rc = 0;
}
cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
goto qdir_exit; goto qdir_exit;
} }
...@@ -2178,11 +2183,6 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2178,11 +2183,6 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
else else
cifs_dbg(VFS, "illegal search buffer type\n"); cifs_dbg(VFS, "illegal search buffer type\n");
if (rsp->hdr.Status == STATUS_NO_MORE_FILES)
srch_inf->endOfSearch = 1;
else
srch_inf->endOfSearch = 0;
return rc; return rc;
qdir_exit: qdir_exit:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment