1871 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org>4 * Copyright (C) 2018 Samsung Electronics Co., Ltd.5 */6 7#include <linux/moduleparam.h>8 9#include "glob.h"10#include "oplock.h"11 12#include "smb_common.h"13#include "../common/smb2status.h"14#include "connection.h"15#include "mgmt/user_session.h"16#include "mgmt/share_config.h"17#include "mgmt/tree_connect.h"18 19static LIST_HEAD(lease_table_list);20static DEFINE_RWLOCK(lease_list_lock);21 22/**23 * alloc_opinfo() - allocate a new opinfo object for oplock info24 * @work: smb work25 * @id: fid of open file26 * @Tid: tree id of connection27 *28 * Return: allocated opinfo object on success, otherwise NULL29 */30static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,31 u64 id, __u16 Tid)32{33 struct ksmbd_conn *conn = work->conn;34 struct ksmbd_session *sess = work->sess;35 struct oplock_info *opinfo;36 37 opinfo = kzalloc(sizeof(struct oplock_info), GFP_KERNEL);38 if (!opinfo)39 return NULL;40 41 opinfo->sess = sess;42 opinfo->conn = conn;43 opinfo->level = SMB2_OPLOCK_LEVEL_NONE;44 opinfo->op_state = OPLOCK_STATE_NONE;45 opinfo->pending_break = 0;46 opinfo->fid = id;47 opinfo->Tid = Tid;48 INIT_LIST_HEAD(&opinfo->op_entry);49 INIT_LIST_HEAD(&opinfo->interim_list);50 init_waitqueue_head(&opinfo->oplock_q);51 init_waitqueue_head(&opinfo->oplock_brk);52 atomic_set(&opinfo->refcount, 1);53 atomic_set(&opinfo->breaking_cnt, 0);54 atomic_inc(&opinfo->conn->refcnt);55 56 return opinfo;57}58 59static void lease_add_list(struct oplock_info *opinfo)60{61 struct lease_table *lb = opinfo->o_lease->l_lb;62 63 spin_lock(&lb->lb_lock);64 list_add_rcu(&opinfo->lease_entry, &lb->lease_list);65 spin_unlock(&lb->lb_lock);66}67 68static void lease_del_list(struct oplock_info *opinfo)69{70 struct lease_table *lb = opinfo->o_lease->l_lb;71 72 if (!lb)73 return;74 75 spin_lock(&lb->lb_lock);76 if (list_empty(&opinfo->lease_entry)) {77 spin_unlock(&lb->lb_lock);78 return;79 }80 81 list_del_init(&opinfo->lease_entry);82 opinfo->o_lease->l_lb = NULL;83 spin_unlock(&lb->lb_lock);84}85 86static void lb_add(struct lease_table *lb)87{88 write_lock(&lease_list_lock);89 list_add(&lb->l_entry, &lease_table_list);90 write_unlock(&lease_list_lock);91}92 93static int alloc_lease(struct oplock_info *opinfo, struct lease_ctx_info *lctx)94{95 struct lease *lease;96 97 lease = kmalloc(sizeof(struct lease), GFP_KERNEL);98 if (!lease)99 return -ENOMEM;100 101 memcpy(lease->lease_key, lctx->lease_key, SMB2_LEASE_KEY_SIZE);102 lease->state = lctx->req_state;103 lease->new_state = 0;104 lease->flags = lctx->flags;105 lease->duration = lctx->duration;106 lease->is_dir = lctx->is_dir;107 memcpy(lease->parent_lease_key, lctx->parent_lease_key, SMB2_LEASE_KEY_SIZE);108 lease->version = lctx->version;109 lease->epoch = le16_to_cpu(lctx->epoch) + 1;110 INIT_LIST_HEAD(&opinfo->lease_entry);111 opinfo->o_lease = lease;112 113 return 0;114}115 116static void free_lease(struct oplock_info *opinfo)117{118 struct lease *lease;119 120 lease = opinfo->o_lease;121 kfree(lease);122}123 124static void free_opinfo(struct oplock_info *opinfo)125{126 if (opinfo->is_lease)127 free_lease(opinfo);128 if (opinfo->conn && atomic_dec_and_test(&opinfo->conn->refcnt))129 kfree(opinfo->conn);130 kfree(opinfo);131}132 133static inline void opinfo_free_rcu(struct rcu_head *rcu_head)134{135 struct oplock_info *opinfo;136 137 opinfo = container_of(rcu_head, struct oplock_info, rcu_head);138 free_opinfo(opinfo);139}140 141struct oplock_info *opinfo_get(struct ksmbd_file *fp)142{143 struct oplock_info *opinfo;144 145 rcu_read_lock();146 opinfo = rcu_dereference(fp->f_opinfo);147 if (opinfo && !atomic_inc_not_zero(&opinfo->refcount))148 opinfo = NULL;149 rcu_read_unlock();150 151 return opinfo;152}153 154static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)155{156 struct oplock_info *opinfo;157 158 if (list_empty(&ci->m_op_list))159 return NULL;160 161 rcu_read_lock();162 opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info,163 op_entry);164 if (opinfo) {165 if (opinfo->conn == NULL ||166 !atomic_inc_not_zero(&opinfo->refcount))167 opinfo = NULL;168 else {169 if (ksmbd_conn_releasing(opinfo->conn)) {170 atomic_dec(&opinfo->refcount);171 opinfo = NULL;172 }173 }174 }175 176 rcu_read_unlock();177 178 return opinfo;179}180 181void opinfo_put(struct oplock_info *opinfo)182{183 if (!opinfo)184 return;185 186 if (!atomic_dec_and_test(&opinfo->refcount))187 return;188 189 call_rcu(&opinfo->rcu_head, opinfo_free_rcu);190}191 192static void opinfo_add(struct oplock_info *opinfo)193{194 struct ksmbd_inode *ci = opinfo->o_fp->f_ci;195 196 down_write(&ci->m_lock);197 list_add_rcu(&opinfo->op_entry, &ci->m_op_list);198 up_write(&ci->m_lock);199}200 201static void opinfo_del(struct oplock_info *opinfo)202{203 struct ksmbd_inode *ci = opinfo->o_fp->f_ci;204 205 if (opinfo->is_lease) {206 write_lock(&lease_list_lock);207 lease_del_list(opinfo);208 write_unlock(&lease_list_lock);209 }210 down_write(&ci->m_lock);211 list_del_rcu(&opinfo->op_entry);212 up_write(&ci->m_lock);213}214 215static unsigned long opinfo_count(struct ksmbd_file *fp)216{217 if (ksmbd_stream_fd(fp))218 return atomic_read(&fp->f_ci->sop_count);219 else220 return atomic_read(&fp->f_ci->op_count);221}222 223static void opinfo_count_inc(struct ksmbd_file *fp)224{225 if (ksmbd_stream_fd(fp))226 return atomic_inc(&fp->f_ci->sop_count);227 else228 return atomic_inc(&fp->f_ci->op_count);229}230 231static void opinfo_count_dec(struct ksmbd_file *fp)232{233 if (ksmbd_stream_fd(fp))234 return atomic_dec(&fp->f_ci->sop_count);235 else236 return atomic_dec(&fp->f_ci->op_count);237}238 239/**240 * opinfo_write_to_read() - convert a write oplock to read oplock241 * @opinfo: current oplock info242 *243 * Return: 0 on success, otherwise -EINVAL244 */245int opinfo_write_to_read(struct oplock_info *opinfo)246{247 struct lease *lease = opinfo->o_lease;248 249 if (!(opinfo->level == SMB2_OPLOCK_LEVEL_BATCH ||250 opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)) {251 pr_err("bad oplock(0x%x)\n", opinfo->level);252 if (opinfo->is_lease)253 pr_err("lease state(0x%x)\n", lease->state);254 return -EINVAL;255 }256 opinfo->level = SMB2_OPLOCK_LEVEL_II;257 258 if (opinfo->is_lease)259 lease->state = lease->new_state;260 return 0;261}262 263/**264 * opinfo_read_handle_to_read() - convert a read/handle oplock to read oplock265 * @opinfo: current oplock info266 *267 * Return: 0 on success, otherwise -EINVAL268 */269int opinfo_read_handle_to_read(struct oplock_info *opinfo)270{271 struct lease *lease = opinfo->o_lease;272 273 lease->state = lease->new_state;274 opinfo->level = SMB2_OPLOCK_LEVEL_II;275 return 0;276}277 278/**279 * opinfo_write_to_none() - convert a write oplock to none280 * @opinfo: current oplock info281 *282 * Return: 0 on success, otherwise -EINVAL283 */284int opinfo_write_to_none(struct oplock_info *opinfo)285{286 struct lease *lease = opinfo->o_lease;287 288 if (!(opinfo->level == SMB2_OPLOCK_LEVEL_BATCH ||289 opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)) {290 pr_err("bad oplock(0x%x)\n", opinfo->level);291 if (opinfo->is_lease)292 pr_err("lease state(0x%x)\n", lease->state);293 return -EINVAL;294 }295 opinfo->level = SMB2_OPLOCK_LEVEL_NONE;296 if (opinfo->is_lease)297 lease->state = lease->new_state;298 return 0;299}300 301/**302 * opinfo_read_to_none() - convert a write read to none303 * @opinfo: current oplock info304 *305 * Return: 0 on success, otherwise -EINVAL306 */307int opinfo_read_to_none(struct oplock_info *opinfo)308{309 struct lease *lease = opinfo->o_lease;310 311 if (opinfo->level != SMB2_OPLOCK_LEVEL_II) {312 pr_err("bad oplock(0x%x)\n", opinfo->level);313 if (opinfo->is_lease)314 pr_err("lease state(0x%x)\n", lease->state);315 return -EINVAL;316 }317 opinfo->level = SMB2_OPLOCK_LEVEL_NONE;318 if (opinfo->is_lease)319 lease->state = lease->new_state;320 return 0;321}322 323/**324 * lease_read_to_write() - upgrade lease state from read to write325 * @opinfo: current lease info326 *327 * Return: 0 on success, otherwise -EINVAL328 */329int lease_read_to_write(struct oplock_info *opinfo)330{331 struct lease *lease = opinfo->o_lease;332 333 if (!(lease->state & SMB2_LEASE_READ_CACHING_LE)) {334 ksmbd_debug(OPLOCK, "bad lease state(0x%x)\n", lease->state);335 return -EINVAL;336 }337 338 lease->new_state = SMB2_LEASE_NONE_LE;339 lease->state |= SMB2_LEASE_WRITE_CACHING_LE;340 if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE)341 opinfo->level = SMB2_OPLOCK_LEVEL_BATCH;342 else343 opinfo->level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;344 return 0;345}346 347/**348 * lease_none_upgrade() - upgrade lease state from none349 * @opinfo: current lease info350 * @new_state: new lease state351 *352 * Return: 0 on success, otherwise -EINVAL353 */354static int lease_none_upgrade(struct oplock_info *opinfo, __le32 new_state)355{356 struct lease *lease = opinfo->o_lease;357 358 if (!(lease->state == SMB2_LEASE_NONE_LE)) {359 ksmbd_debug(OPLOCK, "bad lease state(0x%x)\n", lease->state);360 return -EINVAL;361 }362 363 lease->new_state = SMB2_LEASE_NONE_LE;364 lease->state = new_state;365 if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE)366 if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)367 opinfo->level = SMB2_OPLOCK_LEVEL_BATCH;368 else369 opinfo->level = SMB2_OPLOCK_LEVEL_II;370 else if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)371 opinfo->level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;372 else if (lease->state & SMB2_LEASE_READ_CACHING_LE)373 opinfo->level = SMB2_OPLOCK_LEVEL_II;374 375 return 0;376}377 378/**379 * close_id_del_oplock() - release oplock object at file close time380 * @fp: ksmbd file pointer381 */382void close_id_del_oplock(struct ksmbd_file *fp)383{384 struct oplock_info *opinfo;385 386 if (fp->reserve_lease_break)387 smb_lazy_parent_lease_break_close(fp);388 389 opinfo = opinfo_get(fp);390 if (!opinfo)391 return;392 393 opinfo_del(opinfo);394 395 rcu_assign_pointer(fp->f_opinfo, NULL);396 if (opinfo->op_state == OPLOCK_ACK_WAIT) {397 opinfo->op_state = OPLOCK_CLOSING;398 wake_up_interruptible_all(&opinfo->oplock_q);399 if (opinfo->is_lease) {400 atomic_set(&opinfo->breaking_cnt, 0);401 wake_up_interruptible_all(&opinfo->oplock_brk);402 }403 }404 405 opinfo_count_dec(fp);406 atomic_dec(&opinfo->refcount);407 opinfo_put(opinfo);408}409 410/**411 * grant_write_oplock() - grant exclusive/batch oplock or write lease412 * @opinfo_new: new oplock info object413 * @req_oplock: request oplock414 * @lctx: lease context information415 *416 * Return: 0417 */418static void grant_write_oplock(struct oplock_info *opinfo_new, int req_oplock,419 struct lease_ctx_info *lctx)420{421 struct lease *lease = opinfo_new->o_lease;422 423 if (req_oplock == SMB2_OPLOCK_LEVEL_BATCH)424 opinfo_new->level = SMB2_OPLOCK_LEVEL_BATCH;425 else426 opinfo_new->level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;427 428 if (lctx) {429 lease->state = lctx->req_state;430 memcpy(lease->lease_key, lctx->lease_key, SMB2_LEASE_KEY_SIZE);431 }432}433 434/**435 * grant_read_oplock() - grant level2 oplock or read lease436 * @opinfo_new: new oplock info object437 * @lctx: lease context information438 *439 * Return: 0440 */441static void grant_read_oplock(struct oplock_info *opinfo_new,442 struct lease_ctx_info *lctx)443{444 struct lease *lease = opinfo_new->o_lease;445 446 opinfo_new->level = SMB2_OPLOCK_LEVEL_II;447 448 if (lctx) {449 lease->state = SMB2_LEASE_READ_CACHING_LE;450 if (lctx->req_state & SMB2_LEASE_HANDLE_CACHING_LE)451 lease->state |= SMB2_LEASE_HANDLE_CACHING_LE;452 memcpy(lease->lease_key, lctx->lease_key, SMB2_LEASE_KEY_SIZE);453 }454}455 456/**457 * grant_none_oplock() - grant none oplock or none lease458 * @opinfo_new: new oplock info object459 * @lctx: lease context information460 *461 * Return: 0462 */463static void grant_none_oplock(struct oplock_info *opinfo_new,464 struct lease_ctx_info *lctx)465{466 struct lease *lease = opinfo_new->o_lease;467 468 opinfo_new->level = SMB2_OPLOCK_LEVEL_NONE;469 470 if (lctx) {471 lease->state = 0;472 memcpy(lease->lease_key, lctx->lease_key, SMB2_LEASE_KEY_SIZE);473 }474}475 476static inline int compare_guid_key(struct oplock_info *opinfo,477 const char *guid1, const char *key1)478{479 const char *guid2, *key2;480 481 guid2 = opinfo->conn->ClientGUID;482 key2 = opinfo->o_lease->lease_key;483 if (!memcmp(guid1, guid2, SMB2_CLIENT_GUID_SIZE) &&484 !memcmp(key1, key2, SMB2_LEASE_KEY_SIZE))485 return 1;486 487 return 0;488}489 490/**491 * same_client_has_lease() - check whether current lease request is492 * from lease owner of file493 * @ci: master file pointer494 * @client_guid: Client GUID495 * @lctx: lease context information496 *497 * Return: oplock(lease) object on success, otherwise NULL498 */499static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,500 char *client_guid,501 struct lease_ctx_info *lctx)502{503 int ret;504 struct lease *lease;505 struct oplock_info *opinfo;506 struct oplock_info *m_opinfo = NULL;507 508 if (!lctx)509 return NULL;510 511 /*512 * Compare lease key and client_guid to know request from same owner513 * of same client514 */515 down_read(&ci->m_lock);516 list_for_each_entry(opinfo, &ci->m_op_list, op_entry) {517 if (!opinfo->is_lease || !opinfo->conn)518 continue;519 lease = opinfo->o_lease;520 521 ret = compare_guid_key(opinfo, client_guid, lctx->lease_key);522 if (ret) {523 m_opinfo = opinfo;524 /* skip upgrading lease about breaking lease */525 if (atomic_read(&opinfo->breaking_cnt))526 continue;527 528 /* upgrading lease */529 if ((atomic_read(&ci->op_count) +530 atomic_read(&ci->sop_count)) == 1) {531 if (lease->state != SMB2_LEASE_NONE_LE &&532 lease->state == (lctx->req_state & lease->state)) {533 lease->epoch++;534 lease->state |= lctx->req_state;535 if (lctx->req_state &536 SMB2_LEASE_WRITE_CACHING_LE)537 lease_read_to_write(opinfo);538 539 }540 } else if ((atomic_read(&ci->op_count) +541 atomic_read(&ci->sop_count)) > 1) {542 if (lctx->req_state ==543 (SMB2_LEASE_READ_CACHING_LE |544 SMB2_LEASE_HANDLE_CACHING_LE)) {545 lease->epoch++;546 lease->state = lctx->req_state;547 }548 }549 550 if (lctx->req_state && lease->state ==551 SMB2_LEASE_NONE_LE) {552 lease->epoch++;553 lease_none_upgrade(opinfo, lctx->req_state);554 }555 }556 }557 up_read(&ci->m_lock);558 559 return m_opinfo;560}561 562static void wait_for_break_ack(struct oplock_info *opinfo)563{564 int rc = 0;565 566 rc = wait_event_interruptible_timeout(opinfo->oplock_q,567 opinfo->op_state == OPLOCK_STATE_NONE ||568 opinfo->op_state == OPLOCK_CLOSING,569 OPLOCK_WAIT_TIME);570 571 /* is this a timeout ? */572 if (!rc) {573 if (opinfo->is_lease)574 opinfo->o_lease->state = SMB2_LEASE_NONE_LE;575 opinfo->level = SMB2_OPLOCK_LEVEL_NONE;576 opinfo->op_state = OPLOCK_STATE_NONE;577 }578}579 580static void wake_up_oplock_break(struct oplock_info *opinfo)581{582 clear_bit_unlock(0, &opinfo->pending_break);583 /* memory barrier is needed for wake_up_bit() */584 smp_mb__after_atomic();585 wake_up_bit(&opinfo->pending_break, 0);586}587 588static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level)589{590 while (test_and_set_bit(0, &opinfo->pending_break)) {591 wait_on_bit(&opinfo->pending_break, 0, TASK_UNINTERRUPTIBLE);592 593 /* Not immediately break to none. */594 opinfo->open_trunc = 0;595 596 if (opinfo->op_state == OPLOCK_CLOSING)597 return -ENOENT;598 else if (opinfo->level <= req_op_level) {599 if (opinfo->is_lease == false)600 return 1;601 602 if (opinfo->o_lease->state !=603 (SMB2_LEASE_HANDLE_CACHING_LE |604 SMB2_LEASE_READ_CACHING_LE))605 return 1;606 }607 }608 609 if (opinfo->level <= req_op_level) {610 if (opinfo->is_lease == false) {611 wake_up_oplock_break(opinfo);612 return 1;613 }614 if (opinfo->o_lease->state !=615 (SMB2_LEASE_HANDLE_CACHING_LE |616 SMB2_LEASE_READ_CACHING_LE)) {617 wake_up_oplock_break(opinfo);618 return 1;619 }620 }621 return 0;622}623 624/**625 * __smb2_oplock_break_noti() - send smb2 oplock break cmd from conn626 * to client627 * @wk: smb work object628 *629 * There are two ways this function can be called. 1- while file open we break630 * from exclusive/batch lock to levelII oplock and 2- while file write/truncate631 * we break from levelII oplock no oplock.632 * work->request_buf contains oplock_info.633 */634static void __smb2_oplock_break_noti(struct work_struct *wk)635{636 struct smb2_oplock_break *rsp = NULL;637 struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work);638 struct oplock_break_info *br_info = work->request_buf;639 struct smb2_hdr *rsp_hdr;640 struct ksmbd_file *fp;641 642 fp = ksmbd_lookup_global_fd(br_info->fid);643 if (!fp)644 goto out;645 646 if (allocate_interim_rsp_buf(work)) {647 pr_err("smb2_allocate_rsp_buf failed! ");648 ksmbd_fd_put(work, fp);649 goto out;650 }651 652 rsp_hdr = smb2_get_msg(work->response_buf);653 memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);654 rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;655 rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;656 rsp_hdr->CreditRequest = cpu_to_le16(0);657 rsp_hdr->Command = SMB2_OPLOCK_BREAK;658 rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);659 rsp_hdr->NextCommand = 0;660 rsp_hdr->MessageId = cpu_to_le64(-1);661 rsp_hdr->Id.SyncId.ProcessId = 0;662 rsp_hdr->Id.SyncId.TreeId = 0;663 rsp_hdr->SessionId = 0;664 memset(rsp_hdr->Signature, 0, 16);665 666 rsp = smb2_get_msg(work->response_buf);667 668 rsp->StructureSize = cpu_to_le16(24);669 if (!br_info->open_trunc &&670 (br_info->level == SMB2_OPLOCK_LEVEL_BATCH ||671 br_info->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE))672 rsp->OplockLevel = SMB2_OPLOCK_LEVEL_II;673 else674 rsp->OplockLevel = SMB2_OPLOCK_LEVEL_NONE;675 rsp->Reserved = 0;676 rsp->Reserved2 = 0;677 rsp->PersistentFid = fp->persistent_id;678 rsp->VolatileFid = fp->volatile_id;679 680 ksmbd_fd_put(work, fp);681 if (ksmbd_iov_pin_rsp(work, (void *)rsp,682 sizeof(struct smb2_oplock_break)))683 goto out;684 685 ksmbd_debug(OPLOCK,686 "sending oplock break v_id %llu p_id = %llu lock level = %d\n",687 rsp->VolatileFid, rsp->PersistentFid, rsp->OplockLevel);688 689 ksmbd_conn_write(work);690 691out:692 ksmbd_free_work_struct(work);693}694 695/**696 * smb2_oplock_break_noti() - send smb2 exclusive/batch to level2 oplock697 * break command from server to client698 * @opinfo: oplock info object699 *700 * Return: 0 on success, otherwise error701 */702static int smb2_oplock_break_noti(struct oplock_info *opinfo)703{704 struct ksmbd_conn *conn = opinfo->conn;705 struct oplock_break_info *br_info;706 int ret = 0;707 struct ksmbd_work *work = ksmbd_alloc_work_struct();708 709 if (!work)710 return -ENOMEM;711 712 br_info = kmalloc(sizeof(struct oplock_break_info), GFP_KERNEL);713 if (!br_info) {714 ksmbd_free_work_struct(work);715 return -ENOMEM;716 }717 718 br_info->level = opinfo->level;719 br_info->fid = opinfo->fid;720 br_info->open_trunc = opinfo->open_trunc;721 722 work->request_buf = (char *)br_info;723 work->conn = conn;724 work->sess = opinfo->sess;725 726 if (opinfo->op_state == OPLOCK_ACK_WAIT) {727 INIT_WORK(&work->work, __smb2_oplock_break_noti);728 ksmbd_queue_work(work);729 730 wait_for_break_ack(opinfo);731 } else {732 __smb2_oplock_break_noti(&work->work);733 if (opinfo->level == SMB2_OPLOCK_LEVEL_II)734 opinfo->level = SMB2_OPLOCK_LEVEL_NONE;735 }736 return ret;737}738 739/**740 * __smb2_lease_break_noti() - send lease break command from server741 * to client742 * @wk: smb work object743 */744static void __smb2_lease_break_noti(struct work_struct *wk)745{746 struct smb2_lease_break *rsp = NULL;747 struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work);748 struct lease_break_info *br_info = work->request_buf;749 struct smb2_hdr *rsp_hdr;750 751 if (allocate_interim_rsp_buf(work)) {752 ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! ");753 goto out;754 }755 756 rsp_hdr = smb2_get_msg(work->response_buf);757 memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);758 rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;759 rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;760 rsp_hdr->CreditRequest = cpu_to_le16(0);761 rsp_hdr->Command = SMB2_OPLOCK_BREAK;762 rsp_hdr->Flags = (SMB2_FLAGS_SERVER_TO_REDIR);763 rsp_hdr->NextCommand = 0;764 rsp_hdr->MessageId = cpu_to_le64(-1);765 rsp_hdr->Id.SyncId.ProcessId = 0;766 rsp_hdr->Id.SyncId.TreeId = 0;767 rsp_hdr->SessionId = 0;768 memset(rsp_hdr->Signature, 0, 16);769 770 rsp = smb2_get_msg(work->response_buf);771 rsp->StructureSize = cpu_to_le16(44);772 rsp->Epoch = br_info->epoch;773 rsp->Flags = 0;774 775 if (br_info->curr_state & (SMB2_LEASE_WRITE_CACHING_LE |776 SMB2_LEASE_HANDLE_CACHING_LE))777 rsp->Flags = SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED;778 779 memcpy(rsp->LeaseKey, br_info->lease_key, SMB2_LEASE_KEY_SIZE);780 rsp->CurrentLeaseState = br_info->curr_state;781 rsp->NewLeaseState = br_info->new_state;782 rsp->BreakReason = 0;783 rsp->AccessMaskHint = 0;784 rsp->ShareMaskHint = 0;785 786 if (ksmbd_iov_pin_rsp(work, (void *)rsp,787 sizeof(struct smb2_lease_break)))788 goto out;789 790 ksmbd_conn_write(work);791 792out:793 ksmbd_free_work_struct(work);794}795 796/**797 * smb2_lease_break_noti() - break lease when a new client request798 * write lease799 * @opinfo: contains lease state information800 *801 * Return: 0 on success, otherwise error802 */803static int smb2_lease_break_noti(struct oplock_info *opinfo)804{805 struct ksmbd_conn *conn = opinfo->conn;806 struct list_head *tmp, *t;807 struct ksmbd_work *work;808 struct lease_break_info *br_info;809 struct lease *lease = opinfo->o_lease;810 811 work = ksmbd_alloc_work_struct();812 if (!work)813 return -ENOMEM;814 815 br_info = kmalloc(sizeof(struct lease_break_info), GFP_KERNEL);816 if (!br_info) {817 ksmbd_free_work_struct(work);818 return -ENOMEM;819 }820 821 br_info->curr_state = lease->state;822 br_info->new_state = lease->new_state;823 if (lease->version == 2)824 br_info->epoch = cpu_to_le16(++lease->epoch);825 else826 br_info->epoch = 0;827 memcpy(br_info->lease_key, lease->lease_key, SMB2_LEASE_KEY_SIZE);828 829 work->request_buf = (char *)br_info;830 work->conn = conn;831 work->sess = opinfo->sess;832 833 if (opinfo->op_state == OPLOCK_ACK_WAIT) {834 list_for_each_safe(tmp, t, &opinfo->interim_list) {835 struct ksmbd_work *in_work;836 837 in_work = list_entry(tmp, struct ksmbd_work,838 interim_entry);839 setup_async_work(in_work, NULL, NULL);840 smb2_send_interim_resp(in_work, STATUS_PENDING);841 list_del_init(&in_work->interim_entry);842 release_async_work(in_work);843 }844 INIT_WORK(&work->work, __smb2_lease_break_noti);845 ksmbd_queue_work(work);846 wait_for_break_ack(opinfo);847 } else {848 __smb2_lease_break_noti(&work->work);849 if (opinfo->o_lease->new_state == SMB2_LEASE_NONE_LE) {850 opinfo->level = SMB2_OPLOCK_LEVEL_NONE;851 opinfo->o_lease->state = SMB2_LEASE_NONE_LE;852 }853 }854 return 0;855}856 857static void wait_lease_breaking(struct oplock_info *opinfo)858{859 if (!opinfo->is_lease)860 return;861 862 wake_up_interruptible_all(&opinfo->oplock_brk);863 if (atomic_read(&opinfo->breaking_cnt)) {864 int ret = 0;865 866 ret = wait_event_interruptible_timeout(opinfo->oplock_brk,867 atomic_read(&opinfo->breaking_cnt) == 0,868 HZ);869 if (!ret)870 atomic_set(&opinfo->breaking_cnt, 0);871 }872}873 874static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level)875{876 int err = 0;877 878 /* Need to break exclusive/batch oplock, write lease or overwrite_if */879 ksmbd_debug(OPLOCK,880 "request to send oplock(level : 0x%x) break notification\n",881 brk_opinfo->level);882 883 if (brk_opinfo->is_lease) {884 struct lease *lease = brk_opinfo->o_lease;885 886 atomic_inc(&brk_opinfo->breaking_cnt);887 err = oplock_break_pending(brk_opinfo, req_op_level);888 if (err)889 return err < 0 ? err : 0;890 891 if (brk_opinfo->open_trunc) {892 /*893 * Create overwrite break trigger the lease break to894 * none.895 */896 lease->new_state = SMB2_LEASE_NONE_LE;897 } else {898 if (lease->state & SMB2_LEASE_WRITE_CACHING_LE) {899 if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE)900 lease->new_state =901 SMB2_LEASE_READ_CACHING_LE |902 SMB2_LEASE_HANDLE_CACHING_LE;903 else904 lease->new_state =905 SMB2_LEASE_READ_CACHING_LE;906 } else {907 if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE &&908 !lease->is_dir)909 lease->new_state =910 SMB2_LEASE_READ_CACHING_LE;911 else912 lease->new_state = SMB2_LEASE_NONE_LE;913 }914 }915 916 if (lease->state & (SMB2_LEASE_WRITE_CACHING_LE |917 SMB2_LEASE_HANDLE_CACHING_LE))918 brk_opinfo->op_state = OPLOCK_ACK_WAIT;919 else920 atomic_dec(&brk_opinfo->breaking_cnt);921 } else {922 err = oplock_break_pending(brk_opinfo, req_op_level);923 if (err)924 return err < 0 ? err : 0;925 926 if (brk_opinfo->level == SMB2_OPLOCK_LEVEL_BATCH ||927 brk_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)928 brk_opinfo->op_state = OPLOCK_ACK_WAIT;929 }930 931 if (brk_opinfo->is_lease)932 err = smb2_lease_break_noti(brk_opinfo);933 else934 err = smb2_oplock_break_noti(brk_opinfo);935 936 ksmbd_debug(OPLOCK, "oplock granted = %d\n", brk_opinfo->level);937 if (brk_opinfo->op_state == OPLOCK_CLOSING)938 err = -ENOENT;939 wake_up_oplock_break(brk_opinfo);940 941 wait_lease_breaking(brk_opinfo);942 943 return err;944}945 946void destroy_lease_table(struct ksmbd_conn *conn)947{948 struct lease_table *lb, *lbtmp;949 struct oplock_info *opinfo;950 951 write_lock(&lease_list_lock);952 if (list_empty(&lease_table_list)) {953 write_unlock(&lease_list_lock);954 return;955 }956 957 list_for_each_entry_safe(lb, lbtmp, &lease_table_list, l_entry) {958 if (conn && memcmp(lb->client_guid, conn->ClientGUID,959 SMB2_CLIENT_GUID_SIZE))960 continue;961again:962 rcu_read_lock();963 list_for_each_entry_rcu(opinfo, &lb->lease_list,964 lease_entry) {965 rcu_read_unlock();966 lease_del_list(opinfo);967 goto again;968 }969 rcu_read_unlock();970 list_del(&lb->l_entry);971 kfree(lb);972 }973 write_unlock(&lease_list_lock);974}975 976int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,977 struct lease_ctx_info *lctx)978{979 struct oplock_info *opinfo;980 int err = 0;981 struct lease_table *lb;982 983 if (!lctx)984 return err;985 986 read_lock(&lease_list_lock);987 if (list_empty(&lease_table_list)) {988 read_unlock(&lease_list_lock);989 return 0;990 }991 992 list_for_each_entry(lb, &lease_table_list, l_entry) {993 if (!memcmp(lb->client_guid, sess->ClientGUID,994 SMB2_CLIENT_GUID_SIZE))995 goto found;996 }997 read_unlock(&lease_list_lock);998 999 return 0;1000 1001found:1002 rcu_read_lock();1003 list_for_each_entry_rcu(opinfo, &lb->lease_list, lease_entry) {1004 if (!atomic_inc_not_zero(&opinfo->refcount))1005 continue;1006 rcu_read_unlock();1007 if (opinfo->o_fp->f_ci == ci)1008 goto op_next;1009 err = compare_guid_key(opinfo, sess->ClientGUID,1010 lctx->lease_key);1011 if (err) {1012 err = -EINVAL;1013 ksmbd_debug(OPLOCK,1014 "found same lease key is already used in other files\n");1015 opinfo_put(opinfo);1016 goto out;1017 }1018op_next:1019 opinfo_put(opinfo);1020 rcu_read_lock();1021 }1022 rcu_read_unlock();1023 1024out:1025 read_unlock(&lease_list_lock);1026 return err;1027}1028 1029static void copy_lease(struct oplock_info *op1, struct oplock_info *op2)1030{1031 struct lease *lease1 = op1->o_lease;1032 struct lease *lease2 = op2->o_lease;1033 1034 op2->level = op1->level;1035 lease2->state = lease1->state;1036 memcpy(lease2->lease_key, lease1->lease_key,1037 SMB2_LEASE_KEY_SIZE);1038 lease2->duration = lease1->duration;1039 lease2->flags = lease1->flags;1040 lease2->epoch = lease1->epoch;1041 lease2->version = lease1->version;1042}1043 1044static int add_lease_global_list(struct oplock_info *opinfo)1045{1046 struct lease_table *lb;1047 1048 read_lock(&lease_list_lock);1049 list_for_each_entry(lb, &lease_table_list, l_entry) {1050 if (!memcmp(lb->client_guid, opinfo->conn->ClientGUID,1051 SMB2_CLIENT_GUID_SIZE)) {1052 opinfo->o_lease->l_lb = lb;1053 lease_add_list(opinfo);1054 read_unlock(&lease_list_lock);1055 return 0;1056 }1057 }1058 read_unlock(&lease_list_lock);1059 1060 lb = kmalloc(sizeof(struct lease_table), GFP_KERNEL);1061 if (!lb)1062 return -ENOMEM;1063 1064 memcpy(lb->client_guid, opinfo->conn->ClientGUID,1065 SMB2_CLIENT_GUID_SIZE);1066 INIT_LIST_HEAD(&lb->lease_list);1067 spin_lock_init(&lb->lb_lock);1068 opinfo->o_lease->l_lb = lb;1069 lease_add_list(opinfo);1070 lb_add(lb);1071 return 0;1072}1073 1074static void set_oplock_level(struct oplock_info *opinfo, int level,1075 struct lease_ctx_info *lctx)1076{1077 switch (level) {1078 case SMB2_OPLOCK_LEVEL_BATCH:1079 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:1080 grant_write_oplock(opinfo, level, lctx);1081 break;1082 case SMB2_OPLOCK_LEVEL_II:1083 grant_read_oplock(opinfo, lctx);1084 break;1085 default:1086 grant_none_oplock(opinfo, lctx);1087 break;1088 }1089}1090 1091void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,1092 struct lease_ctx_info *lctx)1093{1094 struct oplock_info *opinfo;1095 struct ksmbd_inode *p_ci = NULL;1096 1097 if (lctx->version != 2)1098 return;1099 1100 p_ci = ksmbd_inode_lookup_lock(fp->filp->f_path.dentry->d_parent);1101 if (!p_ci)1102 return;1103 1104 down_read(&p_ci->m_lock);1105 list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) {1106 if (opinfo->conn == NULL || !opinfo->is_lease)1107 continue;1108 1109 if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE &&1110 (!(lctx->flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE) ||1111 !compare_guid_key(opinfo, fp->conn->ClientGUID,1112 lctx->parent_lease_key))) {1113 if (!atomic_inc_not_zero(&opinfo->refcount))1114 continue;1115 1116 if (ksmbd_conn_releasing(opinfo->conn))1117 continue;1118 1119 oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);1120 opinfo_put(opinfo);1121 }1122 }1123 up_read(&p_ci->m_lock);1124 1125 ksmbd_inode_put(p_ci);1126}1127 1128void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)1129{1130 struct oplock_info *opinfo;1131 struct ksmbd_inode *p_ci = NULL;1132 1133 rcu_read_lock();1134 opinfo = rcu_dereference(fp->f_opinfo);1135 rcu_read_unlock();1136 1137 if (!opinfo || !opinfo->is_lease || opinfo->o_lease->version != 2)1138 return;1139 1140 p_ci = ksmbd_inode_lookup_lock(fp->filp->f_path.dentry->d_parent);1141 if (!p_ci)1142 return;1143 1144 down_read(&p_ci->m_lock);1145 list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) {1146 if (opinfo->conn == NULL || !opinfo->is_lease)1147 continue;1148 1149 if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE) {1150 if (!atomic_inc_not_zero(&opinfo->refcount))1151 continue;1152 1153 if (ksmbd_conn_releasing(opinfo->conn))1154 continue;1155 oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);1156 opinfo_put(opinfo);1157 }1158 }1159 up_read(&p_ci->m_lock);1160 1161 ksmbd_inode_put(p_ci);1162}1163 1164/**1165 * smb_grant_oplock() - handle oplock/lease request on file open1166 * @work: smb work1167 * @req_op_level: oplock level1168 * @pid: id of open file1169 * @fp: ksmbd file pointer1170 * @tid: Tree id of connection1171 * @lctx: lease context information on file open1172 * @share_ret: share mode1173 *1174 * Return: 0 on success, otherwise error1175 */1176int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,1177 struct ksmbd_file *fp, __u16 tid,1178 struct lease_ctx_info *lctx, int share_ret)1179{1180 struct ksmbd_session *sess = work->sess;1181 int err = 0;1182 struct oplock_info *opinfo = NULL, *prev_opinfo = NULL;1183 struct ksmbd_inode *ci = fp->f_ci;1184 bool prev_op_has_lease;1185 __le32 prev_op_state = 0;1186 1187 /* Only v2 leases handle the directory */1188 if (S_ISDIR(file_inode(fp->filp)->i_mode)) {1189 if (!lctx || lctx->version != 2 ||1190 (lctx->flags != SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE &&1191 !lctx->epoch))1192 return 0;1193 }1194 1195 opinfo = alloc_opinfo(work, pid, tid);1196 if (!opinfo)1197 return -ENOMEM;1198 1199 if (lctx) {1200 err = alloc_lease(opinfo, lctx);1201 if (err)1202 goto err_out;1203 opinfo->is_lease = 1;1204 }1205 1206 /* ci does not have any oplock */1207 if (!opinfo_count(fp))1208 goto set_lev;1209 1210 /* grant none-oplock if second open is trunc */1211 if (fp->attrib_only && fp->cdoption != FILE_OVERWRITE_IF_LE &&1212 fp->cdoption != FILE_OVERWRITE_LE &&1213 fp->cdoption != FILE_SUPERSEDE_LE) {1214 req_op_level = SMB2_OPLOCK_LEVEL_NONE;1215 goto set_lev;1216 }1217 1218 if (lctx) {1219 struct oplock_info *m_opinfo;1220 1221 /* is lease already granted ? */1222 m_opinfo = same_client_has_lease(ci, sess->ClientGUID,1223 lctx);1224 if (m_opinfo) {1225 copy_lease(m_opinfo, opinfo);1226 if (atomic_read(&m_opinfo->breaking_cnt))1227 opinfo->o_lease->flags =1228 SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE;1229 goto out;1230 }1231 }1232 prev_opinfo = opinfo_get_list(ci);1233 if (!prev_opinfo ||1234 (prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) {1235 opinfo_put(prev_opinfo);1236 goto set_lev;1237 }1238 prev_op_has_lease = prev_opinfo->is_lease;1239 if (prev_op_has_lease)1240 prev_op_state = prev_opinfo->o_lease->state;1241 1242 if (share_ret < 0 &&1243 prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {1244 err = share_ret;1245 opinfo_put(prev_opinfo);1246 goto err_out;1247 }1248 1249 if (prev_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&1250 prev_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {1251 opinfo_put(prev_opinfo);1252 goto op_break_not_needed;1253 }1254 1255 list_add(&work->interim_entry, &prev_opinfo->interim_list);1256 err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II);1257 opinfo_put(prev_opinfo);1258 if (err == -ENOENT)1259 goto set_lev;1260 /* Check all oplock was freed by close */1261 else if (err < 0)1262 goto err_out;1263 1264op_break_not_needed:1265 if (share_ret < 0) {1266 err = share_ret;1267 goto err_out;1268 }1269 1270 if (req_op_level != SMB2_OPLOCK_LEVEL_NONE)1271 req_op_level = SMB2_OPLOCK_LEVEL_II;1272 1273 /* grant fixed oplock on stacked locking between lease and oplock */1274 if (prev_op_has_lease && !lctx)1275 if (prev_op_state & SMB2_LEASE_HANDLE_CACHING_LE)1276 req_op_level = SMB2_OPLOCK_LEVEL_NONE;1277 1278 if (!prev_op_has_lease && lctx) {1279 req_op_level = SMB2_OPLOCK_LEVEL_II;1280 lctx->req_state = SMB2_LEASE_READ_CACHING_LE;1281 }1282 1283set_lev:1284 set_oplock_level(opinfo, req_op_level, lctx);1285 1286out:1287 rcu_assign_pointer(fp->f_opinfo, opinfo);1288 opinfo->o_fp = fp;1289 1290 opinfo_count_inc(fp);1291 opinfo_add(opinfo);1292 if (opinfo->is_lease) {1293 err = add_lease_global_list(opinfo);1294 if (err)1295 goto err_out;1296 }1297 1298 return 0;1299err_out:1300 free_opinfo(opinfo);1301 return err;1302}1303 1304/**1305 * smb_break_all_write_oplock() - break batch/exclusive oplock to level21306 * @work: smb work1307 * @fp: ksmbd file pointer1308 * @is_trunc: truncate on open1309 */1310static void smb_break_all_write_oplock(struct ksmbd_work *work,1311 struct ksmbd_file *fp, int is_trunc)1312{1313 struct oplock_info *brk_opinfo;1314 1315 brk_opinfo = opinfo_get_list(fp->f_ci);1316 if (!brk_opinfo)1317 return;1318 if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&1319 brk_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {1320 opinfo_put(brk_opinfo);1321 return;1322 }1323 1324 brk_opinfo->open_trunc = is_trunc;1325 list_add(&work->interim_entry, &brk_opinfo->interim_list);1326 oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II);1327 opinfo_put(brk_opinfo);1328}1329 1330/**1331 * smb_break_all_levII_oplock() - send level2 oplock or read lease break command1332 * from server to client1333 * @work: smb work1334 * @fp: ksmbd file pointer1335 * @is_trunc: truncate on open1336 */1337void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,1338 int is_trunc)1339{1340 struct oplock_info *op, *brk_op;1341 struct ksmbd_inode *ci;1342 struct ksmbd_conn *conn = work->conn;1343 1344 if (!test_share_config_flag(work->tcon->share_conf,1345 KSMBD_SHARE_FLAG_OPLOCKS))1346 return;1347 1348 ci = fp->f_ci;1349 op = opinfo_get(fp);1350 1351 rcu_read_lock();1352 list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) {1353 if (brk_op->conn == NULL)1354 continue;1355 1356 if (!atomic_inc_not_zero(&brk_op->refcount))1357 continue;1358 1359 if (ksmbd_conn_releasing(brk_op->conn))1360 continue;1361 1362 rcu_read_unlock();1363 if (brk_op->is_lease && (brk_op->o_lease->state &1364 (~(SMB2_LEASE_READ_CACHING_LE |1365 SMB2_LEASE_HANDLE_CACHING_LE)))) {1366 ksmbd_debug(OPLOCK, "unexpected lease state(0x%x)\n",1367 brk_op->o_lease->state);1368 goto next;1369 } else if (brk_op->level !=1370 SMB2_OPLOCK_LEVEL_II) {1371 ksmbd_debug(OPLOCK, "unexpected oplock(0x%x)\n",1372 brk_op->level);1373 goto next;1374 }1375 1376 /* Skip oplock being break to none */1377 if (brk_op->is_lease &&1378 brk_op->o_lease->new_state == SMB2_LEASE_NONE_LE &&1379 atomic_read(&brk_op->breaking_cnt))1380 goto next;1381 1382 if (op && op->is_lease && brk_op->is_lease &&1383 !memcmp(conn->ClientGUID, brk_op->conn->ClientGUID,1384 SMB2_CLIENT_GUID_SIZE) &&1385 !memcmp(op->o_lease->lease_key, brk_op->o_lease->lease_key,1386 SMB2_LEASE_KEY_SIZE))1387 goto next;1388 brk_op->open_trunc = is_trunc;1389 oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE);1390next:1391 opinfo_put(brk_op);1392 rcu_read_lock();1393 }1394 rcu_read_unlock();1395 1396 if (op)1397 opinfo_put(op);1398}1399 1400/**1401 * smb_break_all_oplock() - break both batch/exclusive and level2 oplock1402 * @work: smb work1403 * @fp: ksmbd file pointer1404 */1405void smb_break_all_oplock(struct ksmbd_work *work, struct ksmbd_file *fp)1406{1407 if (!test_share_config_flag(work->tcon->share_conf,1408 KSMBD_SHARE_FLAG_OPLOCKS))1409 return;1410 1411 smb_break_all_write_oplock(work, fp, 1);1412 smb_break_all_levII_oplock(work, fp, 1);1413}1414 1415/**1416 * smb2_map_lease_to_oplock() - map lease state to corresponding oplock type1417 * @lease_state: lease type1418 *1419 * Return: 0 if no mapping, otherwise corresponding oplock type1420 */1421__u8 smb2_map_lease_to_oplock(__le32 lease_state)1422{1423 if (lease_state == (SMB2_LEASE_HANDLE_CACHING_LE |1424 SMB2_LEASE_READ_CACHING_LE |1425 SMB2_LEASE_WRITE_CACHING_LE)) {1426 return SMB2_OPLOCK_LEVEL_BATCH;1427 } else if (lease_state != SMB2_LEASE_WRITE_CACHING_LE &&1428 lease_state & SMB2_LEASE_WRITE_CACHING_LE) {1429 if (!(lease_state & SMB2_LEASE_HANDLE_CACHING_LE))1430 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;1431 } else if (lease_state & SMB2_LEASE_READ_CACHING_LE) {1432 return SMB2_OPLOCK_LEVEL_II;1433 }1434 return 0;1435}1436 1437/**1438 * create_lease_buf() - create lease context for open cmd response1439 * @rbuf: buffer to create lease context response1440 * @lease: buffer to stored parsed lease state information1441 */1442void create_lease_buf(u8 *rbuf, struct lease *lease)1443{1444 if (lease->version == 2) {1445 struct create_lease_v2 *buf = (struct create_lease_v2 *)rbuf;1446 1447 memset(buf, 0, sizeof(struct create_lease_v2));1448 memcpy(buf->lcontext.LeaseKey, lease->lease_key,1449 SMB2_LEASE_KEY_SIZE);1450 buf->lcontext.LeaseFlags = lease->flags;1451 buf->lcontext.Epoch = cpu_to_le16(lease->epoch);1452 buf->lcontext.LeaseState = lease->state;1453 if (lease->flags == SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)1454 memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key,1455 SMB2_LEASE_KEY_SIZE);1456 buf->ccontext.DataOffset = cpu_to_le16(offsetof1457 (struct create_lease_v2, lcontext));1458 buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context_v2));1459 buf->ccontext.NameOffset = cpu_to_le16(offsetof1460 (struct create_lease_v2, Name));1461 buf->ccontext.NameLength = cpu_to_le16(4);1462 buf->Name[0] = 'R';1463 buf->Name[1] = 'q';1464 buf->Name[2] = 'L';1465 buf->Name[3] = 's';1466 } else {1467 struct create_lease *buf = (struct create_lease *)rbuf;1468 1469 memset(buf, 0, sizeof(struct create_lease));1470 memcpy(buf->lcontext.LeaseKey, lease->lease_key, SMB2_LEASE_KEY_SIZE);1471 buf->lcontext.LeaseFlags = lease->flags;1472 buf->lcontext.LeaseState = lease->state;1473 buf->ccontext.DataOffset = cpu_to_le16(offsetof1474 (struct create_lease, lcontext));1475 buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context));1476 buf->ccontext.NameOffset = cpu_to_le16(offsetof1477 (struct create_lease, Name));1478 buf->ccontext.NameLength = cpu_to_le16(4);1479 buf->Name[0] = 'R';1480 buf->Name[1] = 'q';1481 buf->Name[2] = 'L';1482 buf->Name[3] = 's';1483 }1484}1485 1486/**1487 * parse_lease_state() - parse lease context contained in file open request1488 * @open_req: buffer containing smb2 file open(create) request1489 *1490 * Return: allocated lease context object on success, otherwise NULL1491 */1492struct lease_ctx_info *parse_lease_state(void *open_req)1493{1494 struct create_context *cc;1495 struct smb2_create_req *req = (struct smb2_create_req *)open_req;1496 struct lease_ctx_info *lreq;1497 1498 cc = smb2_find_context_vals(req, SMB2_CREATE_REQUEST_LEASE, 4);1499 if (IS_ERR_OR_NULL(cc))1500 return NULL;1501 1502 lreq = kzalloc(sizeof(struct lease_ctx_info), GFP_KERNEL);1503 if (!lreq)1504 return NULL;1505 1506 if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {1507 struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;1508 1509 memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);1510 lreq->req_state = lc->lcontext.LeaseState;1511 lreq->flags = lc->lcontext.LeaseFlags;1512 lreq->epoch = lc->lcontext.Epoch;1513 lreq->duration = lc->lcontext.LeaseDuration;1514 if (lreq->flags == SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)1515 memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,1516 SMB2_LEASE_KEY_SIZE);1517 lreq->version = 2;1518 } else {1519 struct create_lease *lc = (struct create_lease *)cc;1520 1521 memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);1522 lreq->req_state = lc->lcontext.LeaseState;1523 lreq->flags = lc->lcontext.LeaseFlags;1524 lreq->duration = lc->lcontext.LeaseDuration;1525 lreq->version = 1;1526 }1527 return lreq;1528}1529 1530/**1531 * smb2_find_context_vals() - find a particular context info in open request1532 * @open_req: buffer containing smb2 file open(create) request1533 * @tag: context name to search for1534 * @tag_len: the length of tag1535 *1536 * Return: pointer to requested context, NULL if @str context not found1537 * or error pointer if name length is invalid.1538 */1539struct create_context *smb2_find_context_vals(void *open_req, const char *tag, int tag_len)1540{1541 struct create_context *cc;1542 unsigned int next = 0;1543 char *name;1544 struct smb2_create_req *req = (struct smb2_create_req *)open_req;1545 unsigned int remain_len, name_off, name_len, value_off, value_len,1546 cc_len;1547 1548 /*1549 * CreateContextsOffset and CreateContextsLength are guaranteed to1550 * be valid because of ksmbd_smb2_check_message().1551 */1552 cc = (struct create_context *)((char *)req +1553 le32_to_cpu(req->CreateContextsOffset));1554 remain_len = le32_to_cpu(req->CreateContextsLength);1555 do {1556 cc = (struct create_context *)((char *)cc + next);1557 if (remain_len < offsetof(struct create_context, Buffer))1558 return ERR_PTR(-EINVAL);1559 1560 next = le32_to_cpu(cc->Next);1561 name_off = le16_to_cpu(cc->NameOffset);1562 name_len = le16_to_cpu(cc->NameLength);1563 value_off = le16_to_cpu(cc->DataOffset);1564 value_len = le32_to_cpu(cc->DataLength);1565 cc_len = next ? next : remain_len;1566 1567 if ((next & 0x7) != 0 ||1568 next > remain_len ||1569 name_off != offsetof(struct create_context, Buffer) ||1570 name_len < 4 ||1571 name_off + name_len > cc_len ||1572 (value_off & 0x7) != 0 ||1573 (value_len && value_off < name_off + (name_len < 8 ? 8 : name_len)) ||1574 ((u64)value_off + value_len > cc_len))1575 return ERR_PTR(-EINVAL);1576 1577 name = (char *)cc + name_off;1578 if (name_len == tag_len && !memcmp(name, tag, name_len))1579 return cc;1580 1581 remain_len -= next;1582 } while (next != 0);1583 1584 return NULL;1585}1586 1587/**1588 * create_durable_rsp_buf() - create durable handle context1589 * @cc: buffer to create durable context response1590 */1591void create_durable_rsp_buf(char *cc)1592{1593 struct create_durable_rsp *buf;1594 1595 buf = (struct create_durable_rsp *)cc;1596 memset(buf, 0, sizeof(struct create_durable_rsp));1597 buf->ccontext.DataOffset = cpu_to_le16(offsetof1598 (struct create_durable_rsp, Data));1599 buf->ccontext.DataLength = cpu_to_le32(8);1600 buf->ccontext.NameOffset = cpu_to_le16(offsetof1601 (struct create_durable_rsp, Name));1602 buf->ccontext.NameLength = cpu_to_le16(4);1603 /* SMB2_CREATE_DURABLE_HANDLE_RESPONSE is "DHnQ" */1604 buf->Name[0] = 'D';1605 buf->Name[1] = 'H';1606 buf->Name[2] = 'n';1607 buf->Name[3] = 'Q';1608}1609 1610/**1611 * create_durable_v2_rsp_buf() - create durable handle v2 context1612 * @cc: buffer to create durable context response1613 * @fp: ksmbd file pointer1614 */1615void create_durable_v2_rsp_buf(char *cc, struct ksmbd_file *fp)1616{1617 struct create_durable_v2_rsp *buf;1618 1619 buf = (struct create_durable_v2_rsp *)cc;1620 memset(buf, 0, sizeof(struct create_durable_rsp));1621 buf->ccontext.DataOffset = cpu_to_le16(offsetof1622 (struct create_durable_rsp, Data));1623 buf->ccontext.DataLength = cpu_to_le32(8);1624 buf->ccontext.NameOffset = cpu_to_le16(offsetof1625 (struct create_durable_rsp, Name));1626 buf->ccontext.NameLength = cpu_to_le16(4);1627 /* SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2 is "DH2Q" */1628 buf->Name[0] = 'D';1629 buf->Name[1] = 'H';1630 buf->Name[2] = '2';1631 buf->Name[3] = 'Q';1632 1633 buf->Timeout = cpu_to_le32(fp->durable_timeout);1634 if (fp->is_persistent)1635 buf->Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);1636}1637 1638/**1639 * create_mxac_rsp_buf() - create query maximal access context1640 * @cc: buffer to create maximal access context response1641 * @maximal_access: maximal access1642 */1643void create_mxac_rsp_buf(char *cc, int maximal_access)1644{1645 struct create_mxac_rsp *buf;1646 1647 buf = (struct create_mxac_rsp *)cc;1648 memset(buf, 0, sizeof(struct create_mxac_rsp));1649 buf->ccontext.DataOffset = cpu_to_le16(offsetof1650 (struct create_mxac_rsp, QueryStatus));1651 buf->ccontext.DataLength = cpu_to_le32(8);1652 buf->ccontext.NameOffset = cpu_to_le16(offsetof1653 (struct create_mxac_rsp, Name));1654 buf->ccontext.NameLength = cpu_to_le16(4);1655 /* SMB2_CREATE_QUERY_MAXIMAL_ACCESS_RESPONSE is "MxAc" */1656 buf->Name[0] = 'M';1657 buf->Name[1] = 'x';1658 buf->Name[2] = 'A';1659 buf->Name[3] = 'c';1660 1661 buf->QueryStatus = STATUS_SUCCESS;1662 buf->MaximalAccess = cpu_to_le32(maximal_access);1663}1664 1665void create_disk_id_rsp_buf(char *cc, __u64 file_id, __u64 vol_id)1666{1667 struct create_disk_id_rsp *buf;1668 1669 buf = (struct create_disk_id_rsp *)cc;1670 memset(buf, 0, sizeof(struct create_disk_id_rsp));1671 buf->ccontext.DataOffset = cpu_to_le16(offsetof1672 (struct create_disk_id_rsp, DiskFileId));1673 buf->ccontext.DataLength = cpu_to_le32(32);1674 buf->ccontext.NameOffset = cpu_to_le16(offsetof1675 (struct create_mxac_rsp, Name));1676 buf->ccontext.NameLength = cpu_to_le16(4);1677 /* SMB2_CREATE_QUERY_ON_DISK_ID_RESPONSE is "QFid" */1678 buf->Name[0] = 'Q';1679 buf->Name[1] = 'F';1680 buf->Name[2] = 'i';1681 buf->Name[3] = 'd';1682 1683 buf->DiskFileId = cpu_to_le64(file_id);1684 buf->VolumeId = cpu_to_le64(vol_id);1685}1686 1687/**1688 * create_posix_rsp_buf() - create posix extension context1689 * @cc: buffer to create posix on posix response1690 * @fp: ksmbd file pointer1691 */1692void create_posix_rsp_buf(char *cc, struct ksmbd_file *fp)1693{1694 struct create_posix_rsp *buf;1695 struct inode *inode = file_inode(fp->filp);1696 struct mnt_idmap *idmap = file_mnt_idmap(fp->filp);1697 vfsuid_t vfsuid = i_uid_into_vfsuid(idmap, inode);1698 vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);1699 1700 buf = (struct create_posix_rsp *)cc;1701 memset(buf, 0, sizeof(struct create_posix_rsp));1702 buf->ccontext.DataOffset = cpu_to_le16(offsetof1703 (struct create_posix_rsp, nlink));1704 /*1705 * DataLength = nlink(4) + reparse_tag(4) + mode(4) +1706 * domain sid(28) + unix group sid(16).1707 */1708 buf->ccontext.DataLength = cpu_to_le32(56);1709 buf->ccontext.NameOffset = cpu_to_le16(offsetof1710 (struct create_posix_rsp, Name));1711 buf->ccontext.NameLength = cpu_to_le16(POSIX_CTXT_DATA_LEN);1712 /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */1713 buf->Name[0] = 0x93;1714 buf->Name[1] = 0xAD;1715 buf->Name[2] = 0x25;1716 buf->Name[3] = 0x50;1717 buf->Name[4] = 0x9C;1718 buf->Name[5] = 0xB4;1719 buf->Name[6] = 0x11;1720 buf->Name[7] = 0xE7;1721 buf->Name[8] = 0xB4;1722 buf->Name[9] = 0x23;1723 buf->Name[10] = 0x83;1724 buf->Name[11] = 0xDE;1725 buf->Name[12] = 0x96;1726 buf->Name[13] = 0x8B;1727 buf->Name[14] = 0xCD;1728 buf->Name[15] = 0x7C;1729 1730 buf->nlink = cpu_to_le32(inode->i_nlink);1731 buf->reparse_tag = cpu_to_le32(fp->volatile_id);1732 buf->mode = cpu_to_le32(inode->i_mode & 0777);1733 /*1734 * SidBuffer(44) contain two sids(Domain sid(28), UNIX group sid(16)).1735 * Domain sid(28) = revision(1) + num_subauth(1) + authority(6) +1736 * sub_auth(4 * 4(num_subauth)) + RID(4).1737 * UNIX group id(16) = revision(1) + num_subauth(1) + authority(6) +1738 * sub_auth(4 * 1(num_subauth)) + RID(4).1739 */1740 id_to_sid(from_kuid_munged(&init_user_ns, vfsuid_into_kuid(vfsuid)),1741 SIDOWNER, (struct smb_sid *)&buf->SidBuffer[0]);1742 id_to_sid(from_kgid_munged(&init_user_ns, vfsgid_into_kgid(vfsgid)),1743 SIDUNIX_GROUP, (struct smb_sid *)&buf->SidBuffer[28]);1744}1745 1746/*1747 * Find lease object(opinfo) for given lease key/fid from lease1748 * break/file close path.1749 */1750/**1751 * lookup_lease_in_table() - find a matching lease info object1752 * @conn: connection instance1753 * @lease_key: lease key to be searched for1754 *1755 * Return: opinfo if found matching opinfo, otherwise NULL1756 */1757struct oplock_info *lookup_lease_in_table(struct ksmbd_conn *conn,1758 char *lease_key)1759{1760 struct oplock_info *opinfo = NULL, *ret_op = NULL;1761 struct lease_table *lt;1762 int ret;1763 1764 read_lock(&lease_list_lock);1765 list_for_each_entry(lt, &lease_table_list, l_entry) {1766 if (!memcmp(lt->client_guid, conn->ClientGUID,1767 SMB2_CLIENT_GUID_SIZE))1768 goto found;1769 }1770 1771 read_unlock(&lease_list_lock);1772 return NULL;1773 1774found:1775 rcu_read_lock();1776 list_for_each_entry_rcu(opinfo, <->lease_list, lease_entry) {1777 if (!atomic_inc_not_zero(&opinfo->refcount))1778 continue;1779 rcu_read_unlock();1780 if (!opinfo->op_state || opinfo->op_state == OPLOCK_CLOSING)1781 goto op_next;1782 if (!(opinfo->o_lease->state &1783 (SMB2_LEASE_HANDLE_CACHING_LE |1784 SMB2_LEASE_WRITE_CACHING_LE)))1785 goto op_next;1786 ret = compare_guid_key(opinfo, conn->ClientGUID,1787 lease_key);1788 if (ret) {1789 ksmbd_debug(OPLOCK, "found opinfo\n");1790 ret_op = opinfo;1791 goto out;1792 }1793op_next:1794 opinfo_put(opinfo);1795 rcu_read_lock();1796 }1797 rcu_read_unlock();1798 1799out:1800 read_unlock(&lease_list_lock);1801 return ret_op;1802}1803 1804int smb2_check_durable_oplock(struct ksmbd_conn *conn,1805 struct ksmbd_share_config *share,1806 struct ksmbd_file *fp,1807 struct lease_ctx_info *lctx,1808 char *name)1809{1810 struct oplock_info *opinfo = opinfo_get(fp);1811 int ret = 0;1812 1813 if (!opinfo)1814 return 0;1815 1816 if (opinfo->is_lease == false) {1817 if (lctx) {1818 pr_err("create context include lease\n");1819 ret = -EBADF;1820 goto out;1821 }1822 1823 if (opinfo->level != SMB2_OPLOCK_LEVEL_BATCH) {1824 pr_err("oplock level is not equal to SMB2_OPLOCK_LEVEL_BATCH\n");1825 ret = -EBADF;1826 }1827 1828 goto out;1829 }1830 1831 if (memcmp(conn->ClientGUID, fp->client_guid,1832 SMB2_CLIENT_GUID_SIZE)) {1833 ksmbd_debug(SMB, "Client guid of fp is not equal to the one of connection\n");1834 ret = -EBADF;1835 goto out;1836 }1837 1838 if (!lctx) {1839 ksmbd_debug(SMB, "create context does not include lease\n");1840 ret = -EBADF;1841 goto out;1842 }1843 1844 if (memcmp(opinfo->o_lease->lease_key, lctx->lease_key,1845 SMB2_LEASE_KEY_SIZE)) {1846 ksmbd_debug(SMB,1847 "lease key of fp does not match lease key in create context\n");1848 ret = -EBADF;1849 goto out;1850 }1851 1852 if (!(opinfo->o_lease->state & SMB2_LEASE_HANDLE_CACHING_LE)) {1853 ksmbd_debug(SMB, "lease state does not contain SMB2_LEASE_HANDLE_CACHING\n");1854 ret = -EBADF;1855 goto out;1856 }1857 1858 if (opinfo->o_lease->version != lctx->version) {1859 ksmbd_debug(SMB,1860 "lease version of fp does not match the one in create context\n");1861 ret = -EBADF;1862 goto out;1863 }1864 1865 if (!ksmbd_inode_pending_delete(fp))1866 ret = ksmbd_validate_name_reconnect(share, fp, name);1867out:1868 opinfo_put(opinfo);1869 return ret;1870}1871