Amir Goldstein <amir73il@xxxxxxxxx> writes: > On Fri, Oct 21, 2022 at 11:22 AM Amir Goldstein <amir73il@xxxxxxxxx> wrote: > ... >> > +/* >> > + * Objects may need some additional actions to be taken when the last reference >> > + * is dropped. Define flags to indicate which actions are necessary. >> > + */ >> > +#define FSNOTIFY_OBJ_FLAG_NEED_IPUT 0x01 >> > +#define FSNOTIFY_OBJ_FLAG_UPDATE_CHILDREN 0x02 >> >> with changed_flags argument, you do not need these, you can use >> the existing CONN_FLAGS. >> >> It is a bit ugly that the direction of the change is not expressed >> in changed_flags, but for the current code, it is not needed, because >> update_children does care about the direction of the change and >> the direction of change to HAS_IREF is expressed by the inode >> object return value. >> > > Oh that is a lie... > > return value can be non NULL because of an added mark > that wants iref and also wants to watch children, but the > only practical consequence of this is that you can only > do the WARN_ON for the else case of update_children > in fsnotify_recalc_mask(). > > I still think it is a win for code simplicity as I detailed > in my comments. > >> Maybe try it out in v3 to see how it works. >> >> Unless Jan has an idea that will be easier to read and maintain... >> > > Maybe fsnotify_update_inode_conn_flags() should return "update_flags" > and not "changed_flags", because actually the WATCHING_CHILDREN > flag is not changed by the helper itself. Yeah, this is the way I'd like to go. The approach of "orig_flags ^ new_flags" doesn't work since we're not changing the WATCHING_CHILDREN flag. At the end of the day, I do believe that it's equivalent to what I had originally, except that we'd use FSNOTIFY_CONN_FLAG_* rather than my new FSNOTIFY_OBJ_FLAG_*, which works for me, the new constants are a bit of clutter. > Then, HAS_IREF is not returned when helper did get_iref() and changed > HAS_IREF itself and then the comment that says: > /* Unpin inode after detach of last mark that wanted iref */ > will be even clearer: > > if (want_iref) { > /* Pin inode if any mark wants inode refcount held */ > fsnotify_get_inode_ref(fsnotify_conn_inode(conn)); > conn->flags |= FSNOTIFY_CONN_FLAG_HAS_IREF; > } else { > /* Unpin inode after detach of last mark that wanted iref */ > ret = inode; > update_flags |= FSNOTIFY_CONN_FLAG_HAS_IREF; Is it possible that once the spinlock is dropped, another fsnotify_recalc_mask() finds that FSNOTIFY_CONN_FLAG_HAS_IREF is still set, and so it also sets FSNOTIFY_CONN_FLAG_HAS_IREF, causing two threads to both do an iput? It may not be possible due to the current use of the functions, but I guess it would be safer to clear the connector flag here under the spinlock, and set the *update_flags accordingly so that only one thread performs the iput(). Stephen > } > > Thanks, > Amir.