xref: /kernel/linux/linux-5.10/fs/ocfs2/slot_map.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*-
38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0:
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * slot_map.c
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2002, 2004 Oracle.  All rights reserved.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/highmem.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <cluster/masklog.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "ocfs2.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "dlmglue.h"
198c2ecf20Sopenharmony_ci#include "extent_map.h"
208c2ecf20Sopenharmony_ci#include "heartbeat.h"
218c2ecf20Sopenharmony_ci#include "inode.h"
228c2ecf20Sopenharmony_ci#include "slot_map.h"
238c2ecf20Sopenharmony_ci#include "super.h"
248c2ecf20Sopenharmony_ci#include "sysfile.h"
258c2ecf20Sopenharmony_ci#include "ocfs2_trace.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "buffer_head_io.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct ocfs2_slot {
318c2ecf20Sopenharmony_ci	int sl_valid;
328c2ecf20Sopenharmony_ci	unsigned int sl_node_num;
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct ocfs2_slot_info {
368c2ecf20Sopenharmony_ci	int si_extended;
378c2ecf20Sopenharmony_ci	int si_slots_per_block;
388c2ecf20Sopenharmony_ci	struct inode *si_inode;
398c2ecf20Sopenharmony_ci	unsigned int si_blocks;
408c2ecf20Sopenharmony_ci	struct buffer_head **si_bh;
418c2ecf20Sopenharmony_ci	unsigned int si_num_slots;
428c2ecf20Sopenharmony_ci	struct ocfs2_slot si_slots[];
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic int __ocfs2_node_num_to_slot(struct ocfs2_slot_info *si,
478c2ecf20Sopenharmony_ci				    unsigned int node_num);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic void ocfs2_invalidate_slot(struct ocfs2_slot_info *si,
508c2ecf20Sopenharmony_ci				  int slot_num)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	BUG_ON((slot_num < 0) || (slot_num >= si->si_num_slots));
538c2ecf20Sopenharmony_ci	si->si_slots[slot_num].sl_valid = 0;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic void ocfs2_set_slot(struct ocfs2_slot_info *si,
578c2ecf20Sopenharmony_ci			   int slot_num, unsigned int node_num)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	BUG_ON((slot_num < 0) || (slot_num >= si->si_num_slots));
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	si->si_slots[slot_num].sl_valid = 1;
628c2ecf20Sopenharmony_ci	si->si_slots[slot_num].sl_node_num = node_num;
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/* This version is for the extended slot map */
668c2ecf20Sopenharmony_cistatic void ocfs2_update_slot_info_extended(struct ocfs2_slot_info *si)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	int b, i, slotno;
698c2ecf20Sopenharmony_ci	struct ocfs2_slot_map_extended *se;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	slotno = 0;
728c2ecf20Sopenharmony_ci	for (b = 0; b < si->si_blocks; b++) {
738c2ecf20Sopenharmony_ci		se = (struct ocfs2_slot_map_extended *)si->si_bh[b]->b_data;
748c2ecf20Sopenharmony_ci		for (i = 0;
758c2ecf20Sopenharmony_ci		     (i < si->si_slots_per_block) &&
768c2ecf20Sopenharmony_ci		     (slotno < si->si_num_slots);
778c2ecf20Sopenharmony_ci		     i++, slotno++) {
788c2ecf20Sopenharmony_ci			if (se->se_slots[i].es_valid)
798c2ecf20Sopenharmony_ci				ocfs2_set_slot(si, slotno,
808c2ecf20Sopenharmony_ci					       le32_to_cpu(se->se_slots[i].es_node_num));
818c2ecf20Sopenharmony_ci			else
828c2ecf20Sopenharmony_ci				ocfs2_invalidate_slot(si, slotno);
838c2ecf20Sopenharmony_ci		}
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/*
888c2ecf20Sopenharmony_ci * Post the slot information on disk into our slot_info struct.
898c2ecf20Sopenharmony_ci * Must be protected by osb_lock.
908c2ecf20Sopenharmony_ci */
918c2ecf20Sopenharmony_cistatic void ocfs2_update_slot_info_old(struct ocfs2_slot_info *si)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	int i;
948c2ecf20Sopenharmony_ci	struct ocfs2_slot_map *sm;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	sm = (struct ocfs2_slot_map *)si->si_bh[0]->b_data;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	for (i = 0; i < si->si_num_slots; i++) {
998c2ecf20Sopenharmony_ci		if (le16_to_cpu(sm->sm_slots[i]) == (u16)OCFS2_INVALID_SLOT)
1008c2ecf20Sopenharmony_ci			ocfs2_invalidate_slot(si, i);
1018c2ecf20Sopenharmony_ci		else
1028c2ecf20Sopenharmony_ci			ocfs2_set_slot(si, i, le16_to_cpu(sm->sm_slots[i]));
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic void ocfs2_update_slot_info(struct ocfs2_slot_info *si)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	/*
1098c2ecf20Sopenharmony_ci	 * The slot data will have been refreshed when ocfs2_super_lock
1108c2ecf20Sopenharmony_ci	 * was taken.
1118c2ecf20Sopenharmony_ci	 */
1128c2ecf20Sopenharmony_ci	if (si->si_extended)
1138c2ecf20Sopenharmony_ci		ocfs2_update_slot_info_extended(si);
1148c2ecf20Sopenharmony_ci	else
1158c2ecf20Sopenharmony_ci		ocfs2_update_slot_info_old(si);
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ciint ocfs2_refresh_slot_info(struct ocfs2_super *osb)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	int ret;
1218c2ecf20Sopenharmony_ci	struct ocfs2_slot_info *si = osb->slot_info;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (si == NULL)
1248c2ecf20Sopenharmony_ci		return 0;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	BUG_ON(si->si_blocks == 0);
1278c2ecf20Sopenharmony_ci	BUG_ON(si->si_bh == NULL);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	trace_ocfs2_refresh_slot_info(si->si_blocks);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/*
1328c2ecf20Sopenharmony_ci	 * We pass -1 as blocknr because we expect all of si->si_bh to
1338c2ecf20Sopenharmony_ci	 * be !NULL.  Thus, ocfs2_read_blocks() will ignore blocknr.  If
1348c2ecf20Sopenharmony_ci	 * this is not true, the read of -1 (UINT64_MAX) will fail.
1358c2ecf20Sopenharmony_ci	 */
1368c2ecf20Sopenharmony_ci	ret = ocfs2_read_blocks(INODE_CACHE(si->si_inode), -1, si->si_blocks,
1378c2ecf20Sopenharmony_ci				si->si_bh, OCFS2_BH_IGNORE_CACHE, NULL);
1388c2ecf20Sopenharmony_ci	if (ret == 0) {
1398c2ecf20Sopenharmony_ci		spin_lock(&osb->osb_lock);
1408c2ecf20Sopenharmony_ci		ocfs2_update_slot_info(si);
1418c2ecf20Sopenharmony_ci		spin_unlock(&osb->osb_lock);
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	return ret;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci/* post the our slot info stuff into it's destination bh and write it
1488c2ecf20Sopenharmony_ci * out. */
1498c2ecf20Sopenharmony_cistatic void ocfs2_update_disk_slot_extended(struct ocfs2_slot_info *si,
1508c2ecf20Sopenharmony_ci					    int slot_num,
1518c2ecf20Sopenharmony_ci					    struct buffer_head **bh)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	int blkind = slot_num / si->si_slots_per_block;
1548c2ecf20Sopenharmony_ci	int slotno = slot_num % si->si_slots_per_block;
1558c2ecf20Sopenharmony_ci	struct ocfs2_slot_map_extended *se;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	BUG_ON(blkind >= si->si_blocks);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	se = (struct ocfs2_slot_map_extended *)si->si_bh[blkind]->b_data;
1608c2ecf20Sopenharmony_ci	se->se_slots[slotno].es_valid = si->si_slots[slot_num].sl_valid;
1618c2ecf20Sopenharmony_ci	if (si->si_slots[slot_num].sl_valid)
1628c2ecf20Sopenharmony_ci		se->se_slots[slotno].es_node_num =
1638c2ecf20Sopenharmony_ci			cpu_to_le32(si->si_slots[slot_num].sl_node_num);
1648c2ecf20Sopenharmony_ci	*bh = si->si_bh[blkind];
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic void ocfs2_update_disk_slot_old(struct ocfs2_slot_info *si,
1688c2ecf20Sopenharmony_ci				       int slot_num,
1698c2ecf20Sopenharmony_ci				       struct buffer_head **bh)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	int i;
1728c2ecf20Sopenharmony_ci	struct ocfs2_slot_map *sm;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	sm = (struct ocfs2_slot_map *)si->si_bh[0]->b_data;
1758c2ecf20Sopenharmony_ci	for (i = 0; i < si->si_num_slots; i++) {
1768c2ecf20Sopenharmony_ci		if (si->si_slots[i].sl_valid)
1778c2ecf20Sopenharmony_ci			sm->sm_slots[i] =
1788c2ecf20Sopenharmony_ci				cpu_to_le16(si->si_slots[i].sl_node_num);
1798c2ecf20Sopenharmony_ci		else
1808c2ecf20Sopenharmony_ci			sm->sm_slots[i] = cpu_to_le16(OCFS2_INVALID_SLOT);
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci	*bh = si->si_bh[0];
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic int ocfs2_update_disk_slot(struct ocfs2_super *osb,
1868c2ecf20Sopenharmony_ci				  struct ocfs2_slot_info *si,
1878c2ecf20Sopenharmony_ci				  int slot_num)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	int status;
1908c2ecf20Sopenharmony_ci	struct buffer_head *bh;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	spin_lock(&osb->osb_lock);
1938c2ecf20Sopenharmony_ci	if (si->si_extended)
1948c2ecf20Sopenharmony_ci		ocfs2_update_disk_slot_extended(si, slot_num, &bh);
1958c2ecf20Sopenharmony_ci	else
1968c2ecf20Sopenharmony_ci		ocfs2_update_disk_slot_old(si, slot_num, &bh);
1978c2ecf20Sopenharmony_ci	spin_unlock(&osb->osb_lock);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	status = ocfs2_write_block(osb, bh, INODE_CACHE(si->si_inode));
2008c2ecf20Sopenharmony_ci	if (status < 0)
2018c2ecf20Sopenharmony_ci		mlog_errno(status);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return status;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci/*
2078c2ecf20Sopenharmony_ci * Calculate how many bytes are needed by the slot map.  Returns
2088c2ecf20Sopenharmony_ci * an error if the slot map file is too small.
2098c2ecf20Sopenharmony_ci */
2108c2ecf20Sopenharmony_cistatic int ocfs2_slot_map_physical_size(struct ocfs2_super *osb,
2118c2ecf20Sopenharmony_ci					struct inode *inode,
2128c2ecf20Sopenharmony_ci					unsigned long long *bytes)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	unsigned long long bytes_needed;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (ocfs2_uses_extended_slot_map(osb)) {
2178c2ecf20Sopenharmony_ci		bytes_needed = osb->max_slots *
2188c2ecf20Sopenharmony_ci			sizeof(struct ocfs2_extended_slot);
2198c2ecf20Sopenharmony_ci	} else {
2208c2ecf20Sopenharmony_ci		bytes_needed = osb->max_slots * sizeof(__le16);
2218c2ecf20Sopenharmony_ci	}
2228c2ecf20Sopenharmony_ci	if (bytes_needed > i_size_read(inode)) {
2238c2ecf20Sopenharmony_ci		mlog(ML_ERROR,
2248c2ecf20Sopenharmony_ci		     "Slot map file is too small!  (size %llu, needed %llu)\n",
2258c2ecf20Sopenharmony_ci		     i_size_read(inode), bytes_needed);
2268c2ecf20Sopenharmony_ci		return -ENOSPC;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	*bytes = bytes_needed;
2308c2ecf20Sopenharmony_ci	return 0;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/* try to find global node in the slot info. Returns -ENOENT
2348c2ecf20Sopenharmony_ci * if nothing is found. */
2358c2ecf20Sopenharmony_cistatic int __ocfs2_node_num_to_slot(struct ocfs2_slot_info *si,
2368c2ecf20Sopenharmony_ci				    unsigned int node_num)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	int i, ret = -ENOENT;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	for(i = 0; i < si->si_num_slots; i++) {
2418c2ecf20Sopenharmony_ci		if (si->si_slots[i].sl_valid &&
2428c2ecf20Sopenharmony_ci		    (node_num == si->si_slots[i].sl_node_num)) {
2438c2ecf20Sopenharmony_ci			ret = i;
2448c2ecf20Sopenharmony_ci			break;
2458c2ecf20Sopenharmony_ci		}
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	return ret;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic int __ocfs2_find_empty_slot(struct ocfs2_slot_info *si,
2528c2ecf20Sopenharmony_ci				   int preferred)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	int i, ret = -ENOSPC;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if ((preferred >= 0) && (preferred < si->si_num_slots)) {
2578c2ecf20Sopenharmony_ci		if (!si->si_slots[preferred].sl_valid) {
2588c2ecf20Sopenharmony_ci			ret = preferred;
2598c2ecf20Sopenharmony_ci			goto out;
2608c2ecf20Sopenharmony_ci		}
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	for(i = 0; i < si->si_num_slots; i++) {
2648c2ecf20Sopenharmony_ci		if (!si->si_slots[i].sl_valid) {
2658c2ecf20Sopenharmony_ci			ret = i;
2668c2ecf20Sopenharmony_ci			break;
2678c2ecf20Sopenharmony_ci		}
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ciout:
2708c2ecf20Sopenharmony_ci	return ret;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ciint ocfs2_node_num_to_slot(struct ocfs2_super *osb, unsigned int node_num)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	int slot;
2768c2ecf20Sopenharmony_ci	struct ocfs2_slot_info *si = osb->slot_info;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	spin_lock(&osb->osb_lock);
2798c2ecf20Sopenharmony_ci	slot = __ocfs2_node_num_to_slot(si, node_num);
2808c2ecf20Sopenharmony_ci	spin_unlock(&osb->osb_lock);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	return slot;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ciint ocfs2_slot_to_node_num_locked(struct ocfs2_super *osb, int slot_num,
2868c2ecf20Sopenharmony_ci				  unsigned int *node_num)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	struct ocfs2_slot_info *si = osb->slot_info;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	assert_spin_locked(&osb->osb_lock);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	BUG_ON(slot_num < 0);
2938c2ecf20Sopenharmony_ci	BUG_ON(slot_num >= osb->max_slots);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (!si->si_slots[slot_num].sl_valid)
2968c2ecf20Sopenharmony_ci		return -ENOENT;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	*node_num = si->si_slots[slot_num].sl_node_num;
2998c2ecf20Sopenharmony_ci	return 0;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic void __ocfs2_free_slot_info(struct ocfs2_slot_info *si)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	unsigned int i;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (si == NULL)
3078c2ecf20Sopenharmony_ci		return;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	iput(si->si_inode);
3108c2ecf20Sopenharmony_ci	if (si->si_bh) {
3118c2ecf20Sopenharmony_ci		for (i = 0; i < si->si_blocks; i++) {
3128c2ecf20Sopenharmony_ci			if (si->si_bh[i]) {
3138c2ecf20Sopenharmony_ci				brelse(si->si_bh[i]);
3148c2ecf20Sopenharmony_ci				si->si_bh[i] = NULL;
3158c2ecf20Sopenharmony_ci			}
3168c2ecf20Sopenharmony_ci		}
3178c2ecf20Sopenharmony_ci		kfree(si->si_bh);
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	kfree(si);
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ciint ocfs2_clear_slot(struct ocfs2_super *osb, int slot_num)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	struct ocfs2_slot_info *si = osb->slot_info;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (si == NULL)
3288c2ecf20Sopenharmony_ci		return 0;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	spin_lock(&osb->osb_lock);
3318c2ecf20Sopenharmony_ci	ocfs2_invalidate_slot(si, slot_num);
3328c2ecf20Sopenharmony_ci	spin_unlock(&osb->osb_lock);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return ocfs2_update_disk_slot(osb, osb->slot_info, slot_num);
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic int ocfs2_map_slot_buffers(struct ocfs2_super *osb,
3388c2ecf20Sopenharmony_ci				  struct ocfs2_slot_info *si)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	int status = 0;
3418c2ecf20Sopenharmony_ci	u64 blkno;
3428c2ecf20Sopenharmony_ci	unsigned long long blocks, bytes = 0;
3438c2ecf20Sopenharmony_ci	unsigned int i;
3448c2ecf20Sopenharmony_ci	struct buffer_head *bh;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	status = ocfs2_slot_map_physical_size(osb, si->si_inode, &bytes);
3478c2ecf20Sopenharmony_ci	if (status)
3488c2ecf20Sopenharmony_ci		goto bail;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	blocks = ocfs2_blocks_for_bytes(si->si_inode->i_sb, bytes);
3518c2ecf20Sopenharmony_ci	BUG_ON(blocks > UINT_MAX);
3528c2ecf20Sopenharmony_ci	si->si_blocks = blocks;
3538c2ecf20Sopenharmony_ci	if (!si->si_blocks)
3548c2ecf20Sopenharmony_ci		goto bail;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (si->si_extended)
3578c2ecf20Sopenharmony_ci		si->si_slots_per_block =
3588c2ecf20Sopenharmony_ci			(osb->sb->s_blocksize /
3598c2ecf20Sopenharmony_ci			 sizeof(struct ocfs2_extended_slot));
3608c2ecf20Sopenharmony_ci	else
3618c2ecf20Sopenharmony_ci		si->si_slots_per_block = osb->sb->s_blocksize / sizeof(__le16);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	/* The size checks above should ensure this */
3648c2ecf20Sopenharmony_ci	BUG_ON((osb->max_slots / si->si_slots_per_block) > blocks);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	trace_ocfs2_map_slot_buffers(bytes, si->si_blocks);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	si->si_bh = kcalloc(si->si_blocks, sizeof(struct buffer_head *),
3698c2ecf20Sopenharmony_ci			    GFP_KERNEL);
3708c2ecf20Sopenharmony_ci	if (!si->si_bh) {
3718c2ecf20Sopenharmony_ci		status = -ENOMEM;
3728c2ecf20Sopenharmony_ci		mlog_errno(status);
3738c2ecf20Sopenharmony_ci		goto bail;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	for (i = 0; i < si->si_blocks; i++) {
3778c2ecf20Sopenharmony_ci		status = ocfs2_extent_map_get_blocks(si->si_inode, i,
3788c2ecf20Sopenharmony_ci						     &blkno, NULL, NULL);
3798c2ecf20Sopenharmony_ci		if (status < 0) {
3808c2ecf20Sopenharmony_ci			mlog_errno(status);
3818c2ecf20Sopenharmony_ci			goto bail;
3828c2ecf20Sopenharmony_ci		}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci		trace_ocfs2_map_slot_buffers_block((unsigned long long)blkno, i);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci		bh = NULL;  /* Acquire a fresh bh */
3878c2ecf20Sopenharmony_ci		status = ocfs2_read_blocks(INODE_CACHE(si->si_inode), blkno,
3888c2ecf20Sopenharmony_ci					   1, &bh, OCFS2_BH_IGNORE_CACHE, NULL);
3898c2ecf20Sopenharmony_ci		if (status < 0) {
3908c2ecf20Sopenharmony_ci			mlog_errno(status);
3918c2ecf20Sopenharmony_ci			goto bail;
3928c2ecf20Sopenharmony_ci		}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci		si->si_bh[i] = bh;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cibail:
3988c2ecf20Sopenharmony_ci	return status;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ciint ocfs2_init_slot_info(struct ocfs2_super *osb)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	int status;
4048c2ecf20Sopenharmony_ci	struct inode *inode = NULL;
4058c2ecf20Sopenharmony_ci	struct ocfs2_slot_info *si;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	si = kzalloc(struct_size(si, si_slots, osb->max_slots), GFP_KERNEL);
4088c2ecf20Sopenharmony_ci	if (!si) {
4098c2ecf20Sopenharmony_ci		status = -ENOMEM;
4108c2ecf20Sopenharmony_ci		mlog_errno(status);
4118c2ecf20Sopenharmony_ci		return status;
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	si->si_extended = ocfs2_uses_extended_slot_map(osb);
4158c2ecf20Sopenharmony_ci	si->si_num_slots = osb->max_slots;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	inode = ocfs2_get_system_file_inode(osb, SLOT_MAP_SYSTEM_INODE,
4188c2ecf20Sopenharmony_ci					    OCFS2_INVALID_SLOT);
4198c2ecf20Sopenharmony_ci	if (!inode) {
4208c2ecf20Sopenharmony_ci		status = -EINVAL;
4218c2ecf20Sopenharmony_ci		mlog_errno(status);
4228c2ecf20Sopenharmony_ci		goto bail;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	si->si_inode = inode;
4268c2ecf20Sopenharmony_ci	status = ocfs2_map_slot_buffers(osb, si);
4278c2ecf20Sopenharmony_ci	if (status < 0) {
4288c2ecf20Sopenharmony_ci		mlog_errno(status);
4298c2ecf20Sopenharmony_ci		goto bail;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	osb->slot_info = (struct ocfs2_slot_info *)si;
4338c2ecf20Sopenharmony_cibail:
4348c2ecf20Sopenharmony_ci	if (status < 0)
4358c2ecf20Sopenharmony_ci		__ocfs2_free_slot_info(si);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	return status;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_civoid ocfs2_free_slot_info(struct ocfs2_super *osb)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	struct ocfs2_slot_info *si = osb->slot_info;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	osb->slot_info = NULL;
4458c2ecf20Sopenharmony_ci	__ocfs2_free_slot_info(si);
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ciint ocfs2_find_slot(struct ocfs2_super *osb)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	int status;
4518c2ecf20Sopenharmony_ci	int slot;
4528c2ecf20Sopenharmony_ci	struct ocfs2_slot_info *si;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	si = osb->slot_info;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	spin_lock(&osb->osb_lock);
4578c2ecf20Sopenharmony_ci	ocfs2_update_slot_info(si);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	/* search for ourselves first and take the slot if it already
4608c2ecf20Sopenharmony_ci	 * exists. Perhaps we need to mark this in a variable for our
4618c2ecf20Sopenharmony_ci	 * own journal recovery? Possibly not, though we certainly
4628c2ecf20Sopenharmony_ci	 * need to warn to the user */
4638c2ecf20Sopenharmony_ci	slot = __ocfs2_node_num_to_slot(si, osb->node_num);
4648c2ecf20Sopenharmony_ci	if (slot < 0) {
4658c2ecf20Sopenharmony_ci		/* if no slot yet, then just take 1st available
4668c2ecf20Sopenharmony_ci		 * one. */
4678c2ecf20Sopenharmony_ci		slot = __ocfs2_find_empty_slot(si, osb->preferred_slot);
4688c2ecf20Sopenharmony_ci		if (slot < 0) {
4698c2ecf20Sopenharmony_ci			spin_unlock(&osb->osb_lock);
4708c2ecf20Sopenharmony_ci			mlog(ML_ERROR, "no free slots available!\n");
4718c2ecf20Sopenharmony_ci			status = -EINVAL;
4728c2ecf20Sopenharmony_ci			goto bail;
4738c2ecf20Sopenharmony_ci		}
4748c2ecf20Sopenharmony_ci	} else
4758c2ecf20Sopenharmony_ci		printk(KERN_INFO "ocfs2: Slot %d on device (%s) was already "
4768c2ecf20Sopenharmony_ci		       "allocated to this node!\n", slot, osb->dev_str);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	ocfs2_set_slot(si, slot, osb->node_num);
4798c2ecf20Sopenharmony_ci	osb->slot_num = slot;
4808c2ecf20Sopenharmony_ci	spin_unlock(&osb->osb_lock);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	trace_ocfs2_find_slot(osb->slot_num);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	status = ocfs2_update_disk_slot(osb, si, osb->slot_num);
4858c2ecf20Sopenharmony_ci	if (status < 0) {
4868c2ecf20Sopenharmony_ci		mlog_errno(status);
4878c2ecf20Sopenharmony_ci		/*
4888c2ecf20Sopenharmony_ci		 * if write block failed, invalidate slot to avoid overwrite
4898c2ecf20Sopenharmony_ci		 * slot during dismount in case another node rightly has mounted
4908c2ecf20Sopenharmony_ci		 */
4918c2ecf20Sopenharmony_ci		spin_lock(&osb->osb_lock);
4928c2ecf20Sopenharmony_ci		ocfs2_invalidate_slot(si, osb->slot_num);
4938c2ecf20Sopenharmony_ci		osb->slot_num = OCFS2_INVALID_SLOT;
4948c2ecf20Sopenharmony_ci		spin_unlock(&osb->osb_lock);
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cibail:
4988c2ecf20Sopenharmony_ci	return status;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_civoid ocfs2_put_slot(struct ocfs2_super *osb)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	int status, slot_num;
5048c2ecf20Sopenharmony_ci	struct ocfs2_slot_info *si = osb->slot_info;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (!si)
5078c2ecf20Sopenharmony_ci		return;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	spin_lock(&osb->osb_lock);
5108c2ecf20Sopenharmony_ci	ocfs2_update_slot_info(si);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	slot_num = osb->slot_num;
5138c2ecf20Sopenharmony_ci	ocfs2_invalidate_slot(si, osb->slot_num);
5148c2ecf20Sopenharmony_ci	osb->slot_num = OCFS2_INVALID_SLOT;
5158c2ecf20Sopenharmony_ci	spin_unlock(&osb->osb_lock);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	status = ocfs2_update_disk_slot(osb, si, slot_num);
5188c2ecf20Sopenharmony_ci	if (status < 0)
5198c2ecf20Sopenharmony_ci		mlog_errno(status);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	ocfs2_free_slot_info(osb);
5228c2ecf20Sopenharmony_ci}
523