unsigned short int type;
bool persistent;
bool reconnected;
+ bool app_instance_id;
unsigned int timeout;
char *CreateGuid;
+ char AppInstanceId[SMB2_CREATE_GUID_SIZE];
};
static int parse_durable_handle_context(struct ksmbd_work *work,
return err;
}
+static int parse_app_instance_id(struct smb2_create_req *req,
+ struct durable_info *dh_info)
+{
+ struct create_context *context;
+ char *data;
+
+ context = smb2_find_context_vals(req, SMB2_CREATE_APP_INSTANCE_ID,
+ SMB2_CREATE_GUID_SIZE);
+ if (IS_ERR(context))
+ return PTR_ERR(context);
+ if (!context)
+ return 0;
+
+ if (le32_to_cpu(context->DataLength) < 20)
+ return -EINVAL;
+
+ data = (char *)context + le16_to_cpu(context->DataOffset);
+ if (data[0] != 20 || data[1])
+ return -EINVAL;
+
+ memcpy(dh_info->AppInstanceId, data + 4, SMB2_CREATE_GUID_SIZE);
+ dh_info->app_instance_id = true;
+ return 0;
+}
+
/**
* smb2_open() - handler for smb file open request
* @work: smb work containing request buffer
ksmbd_debug(SMB, "error parsing durable handle context\n");
goto err_out2;
}
+ rc = parse_app_instance_id(req, &dh_info);
+ if (rc)
+ goto err_out2;
if (dh_info.reconnected == true) {
rc = smb2_check_durable_oplock(conn, share, dh_info.fp,
goto reconnected_fp;
}
+
+ if (dh_info.type == DURABLE_REQ_V2 && dh_info.app_instance_id)
+ ksmbd_close_fd_app_instance_id(dh_info.AppInstanceId);
} else if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) {
lc = parse_lease_state(req);
if (IS_ERR(lc)) {
if (dh_info.type == DURABLE_REQ_V2) {
memcpy(fp->create_guid, dh_info.CreateGuid,
SMB2_CREATE_GUID_SIZE);
+ if (dh_info.app_instance_id)
+ memcpy(fp->app_instance_id,
+ dh_info.AppInstanceId,
+ SMB2_CREATE_GUID_SIZE);
if (dh_info.timeout)
fp->durable_timeout =
min_t(unsigned int, dh_info.timeout,
static atomic_long_t fd_limit;
static struct kmem_cache *filp_cache;
+static int ksmbd_mark_fp_closed(struct ksmbd_file *fp);
+
#define OPLOCK_NONE 0
#define OPLOCK_EXCLUSIVE 1
#define OPLOCK_BATCH 2
return ret;
}
+static struct ksmbd_file *ksmbd_lookup_fd_app_instance_id(char *app_instance_id)
+{
+ struct ksmbd_file *fp = NULL;
+ unsigned int id;
+
+ if (!memchr_inv(app_instance_id, 0, SMB2_CREATE_GUID_SIZE))
+ return NULL;
+
+ read_lock(&global_ft.lock);
+ idr_for_each_entry(global_ft.idr, fp, id) {
+ if (!memcmp(fp->app_instance_id, app_instance_id,
+ SMB2_CREATE_GUID_SIZE)) {
+ fp = ksmbd_fp_get(fp);
+ break;
+ }
+ }
+ read_unlock(&global_ft.lock);
+
+ return fp;
+}
+
+int ksmbd_close_fd_app_instance_id(char *app_instance_id)
+{
+ struct ksmbd_file_table *ft;
+ struct ksmbd_file *fp;
+ struct oplock_info *opinfo;
+ int n_to_drop = 0;
+
+ fp = ksmbd_lookup_fd_app_instance_id(app_instance_id);
+ if (!fp)
+ return 0;
+
+ opinfo = opinfo_get(fp);
+ if (!opinfo || !opinfo->sess)
+ goto out;
+
+ ft = &opinfo->sess->file_table;
+ write_lock(&ft->lock);
+ if (fp->f_state == FP_INITED) {
+ if (has_file_id(fp->volatile_id)) {
+ idr_remove(ft->idr, fp->volatile_id);
+ fp->volatile_id = KSMBD_NO_FID;
+ }
+ n_to_drop = ksmbd_mark_fp_closed(fp);
+ }
+ write_unlock(&ft->lock);
+ opinfo_put(opinfo);
+ opinfo = NULL;
+
+ if (!n_to_drop)
+ goto out;
+
+ down_write(&fp->f_ci->m_lock);
+ list_del_init(&fp->node);
+ up_write(&fp->f_ci->m_lock);
+
+ if (atomic_sub_and_test(n_to_drop, &fp->refcount)) {
+ if (fp->conn)
+ atomic_dec(&fp->conn->stats.open_files_count);
+ __ksmbd_close_fd(NULL, fp);
+ }
+ return 0;
+
+out:
+ if (opinfo)
+ opinfo_put(opinfo);
+ ksmbd_put_durable_fd(fp);
+ return 0;
+}
+
int ksmbd_invalidate_durable_fd(unsigned long long id)
{
struct ksmbd_file *fp;
void ksmbd_put_durable_fd(struct ksmbd_file *fp);
int ksmbd_invalidate_durable_fd(unsigned long long id);
bool ksmbd_has_other_active_fd(struct ksmbd_file *fp);
+int ksmbd_close_fd_app_instance_id(char *app_instance_id);
struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);