On Fri, May 25, 2018 at 01:06:29AM +0100, David Howells wrote: > +/** > + * sget_fc - Find or create a superblock > + * @fc: Filesystem context. > + * @test: Comparison callback > + * @set: Setup callback > + * > + * Find or create a superblock using the parameters stored in the filesystem > + * context and the two callback functions. > + * > + * If an extant superblock is matched, then that will be returned with an > + * elevated reference count that the caller must transfer or discard. > + * > + * If no match is made, a new superblock will be allocated and basic > + * initialisation will be performed (s_type, s_fs_info and s_id will be set and > + * the set() callback will be invoked), the superblock will be published and it > + * will be returned in a partially constructed state with SB_BORN and SB_ACTIVE > + * as yet unset. > + */ > +struct super_block *sget_fc(struct fs_context *fc, > + int (*test)(struct super_block *, struct fs_context *), > + int (*set)(struct super_block *, struct fs_context *)) > +{ > + struct super_block *s = NULL; > + struct super_block *old; > + int err; > + > + if (!(fc->sb_flags & SB_KERNMOUNT) && > + fc->purpose != FS_CONTEXT_FOR_SUBMOUNT) { > + /* Don't allow mounting unless the caller has CAP_SYS_ADMIN > + * over the namespace. > + */ > + if (!(fc->fs_type->fs_flags & FS_USERNS_MOUNT) && > + !capable(CAP_SYS_ADMIN)) > + return ERR_PTR(-EPERM); > + else if (!ns_capable(fc->user_ns, CAP_SYS_ADMIN)) > + return ERR_PTR(-EPERM); > + } > + > +retry: > + spin_lock(&sb_lock); > + if (test) { > + hlist_for_each_entry(old, &fc->fs_type->fs_supers, s_instances) { > + if (!test(old, fc)) > + continue; > + if (fc->user_ns != old->s_user_ns) { > + spin_unlock(&sb_lock); > + if (s) { > + up_write(&s->s_umount); > + destroy_unused_super(s); > + } ->s_umount is released once here and again in destroy_unused_super(). > + return ERR_PTR(-EBUSY); > + } > + if (!grab_super(old)) > + goto retry; > + if (s) { > + up_write(&s->s_umount); > + destroy_unused_super(s); Same bug here. > + up_write(&s->s_umount); > + destroy_unused_super(s); And here. - Eric