Re: [PATCH 10/10 v7] nfsd: Allows user un-mounting filesystem where nfsd exports base on

NeilBrown
2015-07-15T06:51:27Z

On Wed, 15 Jul 2015 05:57:56 +0100 Al Viro <viro@ZenIV.linux.org.uk>
wrote:

> On Wed, Jul 15, 2015 at 01:49:48PM +1000, NeilBrown wrote:
>
> > > In any case, you have two possibilities - explicit unexport triggering that
> > > dput(), etc. and umount(2) triggering the same. Whoever comes second gets
> > > to wait until it's done. So why not make the point where we commit to
> > > unexporting the sucker the place where we do pin_kill()? And have ->kill()
> > > of that thing prevent appearance of new entries, then wait for them to run
> > > down. Which is precisely the same thing you want to happen on umount...
> >
> > The "wait for them to run down" part is the sticking point. We don't
> > have any easy way to wait for there to be no more references, so I'd
> > really like to use the waiting that pin_kill() already does.
>
> > I want the ->kill function to just unhash the cache entry, and then
> > wait for pin_delete() to be called.
>
> pin_remove, presumably?

Presumably, yes.

>
> > The final 'put' on the cache entry calls dput on the dentry and then
> > pin_remove().
> >
> > The ->kill function can wait for that to happen by calling pin_kill().
>
> > I guess there is no real need for a return value from pin_remove().
> >
> > So
> > static void expkey_pin_kill(struct fs_pin *pin)
> > {
> > struct svc_expkey *key = container_of(pin, ....);
> >
> > cache_delete_entry(key->cd, &key->h);
>
>
> ... and another CPU drops the last reference, freeing the sucker.

*That's* why I wanted pin_remove to return something.

Why didn't you like that option again?

To recap:
pin_remove does:

tmp = pin->done;
pin->done = 1;
...
return tmp;

path_put_unpin() returns the return value of pin_remove()

expkey_put() does:
auth_domain_put(key->ek_client);
if (test some bits)
if (path_put_unpin() < 0)
/* pin_kill has taken over */
return
kfree_rcu(key, rcu_head);
}

and expkey_pin_kill() does:

cache_delete_entry(key->cd, &key->h);
pin_kill(&key->ek_pin);
kfee_rcu(key, rcu_head);
}

Thanks,
NeilBrown