Commit e3fc0656 authored by Rohith Surabattula's avatar Rohith Surabattula Committed by Steve French
Browse files

cifs: Deferred close performance improvements



During unlink/rename instead of closing all the deferred handles
under tcon, close only handles under the requested dentry.

Signed-off-by: default avatarRohith Surabattula <rohiths@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 4c51de1e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -267,6 +267,9 @@ 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);

extern struct TCP_Server_Info *cifs_get_tcp_session(struct smb3_fs_context *ctx);
extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
				 int from_reconnect);
+3 −3
Original line number Diff line number Diff line
@@ -1624,7 +1624,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
		goto unlink_out;
	}

	cifs_close_deferred_file(CIFS_I(inode));
	cifs_close_deferred_file_under_dentry(tcon, full_path);
	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
		rc = CIFSPOSIXDelFile(xid, tcon, full_path,
@@ -2113,9 +2113,9 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir,
		goto cifs_rename_exit;
	}

	cifs_close_deferred_file(CIFS_I(d_inode(source_dentry)));
	cifs_close_deferred_file_under_dentry(tcon, from_name);
	if (d_inode(target_dentry) != NULL)
		cifs_close_deferred_file(CIFS_I(d_inode(target_dentry)));
		cifs_close_deferred_file_under_dentry(tcon, to_name);

	rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
			    to_name);
+37 −0
Original line number Diff line number Diff line
@@ -780,6 +780,43 @@ 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)
{
	struct cifsFileInfo *cfile;
	struct list_head *tmp;
	struct file_list *tmp_list, *tmp_next_list;
	struct list_head file_head;
	void *page;
	const char *full_path;

	INIT_LIST_HEAD(&file_head);
	page = alloc_dentry_path();
	spin_lock(&tcon->open_file_lock);
	list_for_each(tmp, &tcon->openFileList) {
		cfile = list_entry(tmp, struct cifsFileInfo, 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)) {
					tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
					if (tmp_list == NULL)
						break;
					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);
	}
	free_dentry_path(page);
}

/* parses DFS refferal V3 structure
 * caller is responsible for freeing target_nodes