xref: /openbmc/linux/fs/dlm/dir.c (revision 2522fe45a186e6276583e02723b78e1d1987cdd5)
1*2522fe45SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e7fd4179SDavid Teigland /******************************************************************************
3e7fd4179SDavid Teigland *******************************************************************************
4e7fd4179SDavid Teigland **
5e7fd4179SDavid Teigland **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
6e7fd4179SDavid Teigland **  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
7e7fd4179SDavid Teigland **
8e7fd4179SDavid Teigland **
9e7fd4179SDavid Teigland *******************************************************************************
10e7fd4179SDavid Teigland ******************************************************************************/
11e7fd4179SDavid Teigland 
12e7fd4179SDavid Teigland #include "dlm_internal.h"
13e7fd4179SDavid Teigland #include "lockspace.h"
14e7fd4179SDavid Teigland #include "member.h"
15e7fd4179SDavid Teigland #include "lowcomms.h"
16e7fd4179SDavid Teigland #include "rcom.h"
17e7fd4179SDavid Teigland #include "config.h"
18e7fd4179SDavid Teigland #include "memory.h"
19e7fd4179SDavid Teigland #include "recover.h"
20e7fd4179SDavid Teigland #include "util.h"
21e7fd4179SDavid Teigland #include "lock.h"
22e7fd4179SDavid Teigland #include "dir.h"
23e7fd4179SDavid Teigland 
24e7fd4179SDavid Teigland /*
25e7fd4179SDavid Teigland  * We use the upper 16 bits of the hash value to select the directory node.
26e7fd4179SDavid Teigland  * Low bits are used for distribution of rsb's among hash buckets on each node.
27e7fd4179SDavid Teigland  *
28e7fd4179SDavid Teigland  * To give the exact range wanted (0 to num_nodes-1), we apply a modulus of
29e7fd4179SDavid Teigland  * num_nodes to the hash value.  This value in the desired range is used as an
30e7fd4179SDavid Teigland  * offset into the sorted list of nodeid's to give the particular nodeid.
31e7fd4179SDavid Teigland  */
32e7fd4179SDavid Teigland 
33e7fd4179SDavid Teigland int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash)
34e7fd4179SDavid Teigland {
35c04fecb4SDavid Teigland 	uint32_t node;
36e7fd4179SDavid Teigland 
37c04fecb4SDavid Teigland 	if (ls->ls_num_nodes == 1)
38c04fecb4SDavid Teigland 		return dlm_our_nodeid();
39c04fecb4SDavid Teigland 	else {
40e7fd4179SDavid Teigland 		node = (hash >> 16) % ls->ls_total_weight;
41c04fecb4SDavid Teigland 		return ls->ls_node_array[node];
42e7fd4179SDavid Teigland 	}
43e7fd4179SDavid Teigland }
44e7fd4179SDavid Teigland 
45e7fd4179SDavid Teigland int dlm_dir_nodeid(struct dlm_rsb *r)
46e7fd4179SDavid Teigland {
47c04fecb4SDavid Teigland 	return r->res_dir_nodeid;
48e7fd4179SDavid Teigland }
49e7fd4179SDavid Teigland 
50c04fecb4SDavid Teigland void dlm_recover_dir_nodeid(struct dlm_ls *ls)
51e7fd4179SDavid Teigland {
52c04fecb4SDavid Teigland 	struct dlm_rsb *r;
53e7fd4179SDavid Teigland 
54c04fecb4SDavid Teigland 	down_read(&ls->ls_root_sem);
55c04fecb4SDavid Teigland 	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
56c04fecb4SDavid Teigland 		r->res_dir_nodeid = dlm_hash2nodeid(ls, r->res_hash);
57e7fd4179SDavid Teigland 	}
58c04fecb4SDavid Teigland 	up_read(&ls->ls_root_sem);
59e7fd4179SDavid Teigland }
60e7fd4179SDavid Teigland 
61e7fd4179SDavid Teigland int dlm_recover_directory(struct dlm_ls *ls)
62e7fd4179SDavid Teigland {
63e7fd4179SDavid Teigland 	struct dlm_member *memb;
64e7fd4179SDavid Teigland 	char *b, *last_name = NULL;
65c04fecb4SDavid Teigland 	int error = -ENOMEM, last_len, nodeid, result;
66e7fd4179SDavid Teigland 	uint16_t namelen;
67c04fecb4SDavid Teigland 	unsigned int count = 0, count_match = 0, count_bad = 0, count_add = 0;
68e7fd4179SDavid Teigland 
69075f0177SDavid Teigland 	log_rinfo(ls, "dlm_recover_directory");
70e7fd4179SDavid Teigland 
71e7fd4179SDavid Teigland 	if (dlm_no_directory(ls))
72e7fd4179SDavid Teigland 		goto out_status;
73e7fd4179SDavid Teigland 
74573c24c4SDavid Teigland 	last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_NOFS);
75e7fd4179SDavid Teigland 	if (!last_name)
76e7fd4179SDavid Teigland 		goto out;
77e7fd4179SDavid Teigland 
78e7fd4179SDavid Teigland 	list_for_each_entry(memb, &ls->ls_nodes, list) {
79c04fecb4SDavid Teigland 		if (memb->nodeid == dlm_our_nodeid())
80c04fecb4SDavid Teigland 			continue;
81c04fecb4SDavid Teigland 
82e7fd4179SDavid Teigland 		memset(last_name, 0, DLM_RESNAME_MAXLEN);
83e7fd4179SDavid Teigland 		last_len = 0;
84e7fd4179SDavid Teigland 
85e7fd4179SDavid Teigland 		for (;;) {
86cd9df1aaSAl Viro 			int left;
87e7fd4179SDavid Teigland 			error = dlm_recovery_stopped(ls);
88e7fd4179SDavid Teigland 			if (error)
89e7fd4179SDavid Teigland 				goto out_free;
90e7fd4179SDavid Teigland 
91e7fd4179SDavid Teigland 			error = dlm_rcom_names(ls, memb->nodeid,
92e7fd4179SDavid Teigland 					       last_name, last_len);
93e7fd4179SDavid Teigland 			if (error)
94e7fd4179SDavid Teigland 				goto out_free;
95e7fd4179SDavid Teigland 
96c04fecb4SDavid Teigland 			cond_resched();
97e7fd4179SDavid Teigland 
98e7fd4179SDavid Teigland 			/*
99e7fd4179SDavid Teigland 			 * pick namelen/name pairs out of received buffer
100e7fd4179SDavid Teigland 			 */
101e7fd4179SDavid Teigland 
1024007685cSAl Viro 			b = ls->ls_recover_buf->rc_buf;
103cd9df1aaSAl Viro 			left = ls->ls_recover_buf->rc_header.h_length;
104cd9df1aaSAl Viro 			left -= sizeof(struct dlm_rcom);
105e7fd4179SDavid Teigland 
106e7fd4179SDavid Teigland 			for (;;) {
107cd9df1aaSAl Viro 				__be16 v;
108cd9df1aaSAl Viro 
109cd9df1aaSAl Viro 				error = -EINVAL;
110cd9df1aaSAl Viro 				if (left < sizeof(__be16))
111cd9df1aaSAl Viro 					goto out_free;
112cd9df1aaSAl Viro 
113cd9df1aaSAl Viro 				memcpy(&v, b, sizeof(__be16));
114cd9df1aaSAl Viro 				namelen = be16_to_cpu(v);
115cd9df1aaSAl Viro 				b += sizeof(__be16);
116cd9df1aaSAl Viro 				left -= sizeof(__be16);
117e7fd4179SDavid Teigland 
118e7fd4179SDavid Teigland 				/* namelen of 0xFFFFF marks end of names for
119e7fd4179SDavid Teigland 				   this node; namelen of 0 marks end of the
120e7fd4179SDavid Teigland 				   buffer */
121e7fd4179SDavid Teigland 
122e7fd4179SDavid Teigland 				if (namelen == 0xFFFF)
123e7fd4179SDavid Teigland 					goto done;
124e7fd4179SDavid Teigland 				if (!namelen)
125e7fd4179SDavid Teigland 					break;
126e7fd4179SDavid Teigland 
127cd9df1aaSAl Viro 				if (namelen > left)
128cd9df1aaSAl Viro 					goto out_free;
129cd9df1aaSAl Viro 
130cd9df1aaSAl Viro 				if (namelen > DLM_RESNAME_MAXLEN)
131cd9df1aaSAl Viro 					goto out_free;
132cd9df1aaSAl Viro 
133c04fecb4SDavid Teigland 				error = dlm_master_lookup(ls, memb->nodeid,
134c04fecb4SDavid Teigland 							  b, namelen,
135c04fecb4SDavid Teigland 							  DLM_LU_RECOVER_DIR,
136c04fecb4SDavid Teigland 							  &nodeid, &result);
137c04fecb4SDavid Teigland 				if (error) {
138c04fecb4SDavid Teigland 					log_error(ls, "recover_dir lookup %d",
139c04fecb4SDavid Teigland 						  error);
140e7fd4179SDavid Teigland 					goto out_free;
141c04fecb4SDavid Teigland 				}
142e7fd4179SDavid Teigland 
143c04fecb4SDavid Teigland 				/* The name was found in rsbtbl, but the
144c04fecb4SDavid Teigland 				 * master nodeid is different from
145c04fecb4SDavid Teigland 				 * memb->nodeid which says it is the master.
146c04fecb4SDavid Teigland 				 * This should not happen. */
147c04fecb4SDavid Teigland 
148c04fecb4SDavid Teigland 				if (result == DLM_LU_MATCH &&
149c04fecb4SDavid Teigland 				    nodeid != memb->nodeid) {
150c04fecb4SDavid Teigland 					count_bad++;
151c04fecb4SDavid Teigland 					log_error(ls, "recover_dir lookup %d "
152c04fecb4SDavid Teigland 						  "nodeid %d memb %d bad %u",
153c04fecb4SDavid Teigland 						  result, nodeid, memb->nodeid,
154c04fecb4SDavid Teigland 						  count_bad);
155c04fecb4SDavid Teigland 					print_hex_dump_bytes("dlm_recover_dir ",
156c04fecb4SDavid Teigland 							     DUMP_PREFIX_NONE,
157c04fecb4SDavid Teigland 							     b, namelen);
158c04fecb4SDavid Teigland 				}
159c04fecb4SDavid Teigland 
160c04fecb4SDavid Teigland 				/* The name was found in rsbtbl, and the
161c04fecb4SDavid Teigland 				 * master nodeid matches memb->nodeid. */
162c04fecb4SDavid Teigland 
163c04fecb4SDavid Teigland 				if (result == DLM_LU_MATCH &&
164c04fecb4SDavid Teigland 				    nodeid == memb->nodeid) {
165c04fecb4SDavid Teigland 					count_match++;
166c04fecb4SDavid Teigland 				}
167c04fecb4SDavid Teigland 
168c04fecb4SDavid Teigland 				/* The name was not found in rsbtbl and was
169c04fecb4SDavid Teigland 				 * added with memb->nodeid as the master. */
170c04fecb4SDavid Teigland 
171c04fecb4SDavid Teigland 				if (result == DLM_LU_ADD) {
172c04fecb4SDavid Teigland 					count_add++;
173c04fecb4SDavid Teigland 				}
174c04fecb4SDavid Teigland 
175e7fd4179SDavid Teigland 				last_len = namelen;
176e7fd4179SDavid Teigland 				memcpy(last_name, b, namelen);
177e7fd4179SDavid Teigland 				b += namelen;
178cd9df1aaSAl Viro 				left -= namelen;
179e7fd4179SDavid Teigland 				count++;
180e7fd4179SDavid Teigland 			}
181e7fd4179SDavid Teigland 		}
182e7fd4179SDavid Teigland 	 done:
183e7fd4179SDavid Teigland 		;
184e7fd4179SDavid Teigland 	}
185e7fd4179SDavid Teigland 
186e7fd4179SDavid Teigland  out_status:
187e7fd4179SDavid Teigland 	error = 0;
188c04fecb4SDavid Teigland 	dlm_set_recover_status(ls, DLM_RS_DIR);
189c04fecb4SDavid Teigland 
190075f0177SDavid Teigland 	log_rinfo(ls, "dlm_recover_directory %u in %u new",
191c04fecb4SDavid Teigland 		  count, count_add);
192e7fd4179SDavid Teigland  out_free:
193e7fd4179SDavid Teigland 	kfree(last_name);
194e7fd4179SDavid Teigland  out:
195e7fd4179SDavid Teigland 	return error;
196e7fd4179SDavid Teigland }
197e7fd4179SDavid Teigland 
19885f0379aSDavid Teigland static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len)
19985f0379aSDavid Teigland {
20085f0379aSDavid Teigland 	struct dlm_rsb *r;
2017210cb7aSDavid Teigland 	uint32_t hash, bucket;
2027210cb7aSDavid Teigland 	int rv;
2037210cb7aSDavid Teigland 
2047210cb7aSDavid Teigland 	hash = jhash(name, len, 0);
2057210cb7aSDavid Teigland 	bucket = hash & (ls->ls_rsbtbl_size - 1);
2067210cb7aSDavid Teigland 
2077210cb7aSDavid Teigland 	spin_lock(&ls->ls_rsbtbl[bucket].lock);
208c04fecb4SDavid Teigland 	rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].keep, name, len, &r);
2097210cb7aSDavid Teigland 	if (rv)
2107210cb7aSDavid Teigland 		rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].toss,
211c04fecb4SDavid Teigland 					 name, len, &r);
2127210cb7aSDavid Teigland 	spin_unlock(&ls->ls_rsbtbl[bucket].lock);
2137210cb7aSDavid Teigland 
2147210cb7aSDavid Teigland 	if (!rv)
2157210cb7aSDavid Teigland 		return r;
21685f0379aSDavid Teigland 
21785f0379aSDavid Teigland 	down_read(&ls->ls_root_sem);
21885f0379aSDavid Teigland 	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
21985f0379aSDavid Teigland 		if (len == r->res_length && !memcmp(name, r->res_name, len)) {
22085f0379aSDavid Teigland 			up_read(&ls->ls_root_sem);
221c04fecb4SDavid Teigland 			log_debug(ls, "find_rsb_root revert to root_list %s",
2227210cb7aSDavid Teigland 				  r->res_name);
22385f0379aSDavid Teigland 			return r;
22485f0379aSDavid Teigland 		}
22585f0379aSDavid Teigland 	}
22685f0379aSDavid Teigland 	up_read(&ls->ls_root_sem);
22785f0379aSDavid Teigland 	return NULL;
22885f0379aSDavid Teigland }
22985f0379aSDavid Teigland 
23085f0379aSDavid Teigland /* Find the rsb where we left off (or start again), then send rsb names
23185f0379aSDavid Teigland    for rsb's we're master of and whose directory node matches the requesting
23285f0379aSDavid Teigland    node.  inbuf is the rsb name last sent, inlen is the name's length */
233e7fd4179SDavid Teigland 
234e7fd4179SDavid Teigland void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
235e7fd4179SDavid Teigland  			   char *outbuf, int outlen, int nodeid)
236e7fd4179SDavid Teigland {
237e7fd4179SDavid Teigland 	struct list_head *list;
23885f0379aSDavid Teigland 	struct dlm_rsb *r;
23985f0379aSDavid Teigland 	int offset = 0, dir_nodeid;
240cd8e4679SHarvey Harrison 	__be16 be_namelen;
241e7fd4179SDavid Teigland 
242e7fd4179SDavid Teigland 	down_read(&ls->ls_root_sem);
24385f0379aSDavid Teigland 
24485f0379aSDavid Teigland 	if (inlen > 1) {
24585f0379aSDavid Teigland 		r = find_rsb_root(ls, inbuf, inlen);
24685f0379aSDavid Teigland 		if (!r) {
24785f0379aSDavid Teigland 			inbuf[inlen - 1] = '\0';
24885f0379aSDavid Teigland 			log_error(ls, "copy_master_names from %d start %d %s",
24985f0379aSDavid Teigland 				  nodeid, inlen, inbuf);
25085f0379aSDavid Teigland 			goto out;
25185f0379aSDavid Teigland 		}
25285f0379aSDavid Teigland 		list = r->res_root_list.next;
25385f0379aSDavid Teigland 	} else {
254e7fd4179SDavid Teigland 		list = ls->ls_root_list.next;
25585f0379aSDavid Teigland 	}
256e7fd4179SDavid Teigland 
257e7fd4179SDavid Teigland 	for (offset = 0; list != &ls->ls_root_list; list = list->next) {
258e7fd4179SDavid Teigland 		r = list_entry(list, struct dlm_rsb, res_root_list);
259e7fd4179SDavid Teigland 		if (r->res_nodeid)
260e7fd4179SDavid Teigland 			continue;
261e7fd4179SDavid Teigland 
262e7fd4179SDavid Teigland 		dir_nodeid = dlm_dir_nodeid(r);
263e7fd4179SDavid Teigland 		if (dir_nodeid != nodeid)
264e7fd4179SDavid Teigland 			continue;
265e7fd4179SDavid Teigland 
266e7fd4179SDavid Teigland 		/*
267e7fd4179SDavid Teigland 		 * The block ends when we can't fit the following in the
268e7fd4179SDavid Teigland 		 * remaining buffer space:
269e7fd4179SDavid Teigland 		 * namelen (uint16_t) +
270e7fd4179SDavid Teigland 		 * name (r->res_length) +
271e7fd4179SDavid Teigland 		 * end-of-block record 0x0000 (uint16_t)
272e7fd4179SDavid Teigland 		 */
273e7fd4179SDavid Teigland 
274e7fd4179SDavid Teigland 		if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) {
275e7fd4179SDavid Teigland 			/* Write end-of-block record */
276cd8e4679SHarvey Harrison 			be_namelen = cpu_to_be16(0);
277cd8e4679SHarvey Harrison 			memcpy(outbuf + offset, &be_namelen, sizeof(__be16));
278cd8e4679SHarvey Harrison 			offset += sizeof(__be16);
279c04fecb4SDavid Teigland 			ls->ls_recover_dir_sent_msg++;
280e7fd4179SDavid Teigland 			goto out;
281e7fd4179SDavid Teigland 		}
282e7fd4179SDavid Teigland 
283e7fd4179SDavid Teigland 		be_namelen = cpu_to_be16(r->res_length);
284cd8e4679SHarvey Harrison 		memcpy(outbuf + offset, &be_namelen, sizeof(__be16));
285cd8e4679SHarvey Harrison 		offset += sizeof(__be16);
286e7fd4179SDavid Teigland 		memcpy(outbuf + offset, r->res_name, r->res_length);
287e7fd4179SDavid Teigland 		offset += r->res_length;
288c04fecb4SDavid Teigland 		ls->ls_recover_dir_sent_res++;
289e7fd4179SDavid Teigland 	}
290e7fd4179SDavid Teigland 
291e7fd4179SDavid Teigland 	/*
292e7fd4179SDavid Teigland 	 * If we've reached the end of the list (and there's room) write a
293e7fd4179SDavid Teigland 	 * terminating record.
294e7fd4179SDavid Teigland 	 */
295e7fd4179SDavid Teigland 
296e7fd4179SDavid Teigland 	if ((list == &ls->ls_root_list) &&
297e7fd4179SDavid Teigland 	    (offset + sizeof(uint16_t) <= outlen)) {
298cd8e4679SHarvey Harrison 		be_namelen = cpu_to_be16(0xFFFF);
299cd8e4679SHarvey Harrison 		memcpy(outbuf + offset, &be_namelen, sizeof(__be16));
300cd8e4679SHarvey Harrison 		offset += sizeof(__be16);
301c04fecb4SDavid Teigland 		ls->ls_recover_dir_sent_msg++;
302e7fd4179SDavid Teigland 	}
303e7fd4179SDavid Teigland  out:
304e7fd4179SDavid Teigland 	up_read(&ls->ls_root_sem);
305e7fd4179SDavid Teigland }
306e7fd4179SDavid Teigland 
307