0001
0002
0003
0004
0005
0006
0007
0008 #include "cifsglob.h"
0009 #include "cifsproto.h"
0010 #include "cifs_debug.h"
0011 #include "smb2proto.h"
0012 #include "cached_dir.h"
0013
0014
0015
0016
0017
0018 int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
0019 const char *path,
0020 struct cifs_sb_info *cifs_sb,
0021 bool lookup_only, struct cached_fid **ret_cfid)
0022 {
0023 struct cifs_ses *ses;
0024 struct TCP_Server_Info *server;
0025 struct cifs_open_parms oparms;
0026 struct smb2_create_rsp *o_rsp = NULL;
0027 struct smb2_query_info_rsp *qi_rsp = NULL;
0028 int resp_buftype[2];
0029 struct smb_rqst rqst[2];
0030 struct kvec rsp_iov[2];
0031 struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
0032 struct kvec qi_iov[1];
0033 int rc, flags = 0;
0034 __le16 utf16_path = 0;
0035 u8 oplock = SMB2_OPLOCK_LEVEL_II;
0036 struct cifs_fid *pfid;
0037 struct dentry *dentry;
0038 struct cached_fid *cfid;
0039
0040 if (tcon == NULL || tcon->nohandlecache ||
0041 is_smb1_server(tcon->ses->server))
0042 return -EOPNOTSUPP;
0043
0044 ses = tcon->ses;
0045 server = ses->server;
0046
0047 if (cifs_sb->root == NULL)
0048 return -ENOENT;
0049
0050 if (strlen(path))
0051 return -ENOENT;
0052
0053 dentry = cifs_sb->root;
0054
0055 cfid = tcon->cfid;
0056 mutex_lock(&cfid->fid_mutex);
0057 if (cfid->is_valid) {
0058 cifs_dbg(FYI, "found a cached root file handle\n");
0059 *ret_cfid = cfid;
0060 kref_get(&cfid->refcount);
0061 mutex_unlock(&cfid->fid_mutex);
0062 return 0;
0063 }
0064
0065
0066
0067
0068
0069
0070
0071 mutex_unlock(&cfid->fid_mutex);
0072
0073 if (lookup_only)
0074 return -ENOENT;
0075
0076 if (smb3_encryption_required(tcon))
0077 flags |= CIFS_TRANSFORM_REQ;
0078
0079 if (!server->ops->new_lease_key)
0080 return -EIO;
0081
0082 pfid = &cfid->fid;
0083 server->ops->new_lease_key(pfid);
0084
0085 memset(rqst, 0, sizeof(rqst));
0086 resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER;
0087 memset(rsp_iov, 0, sizeof(rsp_iov));
0088
0089
0090 memset(&open_iov, 0, sizeof(open_iov));
0091 rqst[0].rq_iov = open_iov;
0092 rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
0093
0094 oparms.tcon = tcon;
0095 oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE);
0096 oparms.desired_access = FILE_READ_ATTRIBUTES;
0097 oparms.disposition = FILE_OPEN;
0098 oparms.fid = pfid;
0099 oparms.reconnect = false;
0100
0101 rc = SMB2_open_init(tcon, server,
0102 &rqst[0], &oplock, &oparms, &utf16_path);
0103 if (rc)
0104 goto oshr_free;
0105 smb2_set_next_command(tcon, &rqst[0]);
0106
0107 memset(&qi_iov, 0, sizeof(qi_iov));
0108 rqst[1].rq_iov = qi_iov;
0109 rqst[1].rq_nvec = 1;
0110
0111 rc = SMB2_query_info_init(tcon, server,
0112 &rqst[1], COMPOUND_FID,
0113 COMPOUND_FID, FILE_ALL_INFORMATION,
0114 SMB2_O_INFO_FILE, 0,
0115 sizeof(struct smb2_file_all_info) +
0116 PATH_MAX * 2, 0, NULL);
0117 if (rc)
0118 goto oshr_free;
0119
0120 smb2_set_related(&rqst[1]);
0121
0122 rc = compound_send_recv(xid, ses, server,
0123 flags, 2, rqst,
0124 resp_buftype, rsp_iov);
0125 mutex_lock(&cfid->fid_mutex);
0126
0127
0128
0129
0130
0131
0132 if (cfid->is_valid) {
0133
0134
0135
0136 struct cifs_fid fid = {
0137 .persistent_fid = pfid->persistent_fid,
0138 .volatile_fid = pfid->volatile_fid,
0139 };
0140
0141
0142
0143
0144
0145 kref_get(&cfid->refcount);
0146
0147 mutex_unlock(&cfid->fid_mutex);
0148
0149 if (rc == 0) {
0150
0151 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
0152 }
0153 rc = 0;
0154 goto oshr_free;
0155 }
0156
0157
0158
0159 if (rc) {
0160 if (rc == -EREMCHG) {
0161 tcon->need_reconnect = true;
0162 pr_warn_once("server share %s deleted\n",
0163 tcon->treeName);
0164 }
0165 goto oshr_exit;
0166 }
0167
0168 atomic_inc(&tcon->num_remote_opens);
0169
0170 o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
0171 oparms.fid->persistent_fid = o_rsp->PersistentFileId;
0172 oparms.fid->volatile_fid = o_rsp->VolatileFileId;
0173 #ifdef CONFIG_CIFS_DEBUG2
0174 oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId);
0175 #endif
0176
0177 cfid->tcon = tcon;
0178 cfid->is_valid = true;
0179 cfid->dentry = dentry;
0180 dget(dentry);
0181 kref_init(&cfid->refcount);
0182
0183
0184 if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
0185
0186
0187
0188
0189 kref_get(&cfid->refcount);
0190 cfid->has_lease = true;
0191 smb2_parse_contexts(server, o_rsp,
0192 &oparms.fid->epoch,
0193 oparms.fid->lease_key, &oplock,
0194 NULL, NULL);
0195 } else
0196 goto oshr_exit;
0197
0198 qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
0199 if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info))
0200 goto oshr_exit;
0201 if (!smb2_validate_and_copy_iov(
0202 le16_to_cpu(qi_rsp->OutputBufferOffset),
0203 sizeof(struct smb2_file_all_info),
0204 &rsp_iov[1], sizeof(struct smb2_file_all_info),
0205 (char *)&cfid->file_all_info))
0206 cfid->file_all_info_is_valid = true;
0207
0208 cfid->time = jiffies;
0209
0210 oshr_exit:
0211 mutex_unlock(&cfid->fid_mutex);
0212 oshr_free:
0213 SMB2_open_free(&rqst[0]);
0214 SMB2_query_info_free(&rqst[1]);
0215 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
0216 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
0217 if (rc == 0)
0218 *ret_cfid = cfid;
0219
0220 return rc;
0221 }
0222
0223 int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
0224 struct dentry *dentry,
0225 struct cached_fid **ret_cfid)
0226 {
0227 struct cached_fid *cfid;
0228
0229 cfid = tcon->cfid;
0230
0231 mutex_lock(&cfid->fid_mutex);
0232 if (cfid->dentry == dentry) {
0233 cifs_dbg(FYI, "found a cached root file handle by dentry\n");
0234 *ret_cfid = cfid;
0235 kref_get(&cfid->refcount);
0236 mutex_unlock(&cfid->fid_mutex);
0237 return 0;
0238 }
0239 mutex_unlock(&cfid->fid_mutex);
0240 return -ENOENT;
0241 }
0242
0243 static void
0244 smb2_close_cached_fid(struct kref *ref)
0245 {
0246 struct cached_fid *cfid = container_of(ref, struct cached_fid,
0247 refcount);
0248 struct cached_dirent *dirent, *q;
0249
0250 if (cfid->is_valid) {
0251 cifs_dbg(FYI, "clear cached root file handle\n");
0252 SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
0253 cfid->fid.volatile_fid);
0254 }
0255
0256
0257
0258
0259
0260
0261 cfid->is_valid = false;
0262 cfid->file_all_info_is_valid = false;
0263 cfid->has_lease = false;
0264 if (cfid->dentry) {
0265 dput(cfid->dentry);
0266 cfid->dentry = NULL;
0267 }
0268
0269
0270
0271 mutex_lock(&cfid->dirents.de_mutex);
0272 list_for_each_entry_safe(dirent, q, &cfid->dirents.entries, entry) {
0273 list_del(&dirent->entry);
0274 kfree(dirent->name);
0275 kfree(dirent);
0276 }
0277 cfid->dirents.is_valid = 0;
0278 cfid->dirents.is_failed = 0;
0279 cfid->dirents.ctx = NULL;
0280 cfid->dirents.pos = 0;
0281 mutex_unlock(&cfid->dirents.de_mutex);
0282
0283 }
0284
0285 void close_cached_dir(struct cached_fid *cfid)
0286 {
0287 mutex_lock(&cfid->fid_mutex);
0288 kref_put(&cfid->refcount, smb2_close_cached_fid);
0289 mutex_unlock(&cfid->fid_mutex);
0290 }
0291
0292 void close_cached_dir_lease_locked(struct cached_fid *cfid)
0293 {
0294 if (cfid->has_lease) {
0295 cfid->has_lease = false;
0296 kref_put(&cfid->refcount, smb2_close_cached_fid);
0297 }
0298 }
0299
0300 void close_cached_dir_lease(struct cached_fid *cfid)
0301 {
0302 mutex_lock(&cfid->fid_mutex);
0303 close_cached_dir_lease_locked(cfid);
0304 mutex_unlock(&cfid->fid_mutex);
0305 }
0306
0307
0308
0309
0310 void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
0311 {
0312 struct rb_root *root = &cifs_sb->tlink_tree;
0313 struct rb_node *node;
0314 struct cached_fid *cfid;
0315 struct cifs_tcon *tcon;
0316 struct tcon_link *tlink;
0317
0318 for (node = rb_first(root); node; node = rb_next(node)) {
0319 tlink = rb_entry(node, struct tcon_link, tl_rbnode);
0320 tcon = tlink_tcon(tlink);
0321 if (IS_ERR(tcon))
0322 continue;
0323 cfid = tcon->cfid;
0324 mutex_lock(&cfid->fid_mutex);
0325 if (cfid->dentry) {
0326 dput(cfid->dentry);
0327 cfid->dentry = NULL;
0328 }
0329 mutex_unlock(&cfid->fid_mutex);
0330 }
0331 }
0332
0333
0334
0335
0336
0337 void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
0338 {
0339 mutex_lock(&tcon->cfid->fid_mutex);
0340 tcon->cfid->is_valid = false;
0341
0342 close_cached_dir_lease_locked(tcon->cfid);
0343 memset(&tcon->cfid->fid, 0, sizeof(struct cifs_fid));
0344 mutex_unlock(&tcon->cfid->fid_mutex);
0345 }
0346
0347 static void
0348 smb2_cached_lease_break(struct work_struct *work)
0349 {
0350 struct cached_fid *cfid = container_of(work,
0351 struct cached_fid, lease_break);
0352
0353 close_cached_dir_lease(cfid);
0354 }
0355
0356 int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
0357 {
0358 if (tcon->cfid->is_valid &&
0359 !memcmp(lease_key,
0360 tcon->cfid->fid.lease_key,
0361 SMB2_LEASE_KEY_SIZE)) {
0362 tcon->cfid->time = 0;
0363 INIT_WORK(&tcon->cfid->lease_break,
0364 smb2_cached_lease_break);
0365 queue_work(cifsiod_wq,
0366 &tcon->cfid->lease_break);
0367 return true;
0368 }
0369 return false;
0370 }
0371
0372 struct cached_fid *init_cached_dir(void)
0373 {
0374 struct cached_fid *cfid;
0375
0376 cfid = kzalloc(sizeof(*cfid), GFP_KERNEL);
0377 if (!cfid)
0378 return NULL;
0379 INIT_LIST_HEAD(&cfid->dirents.entries);
0380 mutex_init(&cfid->dirents.de_mutex);
0381 mutex_init(&cfid->fid_mutex);
0382 return cfid;
0383 }
0384
0385 void free_cached_dir(struct cifs_tcon *tcon)
0386 {
0387 kfree(tcon->cfid);
0388 }