Commit 93ed9a29 authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French
Browse files

smb: client: fix filename matching of deferred files



Fix the following case where the client would end up closing both
deferred files (foo.tmp & foo) after unlink(foo) due to strstr() call
in cifs_close_deferred_file_under_dentry():

  fd1 = openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666);
  fd2 = openat(AT_FDCWD, "foo.tmp", O_WRONLY|O_CREAT|O_TRUNC, 0666);
  close(fd1);
  close(fd2);
  unlink("foo");

Fixes: e3fc0656 ("cifs: Deferred close performance improvements")
Signed-off-by: default avatarPaulo Alcantara (Red Hat) <pc@manguebit.org>
Reviewed-by: default avatarEnzo Matsumiya <ematsumiya@suse.de>
Cc: Frank Sorenson <sorenson@redhat.com>
Cc: David Howells <dhowells@redhat.com>
Cc: linux-cifs@vger.kernel.org
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent f57e53ea
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -312,8 +312,8 @@ extern void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode);

extern void cifs_close_all_deferred_files(struct cifs_tcon *cifs_tcon);

extern void cifs_close_deferred_file_under_dentry(struct cifs_tcon *cifs_tcon,
				const char *path);
void cifs_close_deferred_file_under_dentry(struct cifs_tcon *cifs_tcon,
					   struct dentry *dentry);

extern void cifs_mark_open_handles_for_deleted_file(struct inode *inode,
				const char *path);
+3 −3
Original line number Diff line number Diff line
@@ -1984,7 +1984,7 @@ static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyren
	}

	netfs_wait_for_outstanding_io(inode);
	cifs_close_deferred_file_under_dentry(tcon, full_path);
	cifs_close_deferred_file_under_dentry(tcon, dentry);
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
@@ -2538,10 +2538,10 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
		goto cifs_rename_exit;
	}

	cifs_close_deferred_file_under_dentry(tcon, from_name);
	cifs_close_deferred_file_under_dentry(tcon, source_dentry);
	if (d_inode(target_dentry) != NULL) {
		netfs_wait_for_outstanding_io(d_inode(target_dentry));
		cifs_close_deferred_file_under_dentry(tcon, to_name);
		cifs_close_deferred_file_under_dentry(tcon, target_dentry);
	}

	rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
+16 −22
Original line number Diff line number Diff line
@@ -832,22 +832,19 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
		kfree(tmp_list);
	}
}
void
cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)

void cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon,
					   struct dentry *dentry)
{
	struct cifsFileInfo *cfile;
	struct file_list *tmp_list, *tmp_next_list;
	void *page;
	const char *full_path;
	struct cifsFileInfo *cfile;
	LIST_HEAD(file_head);

	page = alloc_dentry_path();
	spin_lock(&tcon->open_file_lock);
	list_for_each_entry(cfile, &tcon->openFileList, tlist) {
		full_path = build_path_from_dentry(cfile->dentry, page);
		if (strstr(full_path, path)) {
			if (delayed_work_pending(&cfile->deferred)) {
				if (cancel_delayed_work(&cfile->deferred)) {
		if ((cfile->dentry == dentry) &&
		    delayed_work_pending(&cfile->deferred) &&
		    cancel_delayed_work(&cfile->deferred)) {
			spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
			cifs_del_deferred_close(cfile);
			spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
@@ -859,8 +856,6 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)
			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) {
@@ -868,7 +863,6 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)
		list_del(&tmp_list->list);
		kfree(tmp_list);
	}
	free_dentry_path(page);
}

/*