Fix directory hardlinks from deleted directories
[pandora-kernel.git] / fs / nfs / idmap.c
index b8c41c3..b122af8 100644 (file)
@@ -323,7 +323,7 @@ struct idmap_hashent {
 
 struct idmap_hashtable {
        __u8                    h_type;
-       struct idmap_hashent    h_entries[IDMAP_HASH_SZ];
+       struct idmap_hashent    *h_entries;
 };
 
 struct idmap {
@@ -378,20 +378,39 @@ nfs_idmap_new(struct nfs_client *clp)
        return 0;
 }
 
+static void
+idmap_alloc_hashtable(struct idmap_hashtable *h)
+{
+       if (h->h_entries != NULL)
+               return;
+       h->h_entries = kcalloc(IDMAP_HASH_SZ,
+                       sizeof(*h->h_entries),
+                       GFP_KERNEL);
+}
+
+static void
+idmap_free_hashtable(struct idmap_hashtable *h)
+{
+       int i;
+
+       if (h->h_entries == NULL)
+               return;
+       for (i = 0; i < IDMAP_HASH_SZ; i++)
+               kfree(h->h_entries[i].ih_name);
+       kfree(h->h_entries);
+}
+
 void
 nfs_idmap_delete(struct nfs_client *clp)
 {
        struct idmap *idmap = clp->cl_idmap;
-       int i;
 
        if (!idmap)
                return;
        rpc_unlink(idmap->idmap_dentry);
        clp->cl_idmap = NULL;
-       for (i = 0; i < ARRAY_SIZE(idmap->idmap_user_hash.h_entries); i++)
-               kfree(idmap->idmap_user_hash.h_entries[i].ih_name);
-       for (i = 0; i < ARRAY_SIZE(idmap->idmap_group_hash.h_entries); i++)
-               kfree(idmap->idmap_group_hash.h_entries[i].ih_name);
+       idmap_free_hashtable(&idmap->idmap_user_hash);
+       idmap_free_hashtable(&idmap->idmap_group_hash);
        kfree(idmap);
 }
 
@@ -401,6 +420,8 @@ nfs_idmap_delete(struct nfs_client *clp)
 static inline struct idmap_hashent *
 idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len)
 {
+       if (h->h_entries == NULL)
+               return NULL;
        return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ];
 }
 
@@ -409,6 +430,8 @@ idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
 {
        struct idmap_hashent *he = idmap_name_hash(h, name, len);
 
+       if (he == NULL)
+               return NULL;
        if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0)
                return NULL;
        if (time_after(jiffies, he->ih_expires))
@@ -419,6 +442,8 @@ idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
 static inline struct idmap_hashent *
 idmap_id_hash(struct idmap_hashtable* h, __u32 id)
 {
+       if (h->h_entries == NULL)
+               return NULL;
        return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ];
 }
 
@@ -426,6 +451,9 @@ static struct idmap_hashent *
 idmap_lookup_id(struct idmap_hashtable *h, __u32 id)
 {
        struct idmap_hashent *he = idmap_id_hash(h, id);
+
+       if (he == NULL)
+               return NULL;
        if (he->ih_id != id || he->ih_namelen == 0)
                return NULL;
        if (time_after(jiffies, he->ih_expires))
@@ -441,12 +469,14 @@ idmap_lookup_id(struct idmap_hashtable *h, __u32 id)
 static inline struct idmap_hashent *
 idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len)
 {
+       idmap_alloc_hashtable(h);
        return idmap_name_hash(h, name, len);
 }
 
 static inline struct idmap_hashent *
 idmap_alloc_id(struct idmap_hashtable *h, __u32 id)
 {
+       idmap_alloc_hashtable(h);
        return idmap_id_hash(h, id);
 }