xref: /openbmc/linux/fs/dlm/dir.c (revision 85f0379aa0f9366bb6918e2e898a915231176fbd)
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)
5252bda2b5SDavid Teigland 		de = kzalloc(sizeof(struct dlm_direntry) + len, GFP_KERNEL);
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 
159e7fd4179SDavid Teigland 	write_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:
176e7fd4179SDavid Teigland 	write_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++) {
188e7fd4179SDavid Teigland 		write_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 		}
195e7fd4179SDavid Teigland 		write_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 
214e7fd4179SDavid Teigland 	last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_KERNEL);
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 (;;) {
223e7fd4179SDavid Teigland 			error = dlm_recovery_stopped(ls);
224e7fd4179SDavid Teigland 			if (error)
225e7fd4179SDavid Teigland 				goto out_free;
226e7fd4179SDavid Teigland 
227e7fd4179SDavid Teigland 			error = dlm_rcom_names(ls, memb->nodeid,
228e7fd4179SDavid Teigland 					       last_name, last_len);
229e7fd4179SDavid Teigland 			if (error)
230e7fd4179SDavid Teigland 				goto out_free;
231e7fd4179SDavid Teigland 
232e7fd4179SDavid Teigland 			schedule();
233e7fd4179SDavid Teigland 
234e7fd4179SDavid Teigland 			/*
235e7fd4179SDavid Teigland 			 * pick namelen/name pairs out of received buffer
236e7fd4179SDavid Teigland 			 */
237e7fd4179SDavid Teigland 
238e7fd4179SDavid Teigland 			b = ls->ls_recover_buf + sizeof(struct dlm_rcom);
239e7fd4179SDavid Teigland 
240e7fd4179SDavid Teigland 			for (;;) {
241e7fd4179SDavid Teigland 				memcpy(&namelen, b, sizeof(uint16_t));
242e7fd4179SDavid Teigland 				namelen = be16_to_cpu(namelen);
243e7fd4179SDavid Teigland 				b += sizeof(uint16_t);
244e7fd4179SDavid Teigland 
245e7fd4179SDavid Teigland 				/* namelen of 0xFFFFF marks end of names for
246e7fd4179SDavid Teigland 				   this node; namelen of 0 marks end of the
247e7fd4179SDavid Teigland 				   buffer */
248e7fd4179SDavid Teigland 
249e7fd4179SDavid Teigland 				if (namelen == 0xFFFF)
250e7fd4179SDavid Teigland 					goto done;
251e7fd4179SDavid Teigland 				if (!namelen)
252e7fd4179SDavid Teigland 					break;
253e7fd4179SDavid Teigland 
254e7fd4179SDavid Teigland 				error = -ENOMEM;
255e7fd4179SDavid Teigland 				de = get_free_de(ls, namelen);
256e7fd4179SDavid Teigland 				if (!de)
257e7fd4179SDavid Teigland 					goto out_free;
258e7fd4179SDavid Teigland 
259e7fd4179SDavid Teigland 				de->master_nodeid = memb->nodeid;
260e7fd4179SDavid Teigland 				de->length = namelen;
261e7fd4179SDavid Teigland 				last_len = namelen;
262e7fd4179SDavid Teigland 				memcpy(de->name, b, namelen);
263e7fd4179SDavid Teigland 				memcpy(last_name, b, namelen);
264e7fd4179SDavid Teigland 				b += namelen;
265e7fd4179SDavid Teigland 
266e7fd4179SDavid Teigland 				add_entry_to_hash(ls, de);
267e7fd4179SDavid Teigland 				count++;
268e7fd4179SDavid Teigland 			}
269e7fd4179SDavid Teigland 		}
270e7fd4179SDavid Teigland          done:
271e7fd4179SDavid Teigland 		;
272e7fd4179SDavid Teigland 	}
273e7fd4179SDavid Teigland 
274e7fd4179SDavid Teigland  out_status:
275e7fd4179SDavid Teigland 	error = 0;
276e7fd4179SDavid Teigland 	dlm_set_recover_status(ls, DLM_RS_DIR);
277e7fd4179SDavid Teigland 	log_debug(ls, "dlm_recover_directory %d entries", count);
278e7fd4179SDavid Teigland  out_free:
279e7fd4179SDavid Teigland 	kfree(last_name);
280e7fd4179SDavid Teigland  out:
281e7fd4179SDavid Teigland 	dlm_clear_free_entries(ls);
282e7fd4179SDavid Teigland 	return error;
283e7fd4179SDavid Teigland }
284e7fd4179SDavid Teigland 
285e7fd4179SDavid Teigland static int get_entry(struct dlm_ls *ls, int nodeid, char *name,
286e7fd4179SDavid Teigland 		     int namelen, int *r_nodeid)
287e7fd4179SDavid Teigland {
288e7fd4179SDavid Teigland 	struct dlm_direntry *de, *tmp;
289e7fd4179SDavid Teigland 	uint32_t bucket;
290e7fd4179SDavid Teigland 
291e7fd4179SDavid Teigland 	bucket = dir_hash(ls, name, namelen);
292e7fd4179SDavid Teigland 
293e7fd4179SDavid Teigland 	write_lock(&ls->ls_dirtbl[bucket].lock);
294e7fd4179SDavid Teigland 	de = search_bucket(ls, name, namelen, bucket);
295e7fd4179SDavid Teigland 	if (de) {
296e7fd4179SDavid Teigland 		*r_nodeid = de->master_nodeid;
297e7fd4179SDavid Teigland 		write_unlock(&ls->ls_dirtbl[bucket].lock);
298e7fd4179SDavid Teigland 		if (*r_nodeid == nodeid)
299e7fd4179SDavid Teigland 			return -EEXIST;
300e7fd4179SDavid Teigland 		return 0;
301e7fd4179SDavid Teigland 	}
302e7fd4179SDavid Teigland 
303e7fd4179SDavid Teigland 	write_unlock(&ls->ls_dirtbl[bucket].lock);
304e7fd4179SDavid Teigland 
30552bda2b5SDavid Teigland 	de = kzalloc(sizeof(struct dlm_direntry) + namelen, GFP_KERNEL);
306e7fd4179SDavid Teigland 	if (!de)
307e7fd4179SDavid Teigland 		return -ENOMEM;
308e7fd4179SDavid Teigland 
309e7fd4179SDavid Teigland 	de->master_nodeid = nodeid;
310e7fd4179SDavid Teigland 	de->length = namelen;
311e7fd4179SDavid Teigland 	memcpy(de->name, name, namelen);
312e7fd4179SDavid Teigland 
313e7fd4179SDavid Teigland 	write_lock(&ls->ls_dirtbl[bucket].lock);
314e7fd4179SDavid Teigland 	tmp = search_bucket(ls, name, namelen, bucket);
315e7fd4179SDavid Teigland 	if (tmp) {
31652bda2b5SDavid Teigland 		kfree(de);
317e7fd4179SDavid Teigland 		de = tmp;
318e7fd4179SDavid Teigland 	} else {
319e7fd4179SDavid Teigland 		list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
320e7fd4179SDavid Teigland 	}
321e7fd4179SDavid Teigland 	*r_nodeid = de->master_nodeid;
322e7fd4179SDavid Teigland 	write_unlock(&ls->ls_dirtbl[bucket].lock);
323e7fd4179SDavid Teigland 	return 0;
324e7fd4179SDavid Teigland }
325e7fd4179SDavid Teigland 
326e7fd4179SDavid Teigland int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
327e7fd4179SDavid Teigland 		   int *r_nodeid)
328e7fd4179SDavid Teigland {
329e7fd4179SDavid Teigland 	return get_entry(ls, nodeid, name, namelen, r_nodeid);
330e7fd4179SDavid Teigland }
331e7fd4179SDavid Teigland 
332*85f0379aSDavid Teigland static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len)
333*85f0379aSDavid Teigland {
334*85f0379aSDavid Teigland 	struct dlm_rsb *r;
335*85f0379aSDavid Teigland 
336*85f0379aSDavid Teigland 	down_read(&ls->ls_root_sem);
337*85f0379aSDavid Teigland 	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
338*85f0379aSDavid Teigland 		if (len == r->res_length && !memcmp(name, r->res_name, len)) {
339*85f0379aSDavid Teigland 			up_read(&ls->ls_root_sem);
340*85f0379aSDavid Teigland 			return r;
341*85f0379aSDavid Teigland 		}
342*85f0379aSDavid Teigland 	}
343*85f0379aSDavid Teigland 	up_read(&ls->ls_root_sem);
344*85f0379aSDavid Teigland 	return NULL;
345*85f0379aSDavid Teigland }
346*85f0379aSDavid Teigland 
347*85f0379aSDavid Teigland /* Find the rsb where we left off (or start again), then send rsb names
348*85f0379aSDavid Teigland    for rsb's we're master of and whose directory node matches the requesting
349*85f0379aSDavid Teigland    node.  inbuf is the rsb name last sent, inlen is the name's length */
350e7fd4179SDavid Teigland 
351e7fd4179SDavid Teigland void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
352e7fd4179SDavid Teigland  			   char *outbuf, int outlen, int nodeid)
353e7fd4179SDavid Teigland {
354e7fd4179SDavid Teigland 	struct list_head *list;
355*85f0379aSDavid Teigland 	struct dlm_rsb *r;
356*85f0379aSDavid Teigland 	int offset = 0, dir_nodeid;
357e7fd4179SDavid Teigland 	uint16_t be_namelen;
358e7fd4179SDavid Teigland 
359e7fd4179SDavid Teigland 	down_read(&ls->ls_root_sem);
360*85f0379aSDavid Teigland 
361*85f0379aSDavid Teigland 	if (inlen > 1) {
362*85f0379aSDavid Teigland 		r = find_rsb_root(ls, inbuf, inlen);
363*85f0379aSDavid Teigland 		if (!r) {
364*85f0379aSDavid Teigland 			inbuf[inlen - 1] = '\0';
365*85f0379aSDavid Teigland 			log_error(ls, "copy_master_names from %d start %d %s",
366*85f0379aSDavid Teigland 				  nodeid, inlen, inbuf);
367*85f0379aSDavid Teigland 			goto out;
368*85f0379aSDavid Teigland 		}
369*85f0379aSDavid Teigland 		list = r->res_root_list.next;
370*85f0379aSDavid Teigland 	} else {
371e7fd4179SDavid Teigland 		list = ls->ls_root_list.next;
372*85f0379aSDavid Teigland 	}
373e7fd4179SDavid Teigland 
374e7fd4179SDavid Teigland 	for (offset = 0; list != &ls->ls_root_list; list = list->next) {
375e7fd4179SDavid Teigland 		r = list_entry(list, struct dlm_rsb, res_root_list);
376e7fd4179SDavid Teigland 		if (r->res_nodeid)
377e7fd4179SDavid Teigland 			continue;
378e7fd4179SDavid Teigland 
379e7fd4179SDavid Teigland 		dir_nodeid = dlm_dir_nodeid(r);
380e7fd4179SDavid Teigland 		if (dir_nodeid != nodeid)
381e7fd4179SDavid Teigland 			continue;
382e7fd4179SDavid Teigland 
383e7fd4179SDavid Teigland 		/*
384e7fd4179SDavid Teigland 		 * The block ends when we can't fit the following in the
385e7fd4179SDavid Teigland 		 * remaining buffer space:
386e7fd4179SDavid Teigland 		 * namelen (uint16_t) +
387e7fd4179SDavid Teigland 		 * name (r->res_length) +
388e7fd4179SDavid Teigland 		 * end-of-block record 0x0000 (uint16_t)
389e7fd4179SDavid Teigland 		 */
390e7fd4179SDavid Teigland 
391e7fd4179SDavid Teigland 		if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) {
392e7fd4179SDavid Teigland 			/* Write end-of-block record */
393e7fd4179SDavid Teigland 			be_namelen = 0;
394e7fd4179SDavid Teigland 			memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
395e7fd4179SDavid Teigland 			offset += sizeof(uint16_t);
396e7fd4179SDavid Teigland 			goto out;
397e7fd4179SDavid Teigland 		}
398e7fd4179SDavid Teigland 
399e7fd4179SDavid Teigland 		be_namelen = cpu_to_be16(r->res_length);
400e7fd4179SDavid Teigland 		memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
401e7fd4179SDavid Teigland 		offset += sizeof(uint16_t);
402e7fd4179SDavid Teigland 		memcpy(outbuf + offset, r->res_name, r->res_length);
403e7fd4179SDavid Teigland 		offset += r->res_length;
404e7fd4179SDavid Teigland 	}
405e7fd4179SDavid Teigland 
406e7fd4179SDavid Teigland 	/*
407e7fd4179SDavid Teigland 	 * If we've reached the end of the list (and there's room) write a
408e7fd4179SDavid Teigland 	 * terminating record.
409e7fd4179SDavid Teigland 	 */
410e7fd4179SDavid Teigland 
411e7fd4179SDavid Teigland 	if ((list == &ls->ls_root_list) &&
412e7fd4179SDavid Teigland 	    (offset + sizeof(uint16_t) <= outlen)) {
413e7fd4179SDavid Teigland 		be_namelen = 0xFFFF;
414e7fd4179SDavid Teigland 		memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
415e7fd4179SDavid Teigland 		offset += sizeof(uint16_t);
416e7fd4179SDavid Teigland 	}
417e7fd4179SDavid Teigland 
418e7fd4179SDavid Teigland  out:
419e7fd4179SDavid Teigland 	up_read(&ls->ls_root_sem);
420e7fd4179SDavid Teigland }
421e7fd4179SDavid Teigland 
422