forked from Minki/linux
4 CIFS/SMB3 Fixes, all for stable, 2 relating to deferred close, 1 for modefromsid mount option
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmEW5MQACgkQiiy9cAdy T1H6zQwAwOyQrMGA3VtsatmhhQo89oHbkUB4q4+tY7xabPNgTRAPT9BpRSFsrW4y njeiaP1T7nmiU1yJsYQD/JwRv005pBO/xa7sMsLb0RSca//kzin4WTTzxom3RUBW hU29PvAxl+AjaRvbo6VpSn6xuHH1BDcZU+YfWtX3c6tE30sdzwjyMu7rEhivNGCf 0ukIZuIaEJrZmCwMZHT8+qE1dBOKEad8I39POG1v+mybQCWJvo4MAUDyYHZYKTJz 6e3JDARI19G8hfq1oVAM/g5gIBRBEISug3jenOMVG/QnBnRsBvyuTIunoq4ba+S6 qp3jv3p24DaUe9FPp5sYyAhuJHo0rzSwGBv/SdikJA+3xb8k2E3rECAUbf4j/NmV /sj0tN/6/Z05/6L4ZgqUjdS2KfLztDvgzTGnv/LsB097Nhb8hVIhsKoqzypmyAcH 5AsjXFETMCclWE7oE8DkzaAOJqKD7MGJ6KXCjbt8JcFb/b6L/QQbRyRB5ggupgVn Ic7gn/iM =RlpY -----END PGP SIGNATURE----- Merge tag '5.14-rc5-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull cifs fixes from Steve French: "Four CIFS/SMB3 Fixes, all for stable, two relating to deferred close, and one for the 'modefromsid' mount option (when 'idsfromsid' not specified)" * tag '5.14-rc5-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: Call close synchronously during unlink/rename/lease break. cifs: Handle race conditions during rename cifs: use the correct max-length for dentry_path_raw() cifs: create sd context must be a multiple of 8
This commit is contained in:
commit
27b2eaa118
@ -1611,6 +1611,11 @@ struct dfs_info3_param {
|
||||
int ttl;
|
||||
};
|
||||
|
||||
struct file_list {
|
||||
struct list_head list;
|
||||
struct cifsFileInfo *cfile;
|
||||
};
|
||||
|
||||
/*
|
||||
* common struct for holding inode info when searching for or updating an
|
||||
* inode with new info
|
||||
|
@ -100,7 +100,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page,
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
|
||||
pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0;
|
||||
|
||||
s = dentry_path_raw(direntry, page, PAGE_SIZE);
|
||||
s = dentry_path_raw(direntry, page, PATH_MAX);
|
||||
if (IS_ERR(s))
|
||||
return s;
|
||||
if (!s[1]) // for root we want "", not "/"
|
||||
|
@ -4847,6 +4847,22 @@ void cifs_oplock_break(struct work_struct *work)
|
||||
cifs_dbg(VFS, "Push locks rc = %d\n", rc);
|
||||
|
||||
oplock_break_ack:
|
||||
/*
|
||||
* When oplock break is received and there are no active
|
||||
* file handles but cached, then schedule deferred close immediately.
|
||||
* So, new open will not use cached handle.
|
||||
*/
|
||||
spin_lock(&CIFS_I(inode)->deferred_lock);
|
||||
is_deferred = cifs_is_deferred_close(cfile, &dclose);
|
||||
spin_unlock(&CIFS_I(inode)->deferred_lock);
|
||||
if (is_deferred &&
|
||||
cfile->deferred_close_scheduled &&
|
||||
delayed_work_pending(&cfile->deferred)) {
|
||||
if (cancel_delayed_work(&cfile->deferred)) {
|
||||
_cifsFileInfo_put(cfile, false, false);
|
||||
goto oplock_break_done;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* releasing stale oplock after recent reconnect of smb session using
|
||||
* a now incorrect file handle is not a data integrity issue but do
|
||||
@ -4858,24 +4874,7 @@ oplock_break_ack:
|
||||
cinode);
|
||||
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
|
||||
}
|
||||
/*
|
||||
* When oplock break is received and there are no active
|
||||
* file handles but cached, then schedule deferred close immediately.
|
||||
* So, new open will not use cached handle.
|
||||
*/
|
||||
spin_lock(&CIFS_I(inode)->deferred_lock);
|
||||
is_deferred = cifs_is_deferred_close(cfile, &dclose);
|
||||
if (is_deferred &&
|
||||
cfile->deferred_close_scheduled &&
|
||||
delayed_work_pending(&cfile->deferred)) {
|
||||
/*
|
||||
* If there is no pending work, mod_delayed_work queues new work.
|
||||
* So, Increase the ref count to avoid use-after-free.
|
||||
*/
|
||||
if (!mod_delayed_work(deferredclose_wq, &cfile->deferred, 0))
|
||||
cifsFileInfo_get(cfile);
|
||||
}
|
||||
spin_unlock(&CIFS_I(inode)->deferred_lock);
|
||||
oplock_break_done:
|
||||
_cifsFileInfo_put(cfile, false /* do not wait for ourself */, false);
|
||||
cifs_done_oplock_break(cinode);
|
||||
}
|
||||
|
@ -1625,7 +1625,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
goto unlink_out;
|
||||
}
|
||||
|
||||
cifs_close_all_deferred_files(tcon);
|
||||
cifs_close_deferred_file(CIFS_I(inode));
|
||||
if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
||||
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
||||
rc = CIFSPOSIXDelFile(xid, tcon, full_path,
|
||||
@ -2084,6 +2084,7 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir,
|
||||
FILE_UNIX_BASIC_INFO *info_buf_target;
|
||||
unsigned int xid;
|
||||
int rc, tmprc;
|
||||
int retry_count = 0;
|
||||
|
||||
if (flags & ~RENAME_NOREPLACE)
|
||||
return -EINVAL;
|
||||
@ -2113,10 +2114,24 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir,
|
||||
goto cifs_rename_exit;
|
||||
}
|
||||
|
||||
cifs_close_all_deferred_files(tcon);
|
||||
cifs_close_deferred_file(CIFS_I(d_inode(source_dentry)));
|
||||
if (d_inode(target_dentry) != NULL)
|
||||
cifs_close_deferred_file(CIFS_I(d_inode(target_dentry)));
|
||||
|
||||
rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
|
||||
to_name);
|
||||
|
||||
if (rc == -EACCES) {
|
||||
while (retry_count < 3) {
|
||||
cifs_close_all_deferred_files(tcon);
|
||||
rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
|
||||
to_name);
|
||||
if (rc != -EACCES)
|
||||
break;
|
||||
retry_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* No-replace is the natural behavior for CIFS, so skip unlink hacks.
|
||||
*/
|
||||
|
@ -723,13 +723,31 @@ void
|
||||
cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
|
||||
{
|
||||
struct cifsFileInfo *cfile = NULL;
|
||||
struct cifs_deferred_close *dclose;
|
||||
struct file_list *tmp_list, *tmp_next_list;
|
||||
struct list_head file_head;
|
||||
|
||||
if (cifs_inode == NULL)
|
||||
return;
|
||||
|
||||
INIT_LIST_HEAD(&file_head);
|
||||
spin_lock(&cifs_inode->open_file_lock);
|
||||
list_for_each_entry(cfile, &cifs_inode->openFileList, flist) {
|
||||
spin_lock(&cifs_inode->deferred_lock);
|
||||
if (cifs_is_deferred_close(cfile, &dclose))
|
||||
mod_delayed_work(deferredclose_wq, &cfile->deferred, 0);
|
||||
spin_unlock(&cifs_inode->deferred_lock);
|
||||
if (delayed_work_pending(&cfile->deferred)) {
|
||||
if (cancel_delayed_work(&cfile->deferred)) {
|
||||
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
|
||||
if (tmp_list == NULL)
|
||||
continue;
|
||||
tmp_list->cfile = cfile;
|
||||
list_add_tail(&tmp_list->list, &file_head);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock(&cifs_inode->open_file_lock);
|
||||
|
||||
list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
|
||||
_cifsFileInfo_put(tmp_list->cfile, true, false);
|
||||
list_del(&tmp_list->list);
|
||||
kfree(tmp_list);
|
||||
}
|
||||
}
|
||||
|
||||
@ -738,20 +756,30 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
|
||||
{
|
||||
struct cifsFileInfo *cfile;
|
||||
struct list_head *tmp;
|
||||
struct file_list *tmp_list, *tmp_next_list;
|
||||
struct list_head file_head;
|
||||
|
||||
INIT_LIST_HEAD(&file_head);
|
||||
spin_lock(&tcon->open_file_lock);
|
||||
list_for_each(tmp, &tcon->openFileList) {
|
||||
cfile = list_entry(tmp, struct cifsFileInfo, tlist);
|
||||
if (delayed_work_pending(&cfile->deferred)) {
|
||||
/*
|
||||
* If there is no pending work, mod_delayed_work queues new work.
|
||||
* So, Increase the ref count to avoid use-after-free.
|
||||
*/
|
||||
if (!mod_delayed_work(deferredclose_wq, &cfile->deferred, 0))
|
||||
cifsFileInfo_get(cfile);
|
||||
if (cancel_delayed_work(&cfile->deferred)) {
|
||||
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
|
||||
if (tmp_list == NULL)
|
||||
continue;
|
||||
tmp_list->cfile = cfile;
|
||||
list_add_tail(&tmp_list->list, &file_head);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock(&tcon->open_file_lock);
|
||||
|
||||
list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
|
||||
_cifsFileInfo_put(tmp_list->cfile, true, false);
|
||||
list_del(&tmp_list->list);
|
||||
kfree(tmp_list);
|
||||
}
|
||||
}
|
||||
|
||||
/* parses DFS refferal V3 structure
|
||||
|
@ -2426,7 +2426,7 @@ create_sd_buf(umode_t mode, bool set_owner, unsigned int *len)
|
||||
memcpy(aclptr, &acl, sizeof(struct cifs_acl));
|
||||
|
||||
buf->ccontext.DataLength = cpu_to_le32(ptr - (__u8 *)&buf->sd);
|
||||
*len = ptr - (__u8 *)buf;
|
||||
*len = roundup(ptr - (__u8 *)buf, 8);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user