diff options
Diffstat (limited to 'fs/smb/client/misc.c')
-rw-r--r-- | fs/smb/client/misc.c | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c index d56959d02e..07c468ddb8 100644 --- a/fs/smb/client/misc.c +++ b/fs/smb/client/misc.c @@ -27,9 +27,6 @@ #include "fs_context.h" #include "cached_dir.h" -extern mempool_t *cifs_sm_req_poolp; -extern mempool_t *cifs_req_poolp; - /* The xid serves as a useful identifier for each incoming vfs request, in a similar way to the mid which is useful to track each sent smb, and CurrentXid can also provide a running counter (although it @@ -114,9 +111,10 @@ sesInfoFree(struct cifs_ses *buf_to_free) } struct cifs_tcon * -tcon_info_alloc(bool dir_leases_enabled) +tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace) { struct cifs_tcon *ret_buf; + static atomic_t tcon_debug_id; ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL); if (!ret_buf) @@ -133,7 +131,8 @@ tcon_info_alloc(bool dir_leases_enabled) atomic_inc(&tconInfoAllocCount); ret_buf->status = TID_NEW; - ++ret_buf->tc_count; + ret_buf->debug_id = atomic_inc_return(&tcon_debug_id); + ret_buf->tc_count = 1; spin_lock_init(&ret_buf->tc_lock); INIT_LIST_HEAD(&ret_buf->openFileList); INIT_LIST_HEAD(&ret_buf->tcon_list); @@ -145,17 +144,19 @@ tcon_info_alloc(bool dir_leases_enabled) #ifdef CONFIG_CIFS_FSCACHE mutex_init(&ret_buf->fscache_lock); #endif + trace_smb3_tcon_ref(ret_buf->debug_id, ret_buf->tc_count, trace); return ret_buf; } void -tconInfoFree(struct cifs_tcon *tcon) +tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace) { if (tcon == NULL) { cifs_dbg(FYI, "Null buffer passed to tconInfoFree\n"); return; } + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, trace); free_cached_dirs(tcon->cfids); atomic_dec(&tconInfoAllocCount); kfree(tcon->nativeFileSystem); @@ -853,6 +854,40 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path) free_dentry_path(page); } +/* + * If a dentry has been deleted, all corresponding open handles should know that + * so that we do not defer close them. + */ +void cifs_mark_open_handles_for_deleted_file(struct inode *inode, + const char *path) +{ + struct cifsFileInfo *cfile; + void *page; + const char *full_path; + struct cifsInodeInfo *cinode = CIFS_I(inode); + + page = alloc_dentry_path(); + spin_lock(&cinode->open_file_lock); + + /* + * note: we need to construct path from dentry and compare only if the + * inode has any hardlinks. When number of hardlinks is 1, we can just + * mark all open handles since they are going to be from the same file. + */ + if (inode->i_nlink > 1) { + list_for_each_entry(cfile, &cinode->openFileList, flist) { + full_path = build_path_from_dentry(cfile->dentry, page); + if (!IS_ERR(full_path) && strcmp(full_path, path) == 0) + cfile->status_file_deleted = true; + } + } else { + list_for_each_entry(cfile, &cinode->openFileList, flist) + cfile->status_file_deleted = true; + } + spin_unlock(&cinode->open_file_lock); + free_dentry_path(page); +} + /* parses DFS referral V3 structure * caller is responsible for freeing target_nodes * returns: |