Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / fs / nfs / idmap.c
index 47d1c6f..b122af8 100644 (file)
@@ -318,12 +318,12 @@ struct idmap_hashent {
        unsigned long           ih_expires;
        __u32                   ih_id;
        size_t                  ih_namelen;
-       char                    ih_name[IDMAP_NAMESZ];
+       const char              *ih_name;
 };
 
 struct idmap_hashtable {
        __u8                    h_type;
-       struct idmap_hashent    h_entries[IDMAP_HASH_SZ];
+       struct idmap_hashent    *h_entries;
 };
 
 struct idmap {
@@ -378,6 +378,28 @@ 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)
 {
@@ -387,6 +409,8 @@ nfs_idmap_delete(struct nfs_client *clp)
                return;
        rpc_unlink(idmap->idmap_dentry);
        clp->cl_idmap = NULL;
+       idmap_free_hashtable(&idmap->idmap_user_hash);
+       idmap_free_hashtable(&idmap->idmap_group_hash);
        kfree(idmap);
 }
 
@@ -396,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];
 }
 
@@ -404,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))
@@ -414,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];
 }
 
@@ -421,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))
@@ -436,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);
 }
 
@@ -449,9 +484,14 @@ static void
 idmap_update_entry(struct idmap_hashent *he, const char *name,
                size_t namelen, __u32 id)
 {
+       char *str = kmalloc(namelen + 1, GFP_KERNEL);
+       if (str == NULL)
+               return;
+       kfree(he->ih_name);
        he->ih_id = id;
-       memcpy(he->ih_name, name, namelen);
-       he->ih_name[namelen] = '\0';
+       memcpy(str, name, namelen);
+       str[namelen] = '\0';
+       he->ih_name = str;
        he->ih_namelen = namelen;
        he->ih_expires = jiffies + nfs_idmap_cache_timeout;
 }