On Wed, Aug 16, 2023 at 10:25 AM Sarah Walker <sarah.walker@xxxxxxxxxx> wrote: > Implement job submission ioctl. Job scheduling is implemented using > drm_sched. [...] > +/** > + * pvr_job_data_fini() - Cleanup all allocs used to set up job submission. > + * @job_data: Job data array. > + * @job_count: Number of members of @job_data. > + */ > +static void > +pvr_job_data_fini(struct pvr_job_data *job_data, u32 job_count) > +{ > + for (u32 i = 0; i < job_count; i++) { > + pvr_job_put(job_data[i].job); > + kvfree(job_data[i].sync_ops); > + } > +} > + > +/** > + * pvr_job_data_init() - Init an array of created jobs, associating them with > + * the appropriate sync_ops args, which will be copied in. > + * @pvr_dev: Target PowerVR device. > + * @pvr_file: Pointer to PowerVR file structure. > + * @job_args: Job args array copied from user. > + * @job_count: Number of members of @job_args. > + * @job_data_out: Job data array. > + */ > +static int pvr_job_data_init(struct pvr_device *pvr_dev, > + struct pvr_file *pvr_file, > + struct drm_pvr_job *job_args, > + u32 *job_count, > + struct pvr_job_data *job_data_out) > +{ > + int err = 0, i = 0; > + > + for (; i < *job_count; i++) { > + job_data_out[i].job = > + create_job(pvr_dev, pvr_file, &job_args[i]); > + err = PTR_ERR_OR_ZERO(job_data_out[i].job); > + > + if (err) { > + *job_count = i; > + job_data_out[i].job = NULL; > + goto err_cleanup; I think this bailout looks fine... > + } > + > + err = PVR_UOBJ_GET_ARRAY(job_data_out[i].sync_ops, > + &job_args[i].sync_ops); > + if (err) { > + *job_count = i; > + goto err_cleanup; ... but this bailout looks like it has an off-by-one. We have initialized the job pointers up to (inclusive) index i... > + } > + > + job_data_out[i].sync_op_count = job_args[i].sync_ops.count; > + } > + > + return 0; > + > +err_cleanup: > + pvr_job_data_fini(job_data_out, i); ... but then we pass i to pvr_job_data_fini() as the exclusive limit of job indices to free? I think this will leave a leaked job around. > + > + return err; > +}