summaryrefslogtreecommitdiff
path: root/fs/cifs/cached_dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/cached_dir.c')
-rw-r--r--fs/cifs/cached_dir.c92
1 files changed, 72 insertions, 20 deletions
diff --git a/fs/cifs/cached_dir.c b/fs/cifs/cached_dir.c
index b401339f6e73..b705dac383f9 100644
--- a/fs/cifs/cached_dir.c
+++ b/fs/cifs/cached_dir.c
@@ -11,6 +11,8 @@
#include "smb2proto.h"
#include "cached_dir.h"
+struct cached_fid *init_cached_dir(const char *path);
+
/*
* Open the and cache a directory handle.
* If error then *cfid is not initialized.
@@ -47,12 +49,19 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
if (cifs_sb->root == NULL)
return -ENOENT;
- if (strlen(path))
+ if (!path[0])
+ dentry = cifs_sb->root;
+ else
return -ENOENT;
- dentry = cifs_sb->root;
+ cfid = tcon->cfids->cfid;
+ if (cfid == NULL) {
+ cfid = init_cached_dir(path);
+ tcon->cfids->cfid = cfid;
+ }
+ if (cfid == NULL)
+ return -ENOMEM;
- cfid = tcon->cfid;
mutex_lock(&cfid->fid_mutex);
if (cfid->is_valid) {
cifs_dbg(FYI, "found a cached root file handle\n");
@@ -160,7 +169,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
if (rc == -EREMCHG) {
tcon->need_reconnect = true;
pr_warn_once("server share %s deleted\n",
- tcon->treeName);
+ tcon->tree_name);
}
goto oshr_exit;
}
@@ -177,7 +186,8 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
cfid->tcon = tcon;
cfid->is_valid = true;
cfid->dentry = dentry;
- dget(dentry);
+ if (dentry)
+ dget(dentry);
kref_init(&cfid->refcount);
/* BB TBD check to see if oplock level check can be removed below */
@@ -226,7 +236,9 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
{
struct cached_fid *cfid;
- cfid = tcon->cfid;
+ cfid = tcon->cfids->cfid;
+ if (cfid == NULL)
+ return -ENOENT;
mutex_lock(&cfid->fid_mutex);
if (cfid->dentry == dentry) {
@@ -320,7 +332,9 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
tcon = tlink_tcon(tlink);
if (IS_ERR(tcon))
continue;
- cfid = tcon->cfid;
+ cfid = tcon->cfids->cfid;
+ if (cfid == NULL)
+ continue;
mutex_lock(&cfid->fid_mutex);
if (cfid->dentry) {
dput(cfid->dentry);
@@ -336,12 +350,17 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
*/
void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
{
- mutex_lock(&tcon->cfid->fid_mutex);
- tcon->cfid->is_valid = false;
+ struct cached_fid *cfid = tcon->cfids->cfid;
+
+ if (cfid == NULL)
+ return;
+
+ mutex_lock(&cfid->fid_mutex);
+ cfid->is_valid = false;
/* cached handle is not valid, so SMB2_CLOSE won't be sent below */
- close_cached_dir_lease_locked(tcon->cfid);
- memset(&tcon->cfid->fid, 0, sizeof(struct cifs_fid));
- mutex_unlock(&tcon->cfid->fid_mutex);
+ close_cached_dir_lease_locked(cfid);
+ memset(&cfid->fid, 0, sizeof(struct cifs_fid));
+ mutex_unlock(&cfid->fid_mutex);
}
static void
@@ -355,34 +374,67 @@ smb2_cached_lease_break(struct work_struct *work)
int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
{
- if (tcon->cfid->is_valid &&
+ struct cached_fid *cfid = tcon->cfids->cfid;
+
+ if (cfid == NULL)
+ return false;
+
+ if (cfid->is_valid &&
!memcmp(lease_key,
- tcon->cfid->fid.lease_key,
+ cfid->fid.lease_key,
SMB2_LEASE_KEY_SIZE)) {
- tcon->cfid->time = 0;
- INIT_WORK(&tcon->cfid->lease_break,
+ cfid->time = 0;
+ INIT_WORK(&cfid->lease_break,
smb2_cached_lease_break);
queue_work(cifsiod_wq,
- &tcon->cfid->lease_break);
+ &cfid->lease_break);
return true;
}
return false;
}
-struct cached_fid *init_cached_dir(void)
+struct cached_fid *init_cached_dir(const char *path)
{
struct cached_fid *cfid;
cfid = kzalloc(sizeof(*cfid), GFP_KERNEL);
if (!cfid)
return NULL;
+ cfid->path = kstrdup(path, GFP_KERNEL);
+ if (!cfid->path) {
+ kfree(cfid);
+ return NULL;
+ }
+
INIT_LIST_HEAD(&cfid->dirents.entries);
mutex_init(&cfid->dirents.de_mutex);
mutex_init(&cfid->fid_mutex);
return cfid;
}
-void free_cached_dir(struct cifs_tcon *tcon)
+void free_cached_dir(struct cached_fid *cfid)
+{
+ kfree(cfid->path);
+ cfid->path = NULL;
+ kfree(cfid);
+}
+
+struct cached_fids *init_cached_dirs(void)
{
- kfree(tcon->cfid);
+ struct cached_fids *cfids;
+
+ cfids = kzalloc(sizeof(*cfids), GFP_KERNEL);
+ if (!cfids)
+ return NULL;
+ mutex_init(&cfids->cfid_list_mutex);
+ return cfids;
+}
+
+void free_cached_dirs(struct cached_fids *cfids)
+{
+ if (cfids->cfid) {
+ free_cached_dir(cfids->cfid);
+ cfids->cfid = NULL;
+ }
+ kfree(cfids);
}