// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2016 Namjae Jeon <[email protected]> * Copyright (C) 2018 Samsung Electronics Co., Ltd. */ #include <linux/moduleparam.h> #include "glob.h" #include "oplock.h" #include "smb_common.h" #include "smbstatus.h" #include "connection.h" #include "mgmt/user_session.h" #include "mgmt/share_config.h" #include "mgmt/tree_connect.h" static LIST_HEAD(lease_table_list); static DEFINE_RWLOCK(lease_list_lock); /** * alloc_opinfo() - allocate a new opinfo object for oplock info * @work: smb work * @id: fid of open file * @Tid: tree id of connection * * Return: allocated opinfo object on success, otherwise NULL */ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work, u64 id, __u16 Tid) { … } static void lease_add_list(struct oplock_info *opinfo) { … } static void lease_del_list(struct oplock_info *opinfo) { … } static void lb_add(struct lease_table *lb) { … } static int alloc_lease(struct oplock_info *opinfo, struct lease_ctx_info *lctx) { … } static void free_lease(struct oplock_info *opinfo) { … } static void free_opinfo(struct oplock_info *opinfo) { … } static inline void opinfo_free_rcu(struct rcu_head *rcu_head) { … } struct oplock_info *opinfo_get(struct ksmbd_file *fp) { … } static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci) { … } static void opinfo_conn_put(struct oplock_info *opinfo) { … } void opinfo_put(struct oplock_info *opinfo) { … } static void opinfo_add(struct oplock_info *opinfo) { … } static void opinfo_del(struct oplock_info *opinfo) { … } static unsigned long opinfo_count(struct ksmbd_file *fp) { … } static void opinfo_count_inc(struct ksmbd_file *fp) { … } static void opinfo_count_dec(struct ksmbd_file *fp) { … } /** * opinfo_write_to_read() - convert a write oplock to read oplock * @opinfo: current oplock info * * Return: 0 on success, otherwise -EINVAL */ int opinfo_write_to_read(struct oplock_info *opinfo) { … } /** * opinfo_read_handle_to_read() - convert a read/handle oplock to read oplock * @opinfo: current oplock info * * Return: 0 on success, otherwise -EINVAL */ int opinfo_read_handle_to_read(struct oplock_info *opinfo) { … } /** * opinfo_write_to_none() - convert a write oplock to none * @opinfo: current oplock info * * Return: 0 on success, otherwise -EINVAL */ int opinfo_write_to_none(struct oplock_info *opinfo) { … } /** * opinfo_read_to_none() - convert a write read to none * @opinfo: current oplock info * * Return: 0 on success, otherwise -EINVAL */ int opinfo_read_to_none(struct oplock_info *opinfo) { … } /** * lease_read_to_write() - upgrade lease state from read to write * @opinfo: current lease info * * Return: 0 on success, otherwise -EINVAL */ int lease_read_to_write(struct oplock_info *opinfo) { … } /** * lease_none_upgrade() - upgrade lease state from none * @opinfo: current lease info * @new_state: new lease state * * Return: 0 on success, otherwise -EINVAL */ static int lease_none_upgrade(struct oplock_info *opinfo, __le32 new_state) { … } /** * close_id_del_oplock() - release oplock object at file close time * @fp: ksmbd file pointer */ void close_id_del_oplock(struct ksmbd_file *fp) { … } /** * grant_write_oplock() - grant exclusive/batch oplock or write lease * @opinfo_new: new oplock info object * @req_oplock: request oplock * @lctx: lease context information * * Return: 0 */ static void grant_write_oplock(struct oplock_info *opinfo_new, int req_oplock, struct lease_ctx_info *lctx) { … } /** * grant_read_oplock() - grant level2 oplock or read lease * @opinfo_new: new oplock info object * @lctx: lease context information * * Return: 0 */ static void grant_read_oplock(struct oplock_info *opinfo_new, struct lease_ctx_info *lctx) { … } /** * grant_none_oplock() - grant none oplock or none lease * @opinfo_new: new oplock info object * @lctx: lease context information * * Return: 0 */ static void grant_none_oplock(struct oplock_info *opinfo_new, struct lease_ctx_info *lctx) { … } static inline int compare_guid_key(struct oplock_info *opinfo, const char *guid1, const char *key1) { … } /** * same_client_has_lease() - check whether current lease request is * from lease owner of file * @ci: master file pointer * @client_guid: Client GUID * @lctx: lease context information * * Return: oplock(lease) object on success, otherwise NULL */ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci, char *client_guid, struct lease_ctx_info *lctx) { … } static void wait_for_break_ack(struct oplock_info *opinfo) { … } static void wake_up_oplock_break(struct oplock_info *opinfo) { … } static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level) { … } /** * __smb2_oplock_break_noti() - send smb2 oplock break cmd from conn * to client * @wk: smb work object * * There are two ways this function can be called. 1- while file open we break * from exclusive/batch lock to levelII oplock and 2- while file write/truncate * we break from levelII oplock no oplock. * work->request_buf contains oplock_info. */ static void __smb2_oplock_break_noti(struct work_struct *wk) { … } /** * smb2_oplock_break_noti() - send smb2 exclusive/batch to level2 oplock * break command from server to client * @opinfo: oplock info object * * Return: 0 on success, otherwise error */ static int smb2_oplock_break_noti(struct oplock_info *opinfo) { … } /** * __smb2_lease_break_noti() - send lease break command from server * to client * @wk: smb work object */ static void __smb2_lease_break_noti(struct work_struct *wk) { … } /** * smb2_lease_break_noti() - break lease when a new client request * write lease * @opinfo: conains lease state information * * Return: 0 on success, otherwise error */ static int smb2_lease_break_noti(struct oplock_info *opinfo) { … } static void wait_lease_breaking(struct oplock_info *opinfo) { … } static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level) { … } void destroy_lease_table(struct ksmbd_conn *conn) { … } int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci, struct lease_ctx_info *lctx) { … } static void copy_lease(struct oplock_info *op1, struct oplock_info *op2) { … } static int add_lease_global_list(struct oplock_info *opinfo) { … } static void set_oplock_level(struct oplock_info *opinfo, int level, struct lease_ctx_info *lctx) { … } void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, struct lease_ctx_info *lctx) { … } void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp) { … } /** * smb_grant_oplock() - handle oplock/lease request on file open * @work: smb work * @req_op_level: oplock level * @pid: id of open file * @fp: ksmbd file pointer * @tid: Tree id of connection * @lctx: lease context information on file open * @share_ret: share mode * * Return: 0 on success, otherwise error */ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid, struct ksmbd_file *fp, __u16 tid, struct lease_ctx_info *lctx, int share_ret) { … } /** * smb_break_all_write_oplock() - break batch/exclusive oplock to level2 * @work: smb work * @fp: ksmbd file pointer * @is_trunc: truncate on open */ static void smb_break_all_write_oplock(struct ksmbd_work *work, struct ksmbd_file *fp, int is_trunc) { … } /** * smb_break_all_levII_oplock() - send level2 oplock or read lease break command * from server to client * @work: smb work * @fp: ksmbd file pointer * @is_trunc: truncate on open */ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp, int is_trunc) { … } /** * smb_break_all_oplock() - break both batch/exclusive and level2 oplock * @work: smb work * @fp: ksmbd file pointer */ void smb_break_all_oplock(struct ksmbd_work *work, struct ksmbd_file *fp) { … } /** * smb2_map_lease_to_oplock() - map lease state to corresponding oplock type * @lease_state: lease type * * Return: 0 if no mapping, otherwise corresponding oplock type */ __u8 smb2_map_lease_to_oplock(__le32 lease_state) { … } /** * create_lease_buf() - create lease context for open cmd response * @rbuf: buffer to create lease context response * @lease: buffer to stored parsed lease state information */ void create_lease_buf(u8 *rbuf, struct lease *lease) { … } /** * parse_lease_state() - parse lease context containted in file open request * @open_req: buffer containing smb2 file open(create) request * * Return: oplock state, -ENOENT if create lease context not found */ struct lease_ctx_info *parse_lease_state(void *open_req) { … } /** * smb2_find_context_vals() - find a particular context info in open request * @open_req: buffer containing smb2 file open(create) request * @tag: context name to search for * @tag_len: the length of tag * * Return: pointer to requested context, NULL if @str context not found * or error pointer if name length is invalid. */ struct create_context *smb2_find_context_vals(void *open_req, const char *tag, int tag_len) { … } /** * create_durable_rsp_buf() - create durable handle context * @cc: buffer to create durable context response */ void create_durable_rsp_buf(char *cc) { … } /** * create_durable_v2_rsp_buf() - create durable handle v2 context * @cc: buffer to create durable context response * @fp: ksmbd file pointer */ void create_durable_v2_rsp_buf(char *cc, struct ksmbd_file *fp) { … } /** * create_mxac_rsp_buf() - create query maximal access context * @cc: buffer to create maximal access context response * @maximal_access: maximal access */ void create_mxac_rsp_buf(char *cc, int maximal_access) { … } void create_disk_id_rsp_buf(char *cc, __u64 file_id, __u64 vol_id) { … } /** * create_posix_rsp_buf() - create posix extension context * @cc: buffer to create posix on posix response * @fp: ksmbd file pointer */ void create_posix_rsp_buf(char *cc, struct ksmbd_file *fp) { … } /* * Find lease object(opinfo) for given lease key/fid from lease * break/file close path. */ /** * lookup_lease_in_table() - find a matching lease info object * @conn: connection instance * @lease_key: lease key to be searched for * * Return: opinfo if found matching opinfo, otherwise NULL */ struct oplock_info *lookup_lease_in_table(struct ksmbd_conn *conn, char *lease_key) { … } int smb2_check_durable_oplock(struct ksmbd_conn *conn, struct ksmbd_share_config *share, struct ksmbd_file *fp, struct lease_ctx_info *lctx, char *name) { … }