/*
* 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/jhash.h>
#include <linux/namei.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include "netfs.h"
static int pohmelfs_cmp_hash(struct pohmelfs_name *n, u32 hash)
{
if (n->hash > hash)
return -1;
if (n->hash < hash)
return 1;
return 0;
}
static struct pohmelfs_name *pohmelfs_search_hash_unprecise(struct pohmelfs_inode *pi, u32 hash)
{
struct rb_node *n = pi->hash_root.rb_node;
struct pohmelfs_name *tmp = NULL;
int cmp;
while (n) {
tmp = rb_entry(n, struct pohmelfs_name, hash_node);
cmp = pohmelfs_cmp_hash(tmp, hash);
if (cmp < 0)
n = n->rb_left;
else if (cmp > 0)
n = n->rb_right;
else
break;
}
return tmp;
}
struct pohmelfs_name *pohmelfs_search_hash(struct pohmelfs_inode *pi, u32 hash)
{
struct pohmelfs_name *tmp;
tmp = pohmelfs_search_hash_unprecise(pi, hash);
if (tmp && (tmp->hash == hash))
return tmp;
return NULL;
}
static void __pohmelfs_name_del(struct pohmelfs_inode *parent, struct pohmelfs_name *node)
{
rb_erase(&node->hash_node, &parent->hash_root);
}
/*
* Remove name cache entry from its caches and free it.
*/
static void pohmelfs_name_free(struct pohmelfs_inode *parent, struct pohmelfs_name *node)
{
__pohmelfs_name_del(parent, node);
list_del(&node->sync_create_entry);
kfree(node);
}
static struct pohmelfs_name *pohmelfs_insert_hash(struct pohmelfs_inode *pi,
struct pohmelfs_name *new)
{
struct rb_node **n = &pi->hash_root.rb_node, *parent = NULL;
struct pohmelfs_name *ret = NULL, *tmp;
int cmp;
while (*n) {
parent = *n;
tmp = rb_entry(parent, struct pohmelfs_name, hash_node);
cmp = pohmelfs_cmp_hash(tmp, new->hash);
if (cmp < 0)
n = &parent->rb_left;
else if (cmp > 0)
n = &parent->rb_right;
else {
ret = tmp;
break;
}
}
if (ret) {
printk("%s: exist: parent: %llu, ino: %llu, hash: %x, len: %u, data: '%s', "
"new: ino: %llu, hash: %x, len: %u, data: '%s'.\n",
__func__, pi->ino,
ret->ino, ret->hash, ret->len, ret->data,
new->ino, new->hash, new->len, new->data);
ret->ino = new->ino;
return ret;
}
rb_link_node(&new->hash_node, parent, n);
rb_insert_color(&new->hash_node, &pi->hash_root);
return NULL;
}
/*
* Free name cache for given inode.
*/
void pohmelfs_free_names(struct pohmelfs_inode *parent)
{
struct rb_node *rb_node;
struct pohmelfs_name *n;
for (rb_node =