struct nfs_server *nfs_alloc_server(void)
{
struct nfs_server *server;
+ int delegation_buckets, i;
server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
if (!server)
atomic_set(&server->active, 0);
atomic_long_set(&server->nr_active_delegations, 0);
+ delegation_buckets = roundup_pow_of_two(nfs_delegation_watermark / 16);
+ server->delegation_hash_mask = delegation_buckets - 1;
+ server->delegation_hash_table = kmalloc_array(delegation_buckets,
+ sizeof(*server->delegation_hash_table), GFP_KERNEL);
+ if (!server->delegation_hash_table)
+ goto out_free_server;
+ for (i = 0; i < delegation_buckets; i++)
+ INIT_HLIST_HEAD(&server->delegation_hash_table[i]);
+
server->io_stats = nfs_alloc_iostats();
- if (!server->io_stats) {
- kfree(server);
- return NULL;
- }
+ if (!server->io_stats)
+ goto out_free_delegation_hash;
server->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED;
rpc_init_wait_queue(&server->uoc_rpcwaitq, "NFS UOC");
return server;
+
+out_free_delegation_hash:
+ kfree(server->delegation_hash_table);
+out_free_server:
+ kfree(server);
+ return NULL;
}
EXPORT_SYMBOL_GPL(nfs_alloc_server);
struct nfs_server *server = container_of(p, struct nfs_server, rcu);
nfs_free_iostats(server->io_stats);
+ kfree(server->delegation_hash_table);
kfree(server);
}
#define NFS_DEFAULT_DELEGATION_WATERMARK (5000U)
-static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
+unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK;
module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644);
+static struct hlist_head *nfs_delegation_hash(struct nfs_server *server,
+ const struct nfs_fh *fhandle)
+{
+ return server->delegation_hash_table +
+ (nfs_fhandle_hash(fhandle) & server->delegation_hash_mask);
+}
+
static void __nfs_free_delegation(struct nfs_delegation *delegation)
{
put_cred(delegation->cred);
spin_unlock(&delegation->lock);
return NULL;
}
+ hlist_del_init_rcu(&delegation->hash);
list_del_rcu(&delegation->super_list);
delegation->inode = NULL;
rcu_assign_pointer(nfsi->delegation, NULL);
spin_unlock(&inode->i_lock);
list_add_tail_rcu(&delegation->super_list, &server->delegations);
+ hlist_add_head_rcu(&delegation->hash,
+ nfs_delegation_hash(server, &NFS_I(inode)->fh));
rcu_assign_pointer(nfsi->delegation, delegation);
delegation = NULL;
nfs_delegation_find_inode_server(struct nfs_server *server,
const struct nfs_fh *fhandle)
{
+ struct hlist_head *head = nfs_delegation_hash(server, fhandle);
struct nfs_delegation *delegation;
struct super_block *freeme = NULL;
struct inode *res = NULL;
- list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
+ hlist_for_each_entry_rcu(delegation, head, hash) {
spin_lock(&delegation->lock);
if (delegation->inode != NULL &&
!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) &&