@@ -102,9 +102,10 @@ static int alloc_lease(struct oplock_info *opinfo, struct lease_ctx_info *lctx)
102102 lease -> new_state = 0 ;
103103 lease -> flags = lctx -> flags ;
104104 lease -> duration = lctx -> duration ;
105+ lease -> is_dir = lctx -> is_dir ;
105106 memcpy (lease -> parent_lease_key , lctx -> parent_lease_key , SMB2_LEASE_KEY_SIZE );
106107 lease -> version = lctx -> version ;
107- lease -> epoch = 0 ;
108+ lease -> epoch = le16_to_cpu ( lctx -> epoch ) ;
108109 INIT_LIST_HEAD (& opinfo -> lease_entry );
109110 opinfo -> o_lease = lease ;
110111
@@ -395,8 +396,8 @@ void close_id_del_oplock(struct ksmbd_file *fp)
395396{
396397 struct oplock_info * opinfo ;
397398
398- if (S_ISDIR ( file_inode ( fp -> filp ) -> i_mode ) )
399- return ;
399+ if (fp -> reserve_lease_break )
400+ smb_lazy_parent_lease_break_close ( fp ) ;
400401
401402 opinfo = opinfo_get (fp );
402403 if (!opinfo )
@@ -543,12 +544,13 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
543544 /* upgrading lease */
544545 if ((atomic_read (& ci -> op_count ) +
545546 atomic_read (& ci -> sop_count )) == 1 ) {
546- if (lease -> state ==
547- (lctx -> req_state & lease -> state )) {
547+ if (lease -> state != SMB2_LEASE_NONE_LE &&
548+ lease -> state == (lctx -> req_state & lease -> state )) {
548549 lease -> state |= lctx -> req_state ;
549550 if (lctx -> req_state &
550551 SMB2_LEASE_WRITE_CACHING_LE )
551552 lease_read_to_write (opinfo );
553+
552554 }
553555 } else if ((atomic_read (& ci -> op_count ) +
554556 atomic_read (& ci -> sop_count )) > 1 ) {
@@ -900,7 +902,8 @@ static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level)
900902 lease -> new_state =
901903 SMB2_LEASE_READ_CACHING_LE ;
902904 } else {
903- if (lease -> state & SMB2_LEASE_HANDLE_CACHING_LE )
905+ if (lease -> state & SMB2_LEASE_HANDLE_CACHING_LE &&
906+ !lease -> is_dir )
904907 lease -> new_state =
905908 SMB2_LEASE_READ_CACHING_LE ;
906909 else
@@ -1032,6 +1035,7 @@ static void copy_lease(struct oplock_info *op1, struct oplock_info *op2)
10321035 SMB2_LEASE_KEY_SIZE );
10331036 lease2 -> duration = lease1 -> duration ;
10341037 lease2 -> flags = lease1 -> flags ;
1038+ lease2 -> epoch = lease1 -> epoch ++ ;
10351039}
10361040
10371041static int add_lease_global_list (struct oplock_info * opinfo )
@@ -1081,6 +1085,89 @@ static void set_oplock_level(struct oplock_info *opinfo, int level,
10811085 }
10821086}
10831087
1088+ void smb_send_parent_lease_break_noti (struct ksmbd_file * fp ,
1089+ struct lease_ctx_info * lctx )
1090+ {
1091+ struct oplock_info * opinfo ;
1092+ struct ksmbd_inode * p_ci = NULL ;
1093+
1094+ if (lctx -> version != 2 )
1095+ return ;
1096+
1097+ p_ci = ksmbd_inode_lookup_lock (fp -> filp -> f_path .dentry -> d_parent );
1098+ if (!p_ci )
1099+ return ;
1100+
1101+ read_lock (& p_ci -> m_lock );
1102+ list_for_each_entry (opinfo , & p_ci -> m_op_list , op_entry ) {
1103+ if (!opinfo -> is_lease )
1104+ continue ;
1105+
1106+ if (opinfo -> o_lease -> state != SMB2_OPLOCK_LEVEL_NONE &&
1107+ (!(lctx -> flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE ) ||
1108+ !compare_guid_key (opinfo , fp -> conn -> ClientGUID ,
1109+ lctx -> parent_lease_key ))) {
1110+ if (!atomic_inc_not_zero (& opinfo -> refcount ))
1111+ continue ;
1112+
1113+ atomic_inc (& opinfo -> conn -> r_count );
1114+ if (ksmbd_conn_releasing (opinfo -> conn )) {
1115+ atomic_dec (& opinfo -> conn -> r_count );
1116+ continue ;
1117+ }
1118+
1119+ read_unlock (& p_ci -> m_lock );
1120+ oplock_break (opinfo , SMB2_OPLOCK_LEVEL_NONE );
1121+ opinfo_conn_put (opinfo );
1122+ read_lock (& p_ci -> m_lock );
1123+ }
1124+ }
1125+ read_unlock (& p_ci -> m_lock );
1126+
1127+ ksmbd_inode_put (p_ci );
1128+ }
1129+
1130+ void smb_lazy_parent_lease_break_close (struct ksmbd_file * fp )
1131+ {
1132+ struct oplock_info * opinfo ;
1133+ struct ksmbd_inode * p_ci = NULL ;
1134+
1135+ rcu_read_lock ();
1136+ opinfo = rcu_dereference (fp -> f_opinfo );
1137+ rcu_read_unlock ();
1138+
1139+ if (!opinfo -> is_lease || opinfo -> o_lease -> version != 2 )
1140+ return ;
1141+
1142+ p_ci = ksmbd_inode_lookup_lock (fp -> filp -> f_path .dentry -> d_parent );
1143+ if (!p_ci )
1144+ return ;
1145+
1146+ read_lock (& p_ci -> m_lock );
1147+ list_for_each_entry (opinfo , & p_ci -> m_op_list , op_entry ) {
1148+ if (!opinfo -> is_lease )
1149+ continue ;
1150+
1151+ if (opinfo -> o_lease -> state != SMB2_OPLOCK_LEVEL_NONE ) {
1152+ if (!atomic_inc_not_zero (& opinfo -> refcount ))
1153+ continue ;
1154+
1155+ atomic_inc (& opinfo -> conn -> r_count );
1156+ if (ksmbd_conn_releasing (opinfo -> conn )) {
1157+ atomic_dec (& opinfo -> conn -> r_count );
1158+ continue ;
1159+ }
1160+ read_unlock (& p_ci -> m_lock );
1161+ oplock_break (opinfo , SMB2_OPLOCK_LEVEL_NONE );
1162+ opinfo_conn_put (opinfo );
1163+ read_lock (& p_ci -> m_lock );
1164+ }
1165+ }
1166+ read_unlock (& p_ci -> m_lock );
1167+
1168+ ksmbd_inode_put (p_ci );
1169+ }
1170+
10841171/**
10851172 * smb_grant_oplock() - handle oplock/lease request on file open
10861173 * @work: smb work
@@ -1104,10 +1191,6 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
11041191 bool prev_op_has_lease ;
11051192 __le32 prev_op_state = 0 ;
11061193
1107- /* not support directory lease */
1108- if (S_ISDIR (file_inode (fp -> filp )-> i_mode ))
1109- return 0 ;
1110-
11111194 opinfo = alloc_opinfo (work , pid , tid );
11121195 if (!opinfo )
11131196 return - ENOMEM ;
@@ -1364,6 +1447,7 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
13641447 memcpy (buf -> lcontext .LeaseKey , lease -> lease_key ,
13651448 SMB2_LEASE_KEY_SIZE );
13661449 buf -> lcontext .LeaseFlags = lease -> flags ;
1450+ buf -> lcontext .Epoch = cpu_to_le16 (++ lease -> epoch );
13671451 buf -> lcontext .LeaseState = lease -> state ;
13681452 memcpy (buf -> lcontext .ParentLeaseKey , lease -> parent_lease_key ,
13691453 SMB2_LEASE_KEY_SIZE );
@@ -1400,10 +1484,11 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
14001484/**
14011485 * parse_lease_state() - parse lease context containted in file open request
14021486 * @open_req: buffer containing smb2 file open(create) request
1487+ * @is_dir: whether leasing file is directory
14031488 *
14041489 * Return: oplock state, -ENOENT if create lease context not found
14051490 */
1406- struct lease_ctx_info * parse_lease_state (void * open_req )
1491+ struct lease_ctx_info * parse_lease_state (void * open_req , bool is_dir )
14071492{
14081493 struct create_context * cc ;
14091494 struct smb2_create_req * req = (struct smb2_create_req * )open_req ;
@@ -1421,8 +1506,14 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
14211506 struct create_lease_v2 * lc = (struct create_lease_v2 * )cc ;
14221507
14231508 memcpy (lreq -> lease_key , lc -> lcontext .LeaseKey , SMB2_LEASE_KEY_SIZE );
1424- lreq -> req_state = lc -> lcontext .LeaseState ;
1509+ if (is_dir ) {
1510+ lreq -> req_state = lc -> lcontext .LeaseState &
1511+ ~SMB2_LEASE_WRITE_CACHING_LE ;
1512+ lreq -> is_dir = true;
1513+ } else
1514+ lreq -> req_state = lc -> lcontext .LeaseState ;
14251515 lreq -> flags = lc -> lcontext .LeaseFlags ;
1516+ lreq -> epoch = lc -> lcontext .Epoch ;
14261517 lreq -> duration = lc -> lcontext .LeaseDuration ;
14271518 memcpy (lreq -> parent_lease_key , lc -> lcontext .ParentLeaseKey ,
14281519 SMB2_LEASE_KEY_SIZE );
0 commit comments