@@ -309,11 +309,17 @@ static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
static void svc_export_put(struct kref *ref)
{
struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
- path_put(&exp->ex_path);
+
+ if (exp->ex_pin.kill) {
+ dput(exp->ex_path.dentry);
+ pin_remove(&exp->ex_pin);
+ } else
+ path_put(&exp->ex_path);
+
auth_domain_put(exp->ex_client);
nfsd4_fslocs_free(&exp->ex_fslocs);
kfree(exp->ex_uuid);
- kfree(exp);
+ kfree_rcu(exp, rcu_head);
}
static void svc_export_request(struct cache_detail *cd,
@@ -699,6 +705,7 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
struct svc_export *new = container_of(cnew, struct svc_export, h);
struct svc_export *item = container_of(citem, struct svc_export, h);
+ init_fs_pin(&new->ex_pin, NULL);
kref_get(&item->ex_client->ref);
new->ex_client = item->ex_client;
new->ex_path = item->ex_path;
@@ -738,6 +745,24 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
}
}
+static void export_pin_kill(struct fs_pin *pin)
+{
+ struct svc_export *exp = container_of(pin, struct svc_export, ex_pin);
+ cache_force_expire(exp->cd, &exp->h);
+}
+
+static void export_update_negative(struct cache_head *cnew, struct cache_head *citem)
+{
+ struct svc_export *new = container_of(cnew, struct svc_export, h);
+
+ if (!test_bit(CACHE_NEGATIVE, &new->h.flags))
+ return ;
+
+ init_fs_pin(&new->ex_pin, export_pin_kill);
+ pin_insert_group(&new->ex_pin, new->ex_path.mnt, NULL);
+ mntput(new->ex_path.mnt);
+}
+
static struct cache_head *svc_export_alloc(void)
{
struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
@@ -758,6 +783,7 @@ static struct cache_detail svc_export_cache_template = {
.match = svc_export_match,
.init = svc_export_init,
.update = export_update,
+ .update_negative= export_update_negative,
.alloc = svc_export_alloc,
};
@@ -4,6 +4,7 @@
#ifndef NFSD_EXPORT_H
#define NFSD_EXPORT_H
+#include <linux/fs_pin.h>
#include <linux/sunrpc/cache.h>
#include <uapi/linux/nfsd/export.h>
@@ -46,6 +47,8 @@ struct exp_flavor_info {
struct svc_export {
struct cache_head h;
+ struct cache_detail *cd;
+
struct auth_domain * ex_client;
int ex_flags;
struct path ex_path;
@@ -58,7 +61,9 @@ struct svc_export {
struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST];
enum pnfs_layouttype ex_layout_type;
struct nfsd4_deviceid_map *ex_devid_map;
- struct cache_detail *cd;
+
+ struct fs_pin ex_pin;
+ struct rcu_head rcu_head;
};
/* an "export key" (expkey) maps a filehandlefragement to an
@@ -101,6 +101,7 @@ struct cache_detail {
int (*match)(struct cache_head *orig, struct cache_head *new);
void (*init)(struct cache_head *orig, struct cache_head *new);
void (*update)(struct cache_head *orig, struct cache_head *new);
+ void (*update_negative)(struct cache_head *orig, struct cache_head *new);
/* fields below this comment are for internal use
* and should not be touched by cache owners
@@ -149,9 +149,11 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
if (!test_bit(CACHE_VALID, &old->flags)) {
write_lock(&detail->hash_lock);
if (!test_bit(CACHE_VALID, &old->flags)) {
- if (test_bit(CACHE_NEGATIVE, &new->flags))
+ if (test_bit(CACHE_NEGATIVE, &new->flags)) {
set_bit(CACHE_NEGATIVE, &old->flags);
- else
+ if (detail->update_negative)
+ detail->update_negative(old, new);
+ } else
detail->update(old, new);
cache_fresh_locked(old, new->expiry_time);
write_unlock(&detail->hash_lock);
@@ -171,9 +173,11 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
head = &detail->hash_table[hash];
write_lock(&detail->hash_lock);
- if (test_bit(CACHE_NEGATIVE, &new->flags))
+ if (test_bit(CACHE_NEGATIVE, &new->flags)) {
set_bit(CACHE_NEGATIVE, &tmp->flags);
- else
+ if (detail->update_negative)
+ detail->update_negative(old, new);
+ } else
detail->update(tmp, new);
tmp->next = *head;
*head = tmp;