@@ -159,7 +159,8 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
159159 opinfo = list_first_or_null_rcu (& ci -> m_op_list , struct oplock_info ,
160160 op_entry );
161161 if (opinfo ) {
162- if (!atomic_inc_not_zero (& opinfo -> refcount ))
162+ if (opinfo -> conn == NULL ||
163+ !atomic_inc_not_zero (& opinfo -> refcount ))
163164 opinfo = NULL ;
164165 else {
165166 atomic_inc (& opinfo -> conn -> r_count );
@@ -527,7 +528,7 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
527528 */
528529 read_lock (& ci -> m_lock );
529530 list_for_each_entry (opinfo , & ci -> m_op_list , op_entry ) {
530- if (!opinfo -> is_lease )
531+ if (!opinfo -> is_lease || ! opinfo -> conn )
531532 continue ;
532533 read_unlock (& ci -> m_lock );
533534 lease = opinfo -> o_lease ;
@@ -641,7 +642,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
641642 struct smb2_hdr * rsp_hdr ;
642643 struct ksmbd_file * fp ;
643644
644- fp = ksmbd_lookup_durable_fd (br_info -> fid );
645+ fp = ksmbd_lookup_global_fd (br_info -> fid );
645646 if (!fp )
646647 goto out ;
647648
@@ -1106,7 +1107,7 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
11061107
11071108 read_lock (& p_ci -> m_lock );
11081109 list_for_each_entry (opinfo , & p_ci -> m_op_list , op_entry ) {
1109- if (!opinfo -> is_lease )
1110+ if (opinfo -> conn == NULL || !opinfo -> is_lease )
11101111 continue ;
11111112
11121113 if (opinfo -> o_lease -> state != SMB2_OPLOCK_LEVEL_NONE &&
@@ -1142,7 +1143,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
11421143 opinfo = rcu_dereference (fp -> f_opinfo );
11431144 rcu_read_unlock ();
11441145
1145- if (!opinfo -> is_lease || opinfo -> o_lease -> version != 2 )
1146+ if (!opinfo || ! opinfo -> is_lease || opinfo -> o_lease -> version != 2 )
11461147 return ;
11471148
11481149 p_ci = ksmbd_inode_lookup_lock (fp -> filp -> f_path .dentry -> d_parent );
@@ -1151,7 +1152,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
11511152
11521153 read_lock (& p_ci -> m_lock );
11531154 list_for_each_entry (opinfo , & p_ci -> m_op_list , op_entry ) {
1154- if (!opinfo -> is_lease )
1155+ if (opinfo -> conn == NULL || !opinfo -> is_lease )
11551156 continue ;
11561157
11571158 if (opinfo -> o_lease -> state != SMB2_OPLOCK_LEVEL_NONE ) {
@@ -1361,6 +1362,9 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
13611362
13621363 rcu_read_lock ();
13631364 list_for_each_entry_rcu (brk_op , & ci -> m_op_list , op_entry ) {
1365+ if (brk_op -> conn == NULL )
1366+ continue ;
1367+
13641368 if (!atomic_inc_not_zero (& brk_op -> refcount ))
13651369 continue ;
13661370
@@ -1496,11 +1500,10 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
14961500/**
14971501 * parse_lease_state() - parse lease context containted in file open request
14981502 * @open_req: buffer containing smb2 file open(create) request
1499- * @is_dir: whether leasing file is directory
15001503 *
15011504 * Return: oplock state, -ENOENT if create lease context not found
15021505 */
1503- struct lease_ctx_info * parse_lease_state (void * open_req , bool is_dir )
1506+ struct lease_ctx_info * parse_lease_state (void * open_req )
15041507{
15051508 struct create_context * cc ;
15061509 struct smb2_create_req * req = (struct smb2_create_req * )open_req ;
@@ -1518,12 +1521,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir)
15181521 struct create_lease_v2 * lc = (struct create_lease_v2 * )cc ;
15191522
15201523 memcpy (lreq -> lease_key , lc -> lcontext .LeaseKey , SMB2_LEASE_KEY_SIZE );
1521- if (is_dir ) {
1522- lreq -> req_state = lc -> lcontext .LeaseState &
1523- ~SMB2_LEASE_WRITE_CACHING_LE ;
1524- lreq -> is_dir = true;
1525- } else
1526- lreq -> req_state = lc -> lcontext .LeaseState ;
1524+ lreq -> req_state = lc -> lcontext .LeaseState ;
15271525 lreq -> flags = lc -> lcontext .LeaseFlags ;
15281526 lreq -> epoch = lc -> lcontext .Epoch ;
15291527 lreq -> duration = lc -> lcontext .LeaseDuration ;
@@ -1646,6 +1644,8 @@ void create_durable_v2_rsp_buf(char *cc, struct ksmbd_file *fp)
16461644 buf -> Name [3 ] = 'Q' ;
16471645
16481646 buf -> Timeout = cpu_to_le32 (fp -> durable_timeout );
1647+ if (fp -> is_persistent )
1648+ buf -> Flags = cpu_to_le32 (SMB2_DHANDLE_FLAG_PERSISTENT );
16491649}
16501650
16511651/**
@@ -1813,3 +1813,71 @@ struct oplock_info *lookup_lease_in_table(struct ksmbd_conn *conn,
18131813 read_unlock (& lease_list_lock );
18141814 return ret_op ;
18151815}
1816+
1817+ int smb2_check_durable_oplock (struct ksmbd_conn * conn ,
1818+ struct ksmbd_share_config * share ,
1819+ struct ksmbd_file * fp ,
1820+ struct lease_ctx_info * lctx ,
1821+ char * name )
1822+ {
1823+ struct oplock_info * opinfo = opinfo_get (fp );
1824+ int ret = 0 ;
1825+
1826+ if (!opinfo )
1827+ return 0 ;
1828+
1829+ if (opinfo -> is_lease == false) {
1830+ if (lctx ) {
1831+ pr_err ("create context include lease\n" );
1832+ ret = - EBADF ;
1833+ goto out ;
1834+ }
1835+
1836+ if (opinfo -> level != SMB2_OPLOCK_LEVEL_BATCH ) {
1837+ pr_err ("oplock level is not equal to SMB2_OPLOCK_LEVEL_BATCH\n" );
1838+ ret = - EBADF ;
1839+ }
1840+
1841+ goto out ;
1842+ }
1843+
1844+ if (memcmp (conn -> ClientGUID , fp -> client_guid ,
1845+ SMB2_CLIENT_GUID_SIZE )) {
1846+ ksmbd_debug (SMB , "Client guid of fp is not equal to the one of connection\n" );
1847+ ret = - EBADF ;
1848+ goto out ;
1849+ }
1850+
1851+ if (!lctx ) {
1852+ ksmbd_debug (SMB , "create context does not include lease\n" );
1853+ ret = - EBADF ;
1854+ goto out ;
1855+ }
1856+
1857+ if (memcmp (opinfo -> o_lease -> lease_key , lctx -> lease_key ,
1858+ SMB2_LEASE_KEY_SIZE )) {
1859+ ksmbd_debug (SMB ,
1860+ "lease key of fp does not match lease key in create context\n" );
1861+ ret = - EBADF ;
1862+ goto out ;
1863+ }
1864+
1865+ if (!(opinfo -> o_lease -> state & SMB2_LEASE_HANDLE_CACHING_LE )) {
1866+ ksmbd_debug (SMB , "lease state does not contain SMB2_LEASE_HANDLE_CACHING\n" );
1867+ ret = - EBADF ;
1868+ goto out ;
1869+ }
1870+
1871+ if (opinfo -> o_lease -> version != lctx -> version ) {
1872+ ksmbd_debug (SMB ,
1873+ "lease version of fp does not match the one in create context\n" );
1874+ ret = - EBADF ;
1875+ goto out ;
1876+ }
1877+
1878+ if (!ksmbd_inode_pending_delete (fp ))
1879+ ret = ksmbd_validate_name_reconnect (share , fp , name );
1880+ out :
1881+ opinfo_put (opinfo );
1882+ return ret ;
1883+ }
0 commit comments