On Thu, Sep 28, 2017 at 5:12 PM, Mimi Zohar <zohar@xxxxxxxxxxxxxxxxxx> wrote: > > Originally IMA did define it's own lock, prior to IMA-appraisal. IMA- > appraisal introduced writing the file hash as an xattr, which required > taking the i_mutex. process_measurement() and ima_file_free() took > the iint->mutex first and then the i_mutex, while setxattr, chmod and > chown took the locks in reverse order. To resolve the potential > deadlock, the iint->mutex was eliminated. Umm. You already have an explicit invalidation model, where you invalidate after a write has occurred. But the locking of the generation count (or "invalidation status" or whatever) can - and should be - entirely independent of the locking of the actual appraisal. So make the appraisal itself use a semaphore ("only one appraisal at a time"). But use a separate lock for the generation count. So then appraisal is: - get appraisal semaphore - get generation count lock read generation count - drop generation count lock - do the actual appraisal - drop appraisal semaphore Note that you now have a tuple of "generation count, appraisal" that you have *not* saved off yet, but it's your stable thing. Now you can write the xattr: - get exclusive inode lock (for xattr) - get generation count lock - if the appraisal generation does not match, do NOT write the appraisal you just calculated, since it's pointless: it's already stale. - otherwise write the appraisal and generation count to the xattr - drop generation count lock - release exclusive inode lock and then for anything that does setxattr or chmod or whatever, just use that generation count lock to invalidate the appraisal. You don't need to actual appraisal lock for that. So now the appraisal lock is always the outermost one, and the generation count lock is always the innermost. Anyway, I haven't looked at the details of what IMA does, but something like the above really sounds like it should work and seems pretty straightforward. No? Linus