xref: /openbmc/linux/fs/dlm/dir.c (revision 573c24c4af6664ffcd9aa7ba617a35fde2b95534)
1e7fd4179SDavid Teigland /******************************************************************************
2e7fd4179SDavid Teigland *******************************************************************************
3e7fd4179SDavid Teigland **
4e7fd4179SDavid Teigland **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
5e7fd4179SDavid Teigland **  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
6e7fd4179SDavid Teigland **
7e7fd4179SDavid Teigland **  This copyrighted material is made available to anyone wishing to use,
8e7fd4179SDavid Teigland **  modify, copy, or redistribute it subject to the terms and conditions
9e7fd4179SDavid Teigland **  of the GNU General Public License v.2.
10e7fd4179SDavid Teigland **
11e7fd4179SDavid Teigland *******************************************************************************
12e7fd4179SDavid Teigland ******************************************************************************/
13e7fd4179SDavid Teigland 
14e7fd4179SDavid Teigland #include "dlm_internal.h"
15e7fd4179SDavid Teigland #include "lockspace.h"
16e7fd4179SDavid Teigland #include "member.h"
17e7fd4179SDavid Teigland #include "lowcomms.h"
18e7fd4179SDavid Teigland #include "rcom.h"
19e7fd4179SDavid Teigland #include "config.h"
20e7fd4179SDavid Teigland #include "memory.h"
21e7fd4179SDavid Teigland #include "recover.h"
22e7fd4179SDavid Teigland #include "util.h"
23e7fd4179SDavid Teigland #include "lock.h"
24e7fd4179SDavid Teigland #include "dir.h"
25e7fd4179SDavid Teigland 
26e7fd4179SDavid Teigland 
27e7fd4179SDavid Teigland static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de)
28e7fd4179SDavid Teigland {
29e7fd4179SDavid Teigland 	spin_lock(&ls->ls_recover_list_lock);
30e7fd4179SDavid Teigland 	list_add(&de->list, &ls->ls_recover_list);
31e7fd4179SDavid Teigland 	spin_unlock(&ls->ls_recover_list_lock);
32e7fd4179SDavid Teigland }
33e7fd4179SDavid Teigland 
34e7fd4179SDavid Teigland static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len)
35e7fd4179SDavid Teigland {
3690135925SDavid Teigland 	int found = 0;
37e7fd4179SDavid Teigland 	struct dlm_direntry *de;
38e7fd4179SDavid Teigland 
39e7fd4179SDavid Teigland 	spin_lock(&ls->ls_recover_list_lock);
40e7fd4179SDavid Teigland 	list_for_each_entry(de, &ls->ls_recover_list, list) {
41e7fd4179SDavid Teigland 		if (de->length == len) {
42e7fd4179SDavid Teigland 			list_del(&de->list);
43e7fd4179SDavid Teigland 			de->master_nodeid = 0;
44e7fd4179SDavid Teigland 			memset(de->name, 0, len);
4590135925SDavid Teigland 			found = 1;
46e7fd4179SDavid Teigland 			break;
47e7fd4179SDavid Teigland 		}
48e7fd4179SDavid Teigland 	}
49e7fd4179SDavid Teigland 	spin_unlock(&ls->ls_recover_list_lock);
50e7fd4179SDavid Teigland 
51e7fd4179SDavid Teigland 	if (!found)
52*573c24c4SDavid Teigland 		de = kzalloc(sizeof(struct dlm_direntry) + len, GFP_NOFS);
53e7fd4179SDavid Teigland 	return de;
54e7fd4179SDavid Teigland }
55e7fd4179SDavid Teigland 
56e7fd4179SDavid Teigland void dlm_clear_free_entries(struct dlm_ls *ls)
57e7fd4179SDavid Teigland {
58e7fd4179SDavid Teigland 	struct dlm_direntry *de;
59e7fd4179SDavid Teigland 
60e7fd4179SDavid Teigland 	spin_lock(&ls->ls_recover_list_lock);
61e7fd4179SDavid Teigland 	while (!list_empty(&ls->ls_recover_list)) {
62e7fd4179SDavid Teigland 		de = list_entry(ls->ls_recover_list.next, struct dlm_direntry,
63e7fd4179SDavid Teigland 				list);
64e7fd4179SDavid Teigland 		list_del(&de->list);
6552bda2b5SDavid Teigland 		kfree(de);
66e7fd4179SDavid Teigland 	}
67e7fd4179SDavid Teigland 	spin_unlock(&ls->ls_recover_list_lock);
68e7fd4179SDavid Teigland }
69e7fd4179SDavid Teigland 
70e7fd4179SDavid Teigland /*
71e7fd4179SDavid Teigland  * We use the upper 16 bits of the hash value to select the directory node.
72e7fd4179SDavid Teigland  * Low bits are used for distribution of rsb's among hash buckets on each node.
73e7fd4179SDavid Teigland  *
74e7fd4179SDavid Teigland  * To give the exact range wanted (0 to num_nodes-1), we apply a modulus of
75e7fd4179SDavid Teigland  * num_nodes to the hash value.  This value in the desired range is used as an
76e7fd4179SDavid Teigland  * offset into the sorted list of nodeid's to give the particular nodeid.
77e7fd4179SDavid Teigland  */
78e7fd4179SDavid Teigland 
79e7fd4179SDavid Teigland int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash)
80e7fd4179SDavid Teigland {
81e7fd4179SDavid Teigland 	struct list_head *tmp;
82e7fd4179SDavid Teigland 	struct dlm_member *memb = NULL;
83e7fd4179SDavid Teigland 	uint32_t node, n = 0;
84e7fd4179SDavid Teigland 	int nodeid;
85e7fd4179SDavid Teigland 
86e7fd4179SDavid Teigland 	if (ls->ls_num_nodes == 1) {
87e7fd4179SDavid Teigland 		nodeid = dlm_our_nodeid();
88e7fd4179SDavid Teigland 		goto out;
89e7fd4179SDavid Teigland 	}
90e7fd4179SDavid Teigland 
91e7fd4179SDavid Teigland 	if (ls->ls_node_array) {
92e7fd4179SDavid Teigland 		node = (hash >> 16) % ls->ls_total_weight;
93e7fd4179SDavid Teigland 		nodeid = ls->ls_node_array[node];
94e7fd4179SDavid Teigland 		goto out;
95e7fd4179SDavid Teigland 	}
96e7fd4179SDavid Teigland 
97e7fd4179SDavid Teigland 	/* make_member_array() failed to kmalloc ls_node_array... */
98e7fd4179SDavid Teigland 
99e7fd4179SDavid Teigland 	node = (hash >> 16) % ls->ls_num_nodes;
100e7fd4179SDavid Teigland 
101e7fd4179SDavid Teigland 	list_for_each(tmp, &ls->ls_nodes) {
102e7fd4179SDavid Teigland 		if (n++ != node)
103e7fd4179SDavid Teigland 			continue;
104e7fd4179SDavid Teigland 		memb = list_entry(tmp, struct dlm_member, list);
105e7fd4179SDavid Teigland 		break;
106e7fd4179SDavid Teigland 	}
107e7fd4179SDavid Teigland 
108e7fd4179SDavid Teigland 	DLM_ASSERT(memb , printk("num_nodes=%u n=%u node=%u\n",
109e7fd4179SDavid Teigland 				 ls->ls_num_nodes, n, node););
110e7fd4179SDavid Teigland 	nodeid = memb->nodeid;
111e7fd4179SDavid Teigland  out:
112e7fd4179SDavid Teigland 	return nodeid;
113e7fd4179SDavid Teigland }
114e7fd4179SDavid Teigland 
115e7fd4179SDavid Teigland int dlm_dir_nodeid(struct dlm_rsb *r)
116e7fd4179SDavid Teigland {
117e7fd4179SDavid Teigland 	return dlm_hash2nodeid(r->res_ls, r->res_hash);
118e7fd4179SDavid Teigland }
119e7fd4179SDavid Teigland 
120e7fd4179SDavid Teigland static inline uint32_t dir_hash(struct dlm_ls *ls, char *name, int len)
121e7fd4179SDavid Teigland {
122e7fd4179SDavid Teigland 	uint32_t val;
123e7fd4179SDavid Teigland 
124e7fd4179SDavid Teigland 	val = jhash(name, len, 0);
125e7fd4179SDavid Teigland 	val &= (ls->ls_dirtbl_size - 1);
126e7fd4179SDavid Teigland 
127e7fd4179SDavid Teigland 	return val;
128e7fd4179SDavid Teigland }
129e7fd4179SDavid Teigland 
130e7fd4179SDavid Teigland static void add_entry_to_hash(struct dlm_ls *ls, struct dlm_direntry *de)
131e7fd4179SDavid Teigland {
132e7fd4179SDavid Teigland 	uint32_t bucket;
133e7fd4179SDavid Teigland 
134e7fd4179SDavid Teigland 	bucket = dir_hash(ls, de->name, de->length);
135e7fd4179SDavid Teigland 	list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
136e7fd4179SDavid Teigland }
137e7fd4179SDavid Teigland 
138e7fd4179SDavid Teigland static struct dlm_direntry *search_bucket(struct dlm_ls *ls, char *name,
139e7fd4179SDavid Teigland 					  int namelen, uint32_t bucket)
140e7fd4179SDavid Teigland {
141e7fd4179SDavid Teigland 	struct dlm_direntry *de;
142e7fd4179SDavid Teigland 
143e7fd4179SDavid Teigland 	list_for_each_entry(de, &ls->ls_dirtbl[bucket].list, list) {
144e7fd4179SDavid Teigland 		if (de->length == namelen && !memcmp(name, de->name, namelen))
145e7fd4179SDavid Teigland 			goto out;
146e7fd4179SDavid Teigland 	}
147e7fd4179SDavid Teigland 	de = NULL;
148e7fd4179SDavid Teigland  out:
149e7fd4179SDavid Teigland 	return de;
150e7fd4179SDavid Teigland }
151e7fd4179SDavid Teigland 
152e7fd4179SDavid Teigland void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen)
153e7fd4179SDavid Teigland {
154e7fd4179SDavid Teigland 	struct dlm_direntry *de;
155e7fd4179SDavid Teigland 	uint32_t bucket;
156e7fd4179SDavid Teigland 
157e7fd4179SDavid Teigland 	bucket = dir_hash(ls, name, namelen);
158e7fd4179SDavid Teigland 
159305a47b1SSteven Whitehouse 	spin_lock(&ls->ls_dirtbl[bucket].lock);
160e7fd4179SDavid Teigland 
161e7fd4179SDavid Teigland 	de = search_bucket(ls, name, namelen, bucket);
162e7fd4179SDavid Teigland 
163e7fd4179SDavid Teigland 	if (!de) {
164e7fd4179SDavid Teigland 		log_error(ls, "remove fr %u none", nodeid);
165e7fd4179SDavid Teigland 		goto out;
166e7fd4179SDavid Teigland 	}
167e7fd4179SDavid Teigland 
168e7fd4179SDavid Teigland 	if (de->master_nodeid != nodeid) {
169e7fd4179SDavid Teigland 		log_error(ls, "remove fr %u ID %u", nodeid, de->master_nodeid);
170e7fd4179SDavid Teigland 		goto out;
171e7fd4179SDavid Teigland 	}
172e7fd4179SDavid Teigland 
173e7fd4179SDavid Teigland 	list_del(&de->list);
17452bda2b5SDavid Teigland 	kfree(de);
175e7fd4179SDavid Teigland  out:
176305a47b1SSteven Whitehouse 	spin_unlock(&ls->ls_dirtbl[bucket].lock);
177e7fd4179SDavid Teigland }
178e7fd4179SDavid Teigland 
179e7fd4179SDavid Teigland void dlm_dir_clear(struct dlm_ls *ls)
180e7fd4179SDavid Teigland {
181e7fd4179SDavid Teigland 	struct list_head *head;
182e7fd4179SDavid Teigland 	struct dlm_direntry *de;
183e7fd4179SDavid Teigland 	int i;
184e7fd4179SDavid Teigland 
185e7fd4179SDavid Teigland 	DLM_ASSERT(list_empty(&ls->ls_recover_list), );
186e7fd4179SDavid Teigland 
187e7fd4179SDavid Teigland 	for (i = 0; i < ls->ls_dirtbl_size; i++) {
188305a47b1SSteven Whitehouse 		spin_lock(&ls->ls_dirtbl[i].lock);
189e7fd4179SDavid Teigland 		head = &ls->ls_dirtbl[i].list;
190e7fd4179SDavid Teigland 		while (!list_empty(head)) {
191e7fd4179SDavid Teigland 			de = list_entry(head->next, struct dlm_direntry, list);
192e7fd4179SDavid Teigland 			list_del(&de->list);
193e7fd4179SDavid Teigland 			put_free_de(ls, de);
194e7fd4179SDavid Teigland 		}
195305a47b1SSteven Whitehouse 		spin_unlock(&ls->ls_dirtbl[i].lock);
196e7fd4179SDavid Teigland 	}
197e7fd4179SDavid Teigland }
198e7fd4179SDavid Teigland 
199e7fd4179SDavid Teigland int dlm_recover_directory(struct dlm_ls *ls)
200e7fd4179SDavid Teigland {
201e7fd4179SDavid Teigland 	struct dlm_member *memb;
202e7fd4179SDavid Teigland 	struct dlm_direntry *de;
203e7fd4179SDavid Teigland 	char *b, *last_name = NULL;
204e7fd4179SDavid Teigland 	int error = -ENOMEM, last_len, count = 0;
205e7fd4179SDavid Teigland 	uint16_t namelen;
206e7fd4179SDavid Teigland 
207e7fd4179SDavid Teigland 	log_debug(ls, "dlm_recover_directory");
208e7fd4179SDavid Teigland 
209e7fd4179SDavid Teigland 	if (dlm_no_directory(ls))
210e7fd4179SDavid Teigland 		goto out_status;
211e7fd4179SDavid Teigland 
212e7fd4179SDavid Teigland 	dlm_dir_clear(ls);
213e7fd4179SDavid Teigland 
214*573c24c4SDavid Teigland 	last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_NOFS);
215e7fd4179SDavid Teigland 	if (!last_name)
216e7fd4179SDavid Teigland 		goto out;
217e7fd4179SDavid Teigland 
218e7fd4179SDavid Teigland 	list_for_each_entry(memb, &ls->ls_nodes, list) {
219e7fd4179SDavid Teigland 		memset(last_name, 0, DLM_RESNAME_MAXLEN);
220e7fd4179SDavid Teigland 		last_len = 0;
221e7fd4179SDavid Teigland 
222e7fd4179SDavid Teigland 		for (;;) {
223cd9df1aaSAl Viro 			int left;
224e7fd4179SDavid Teigland 			error = dlm_recovery_stopped(ls);
225e7fd4179SDavid Teigland 			if (error)
226e7fd4179SDavid Teigland 				goto out_free;
227e7fd4179SDavid Teigland 
228e7fd4179SDavid Teigland 			error = dlm_rcom_names(ls, memb->nodeid,
229e7fd4179SDavid Teigland 					       last_name, last_len);
230e7fd4179SDavid Teigland 			if (error)
231e7fd4179SDavid Teigland 				goto out_free;
232e7fd4179SDavid Teigland 
233e7fd4179SDavid Teigland 			schedule();
234e7fd4179SDavid Teigland 
235e7fd4179SDavid Teigland 			/*
236e7fd4179SDavid Teigland 			 * pick namelen/name pairs out of received buffer
237e7fd4179SDavid Teigland 			 */
238e7fd4179SDavid Teigland 
2394007685cSAl Viro 			b = ls->ls_recover_buf->rc_buf;
240cd9df1aaSAl Viro 			left = ls->ls_recover_buf->rc_header.h_length;
241cd9df1aaSAl Viro 			left -= sizeof(struct dlm_rcom);
242e7fd4179SDavid Teigland 
243e7fd4179SDavid Teigland 			for (;;) {
244cd9df1aaSAl Viro 				__be16 v;
245cd9df1aaSAl Viro 
246cd9df1aaSAl Viro 				error = -EINVAL;
247cd9df1aaSAl Viro 				if (left < sizeof(__be16))
248cd9df1aaSAl Viro 					goto out_free;
249cd9df1aaSAl Viro 
250cd9df1aaSAl Viro 				memcpy(&v, b, sizeof(__be16));
251cd9df1aaSAl Viro 				namelen = be16_to_cpu(v);
252cd9df1aaSAl Viro 				b += sizeof(__be16);
253cd9df1aaSAl Viro 				left -= sizeof(__be16);
254e7fd4179SDavid Teigland 
255e7fd4179SDavid Teigland 				/* namelen of 0xFFFFF marks end of names for
256e7fd4179SDavid Teigland 				   this node; namelen of 0 marks end of the
257e7fd4179SDavid Teigland 				   buffer */
258e7fd4179SDavid Teigland 
259e7fd4179SDavid Teigland 				if (namelen == 0xFFFF)
260e7fd4179SDavid Teigland 					goto done;
261e7fd4179SDavid Teigland 				if (!namelen)
262e7fd4179SDavid Teigland 					break;
263e7fd4179SDavid Teigland 
264cd9df1aaSAl Viro 				if (namelen > left)
265cd9df1aaSAl Viro 					goto out_free;
266cd9df1aaSAl Viro 
267cd9df1aaSAl Viro 				if (namelen > DLM_RESNAME_MAXLEN)
268cd9df1aaSAl Viro 					goto out_free;
269cd9df1aaSAl Viro 
270e7fd4179SDavid Teigland 				error = -ENOMEM;
271e7fd4179SDavid Teigland 				de = get_free_de(ls, namelen);
272e7fd4179SDavid Teigland 				if (!de)
273e7fd4179SDavid Teigland 					goto out_free;
274e7fd4179SDavid Teigland 
275e7fd4179SDavid Teigland 				de->master_nodeid = memb->nodeid;
276e7fd4179SDavid Teigland 				de->length = namelen;
277e7fd4179SDavid Teigland 				last_len = namelen;
278e7fd4179SDavid Teigland 				memcpy(de->name, b, namelen);
279e7fd4179SDavid Teigland 				memcpy(last_name, b, namelen);
280e7fd4179SDavid Teigland 				b += namelen;
281cd9df1aaSAl Viro 				left -= namelen;
282e7fd4179SDavid Teigland 
283e7fd4179SDavid Teigland 				add_entry_to_hash(ls, de);
284e7fd4179SDavid Teigland 				count++;
285e7fd4179SDavid Teigland 			}
286e7fd4179SDavid Teigland 		}
287e7fd4179SDavid Teigland          done:
288e7fd4179SDavid Teigland 		;
289e7fd4179SDavid Teigland 	}
290e7fd4179SDavid Teigland 
291e7fd4179SDavid Teigland  out_status:
292e7fd4179SDavid Teigland 	error = 0;
293e7fd4179SDavid Teigland 	dlm_set_recover_status(ls, DLM_RS_DIR);
294e7fd4179SDavid Teigland 	log_debug(ls, "dlm_recover_directory %d entries", count);
295e7fd4179SDavid Teigland  out_free:
296e7fd4179SDavid Teigland 	kfree(last_name);
297e7fd4179SDavid Teigland  out:
298e7fd4179SDavid Teigland 	dlm_clear_free_entries(ls);
299e7fd4179SDavid Teigland 	return error;
300e7fd4179SDavid Teigland }
301e7fd4179SDavid Teigland 
302e7fd4179SDavid Teigland static int get_entry(struct dlm_ls *ls, int nodeid, char *name,
303e7fd4179SDavid Teigland 		     int namelen, int *r_nodeid)
304e7fd4179SDavid Teigland {
305e7fd4179SDavid Teigland 	struct dlm_direntry *de, *tmp;
306e7fd4179SDavid Teigland 	uint32_t bucket;
307e7fd4179SDavid Teigland 
308e7fd4179SDavid Teigland 	bucket = dir_hash(ls, name, namelen);
309e7fd4179SDavid Teigland 
310305a47b1SSteven Whitehouse 	spin_lock(&ls->ls_dirtbl[bucket].lock);
311e7fd4179SDavid Teigland 	de = search_bucket(ls, name, namelen, bucket);
312e7fd4179SDavid Teigland 	if (de) {
313e7fd4179SDavid Teigland 		*r_nodeid = de->master_nodeid;
314305a47b1SSteven Whitehouse 		spin_unlock(&ls->ls_dirtbl[bucket].lock);
315e7fd4179SDavid Teigland 		if (*r_nodeid == nodeid)
316e7fd4179SDavid Teigland 			return -EEXIST;
317e7fd4179SDavid Teigland 		return 0;
318e7fd4179SDavid Teigland 	}
319e7fd4179SDavid Teigland 
320305a47b1SSteven Whitehouse 	spin_unlock(&ls->ls_dirtbl[bucket].lock);
321e7fd4179SDavid Teigland 
322043b19cdSAl Viro 	if (namelen > DLM_RESNAME_MAXLEN)
323043b19cdSAl Viro 		return -EINVAL;
324043b19cdSAl Viro 
325*573c24c4SDavid Teigland 	de = kzalloc(sizeof(struct dlm_direntry) + namelen, GFP_NOFS);
326e7fd4179SDavid Teigland 	if (!de)
327e7fd4179SDavid Teigland 		return -ENOMEM;
328e7fd4179SDavid Teigland 
329e7fd4179SDavid Teigland 	de->master_nodeid = nodeid;
330e7fd4179SDavid Teigland 	de->length = namelen;
331e7fd4179SDavid Teigland 	memcpy(de->name, name, namelen);
332e7fd4179SDavid Teigland 
333305a47b1SSteven Whitehouse 	spin_lock(&ls->ls_dirtbl[bucket].lock);
334e7fd4179SDavid Teigland 	tmp = search_bucket(ls, name, namelen, bucket);
335e7fd4179SDavid Teigland 	if (tmp) {
33652bda2b5SDavid Teigland 		kfree(de);
337e7fd4179SDavid Teigland 		de = tmp;
338e7fd4179SDavid Teigland 	} else {
339e7fd4179SDavid Teigland 		list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
340e7fd4179SDavid Teigland 	}
341e7fd4179SDavid Teigland 	*r_nodeid = de->master_nodeid;
342305a47b1SSteven Whitehouse 	spin_unlock(&ls->ls_dirtbl[bucket].lock);
343e7fd4179SDavid Teigland 	return 0;
344e7fd4179SDavid Teigland }
345e7fd4179SDavid Teigland 
346e7fd4179SDavid Teigland int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
347e7fd4179SDavid Teigland 		   int *r_nodeid)
348e7fd4179SDavid Teigland {
349e7fd4179SDavid Teigland 	return get_entry(ls, nodeid, name, namelen, r_nodeid);
350e7fd4179SDavid Teigland }
351e7fd4179SDavid Teigland 
35285f0379aSDavid Teigland static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len)
35385f0379aSDavid Teigland {
35485f0379aSDavid Teigland 	struct dlm_rsb *r;
35585f0379aSDavid Teigland 
35685f0379aSDavid Teigland 	down_read(&ls->ls_root_sem);
35785f0379aSDavid Teigland 	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
35885f0379aSDavid Teigland 		if (len == r->res_length && !memcmp(name, r->res_name, len)) {
35985f0379aSDavid Teigland 			up_read(&ls->ls_root_sem);
36085f0379aSDavid Teigland 			return r;
36185f0379aSDavid Teigland 		}
36285f0379aSDavid Teigland 	}
36385f0379aSDavid Teigland 	up_read(&ls->ls_root_sem);
36485f0379aSDavid Teigland 	return NULL;
36585f0379aSDavid Teigland }
36685f0379aSDavid Teigland 
36785f0379aSDavid Teigland /* Find the rsb where we left off (or start again), then send rsb names
36885f0379aSDavid Teigland    for rsb's we're master of and whose directory node matches the requesting
36985f0379aSDavid Teigland    node.  inbuf is the rsb name last sent, inlen is the name's length */
370e7fd4179SDavid Teigland 
371e7fd4179SDavid Teigland void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
372e7fd4179SDavid Teigland  			   char *outbuf, int outlen, int nodeid)
373e7fd4179SDavid Teigland {
374e7fd4179SDavid Teigland 	struct list_head *list;
37585f0379aSDavid Teigland 	struct dlm_rsb *r;
37685f0379aSDavid Teigland 	int offset = 0, dir_nodeid;
377cd8e4679SHarvey Harrison 	__be16 be_namelen;
378e7fd4179SDavid Teigland 
379e7fd4179SDavid Teigland 	down_read(&ls->ls_root_sem);
38085f0379aSDavid Teigland 
38185f0379aSDavid Teigland 	if (inlen > 1) {
38285f0379aSDavid Teigland 		r = find_rsb_root(ls, inbuf, inlen);
38385f0379aSDavid Teigland 		if (!r) {
38485f0379aSDavid Teigland 			inbuf[inlen - 1] = '\0';
38585f0379aSDavid Teigland 			log_error(ls, "copy_master_names from %d start %d %s",
38685f0379aSDavid Teigland 				  nodeid, inlen, inbuf);
38785f0379aSDavid Teigland 			goto out;
38885f0379aSDavid Teigland 		}
38985f0379aSDavid Teigland 		list = r->res_root_list.next;
39085f0379aSDavid Teigland 	} else {
391e7fd4179SDavid Teigland 		list = ls->ls_root_list.next;
39285f0379aSDavid Teigland 	}
393e7fd4179SDavid Teigland 
394e7fd4179SDavid Teigland 	for (offset = 0; list != &ls->ls_root_list; list = list->next) {
395e7fd4179SDavid Teigland 		r = list_entry(list, struct dlm_rsb, res_root_list);
396e7fd4179SDavid Teigland 		if (r->res_nodeid)
397e7fd4179SDavid Teigland 			continue;
398e7fd4179SDavid Teigland 
399e7fd4179SDavid Teigland 		dir_nodeid = dlm_dir_nodeid(r);
400e7fd4179SDavid Teigland 		if (dir_nodeid != nodeid)
401e7fd4179SDavid Teigland 			continue;
402e7fd4179SDavid Teigland 
403e7fd4179SDavid Teigland 		/*
404e7fd4179SDavid Teigland 		 * The block ends when we can't fit the following in the
405e7fd4179SDavid Teigland 		 * remaining buffer space:
406e7fd4179SDavid Teigland 		 * namelen (uint16_t) +
407e7fd4179SDavid Teigland 		 * name (r->res_length) +
408e7fd4179SDavid Teigland 		 * end-of-block record 0x0000 (uint16_t)
409e7fd4179SDavid Teigland 		 */
410e7fd4179SDavid Teigland 
411e7fd4179SDavid Teigland 		if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) {
412e7fd4179SDavid Teigland 			/* Write end-of-block record */
413cd8e4679SHarvey Harrison 			be_namelen = cpu_to_be16(0);
414cd8e4679SHarvey Harrison 			memcpy(outbuf + offset, &be_namelen, sizeof(__be16));
415cd8e4679SHarvey Harrison 			offset += sizeof(__be16);
416e7fd4179SDavid Teigland 			goto out;
417e7fd4179SDavid Teigland 		}
418e7fd4179SDavid Teigland 
419e7fd4179SDavid Teigland 		be_namelen = cpu_to_be16(r->res_length);
420cd8e4679SHarvey Harrison 		memcpy(outbuf + offset, &be_namelen, sizeof(__be16));
421cd8e4679SHarvey Harrison 		offset += sizeof(__be16);
422e7fd4179SDavid Teigland 		memcpy(outbuf + offset, r->res_name, r->res_length);
423e7fd4179SDavid Teigland 		offset += r->res_length;
424e7fd4179SDavid Teigland 	}
425e7fd4179SDavid Teigland 
426e7fd4179SDavid Teigland 	/*
427e7fd4179SDavid Teigland 	 * If we've reached the end of the list (and there's room) write a
428e7fd4179SDavid Teigland 	 * terminating record.
429e7fd4179SDavid Teigland 	 */
430e7fd4179SDavid Teigland 
431e7fd4179SDavid Teigland 	if ((list == &ls->ls_root_list) &&
432e7fd4179SDavid Teigland 	    (offset + sizeof(uint16_t) <= outlen)) {
433cd8e4679SHarvey Harrison 		be_namelen = cpu_to_be16(0xFFFF);
434cd8e4679SHarvey Harrison 		memcpy(outbuf + offset, &be_namelen, sizeof(__be16));
435cd8e4679SHarvey Harrison 		offset += sizeof(__be16);
436e7fd4179SDavid Teigland 	}
437e7fd4179SDavid Teigland 
438e7fd4179SDavid Teigland  out:
439e7fd4179SDavid Teigland 	up_read(&ls->ls_root_sem);
440e7fd4179SDavid Teigland }
441e7fd4179SDavid Teigland 
442