free_opinfo(opinfo);
}
+static bool ksmbd_inode_has_lease(struct ksmbd_inode *ci)
+{
+ struct oplock_info *opinfo = opinfo_get_list(ci);
+ bool is_lease;
+
+ if (!opinfo)
+ return false;
+ is_lease = opinfo->is_lease;
+ opinfo_put(opinfo);
+ return is_lease;
+}
+
static void opinfo_add(struct oplock_info *opinfo, struct ksmbd_file *fp)
{
struct ksmbd_inode *ci = fp->f_ci;
if (!opinfo_count(fp))
goto set_lev;
- /* grant none-oplock if second open is trunc */
- if (fp->attrib_only && fp->cdoption != FILE_OVERWRITE_IF_LE &&
+ /*
+ * A stat open that only requests metadata access must not break the
+ * existing caching state. READ_CONTROL (reading the security
+ * descriptor) does not conflict with a lease, but it does conflict
+ * with an oplock, so only treat a read-control-only open as a stat
+ * open when the existing holder is a lease.
+ */
+ if (fp->cdoption != FILE_OVERWRITE_IF_LE &&
fp->cdoption != FILE_OVERWRITE_LE &&
- fp->cdoption != FILE_SUPERSEDE_LE) {
+ fp->cdoption != FILE_SUPERSEDE_LE &&
+ (fp->attrib_only ||
+ (!(fp->daccess & ~(FILE_READ_ATTRIBUTES_LE |
+ FILE_WRITE_ATTRIBUTES_LE |
+ FILE_SYNCHRONIZE_LE |
+ FILE_READ_CONTROL_LE)) &&
+ ksmbd_inode_has_lease(ci)))) {
req_op_level = SMB2_OPLOCK_LEVEL_NONE;
goto set_lev;
}