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) 52573c24c4SDavid 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 214573c24c4SDavid 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 log_debug(ls, "dlm_recover_directory %d entries", count); 294e7fd4179SDavid Teigland out_free: 295e7fd4179SDavid Teigland kfree(last_name); 296e7fd4179SDavid Teigland out: 297e7fd4179SDavid Teigland dlm_clear_free_entries(ls); 298e7fd4179SDavid Teigland return error; 299e7fd4179SDavid Teigland } 300e7fd4179SDavid Teigland 301e7fd4179SDavid Teigland static int get_entry(struct dlm_ls *ls, int nodeid, char *name, 302e7fd4179SDavid Teigland int namelen, int *r_nodeid) 303e7fd4179SDavid Teigland { 304e7fd4179SDavid Teigland struct dlm_direntry *de, *tmp; 305e7fd4179SDavid Teigland uint32_t bucket; 306e7fd4179SDavid Teigland 307e7fd4179SDavid Teigland bucket = dir_hash(ls, name, namelen); 308e7fd4179SDavid Teigland 309305a47b1SSteven Whitehouse spin_lock(&ls->ls_dirtbl[bucket].lock); 310e7fd4179SDavid Teigland de = search_bucket(ls, name, namelen, bucket); 311e7fd4179SDavid Teigland if (de) { 312e7fd4179SDavid Teigland *r_nodeid = de->master_nodeid; 313305a47b1SSteven Whitehouse spin_unlock(&ls->ls_dirtbl[bucket].lock); 314e7fd4179SDavid Teigland if (*r_nodeid == nodeid) 315e7fd4179SDavid Teigland return -EEXIST; 316e7fd4179SDavid Teigland return 0; 317e7fd4179SDavid Teigland } 318e7fd4179SDavid Teigland 319305a47b1SSteven Whitehouse spin_unlock(&ls->ls_dirtbl[bucket].lock); 320e7fd4179SDavid Teigland 321043b19cdSAl Viro if (namelen > DLM_RESNAME_MAXLEN) 322043b19cdSAl Viro return -EINVAL; 323043b19cdSAl Viro 324573c24c4SDavid Teigland de = kzalloc(sizeof(struct dlm_direntry) + namelen, GFP_NOFS); 325e7fd4179SDavid Teigland if (!de) 326e7fd4179SDavid Teigland return -ENOMEM; 327e7fd4179SDavid Teigland 328e7fd4179SDavid Teigland de->master_nodeid = nodeid; 329e7fd4179SDavid Teigland de->length = namelen; 330e7fd4179SDavid Teigland memcpy(de->name, name, namelen); 331e7fd4179SDavid Teigland 332305a47b1SSteven Whitehouse spin_lock(&ls->ls_dirtbl[bucket].lock); 333e7fd4179SDavid Teigland tmp = search_bucket(ls, name, namelen, bucket); 334e7fd4179SDavid Teigland if (tmp) { 33552bda2b5SDavid Teigland kfree(de); 336e7fd4179SDavid Teigland de = tmp; 337e7fd4179SDavid Teigland } else { 338e7fd4179SDavid Teigland list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list); 339e7fd4179SDavid Teigland } 340e7fd4179SDavid Teigland *r_nodeid = de->master_nodeid; 341305a47b1SSteven Whitehouse spin_unlock(&ls->ls_dirtbl[bucket].lock); 342e7fd4179SDavid Teigland return 0; 343e7fd4179SDavid Teigland } 344e7fd4179SDavid Teigland 345e7fd4179SDavid Teigland int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen, 346e7fd4179SDavid Teigland int *r_nodeid) 347e7fd4179SDavid Teigland { 348e7fd4179SDavid Teigland return get_entry(ls, nodeid, name, namelen, r_nodeid); 349e7fd4179SDavid Teigland } 350e7fd4179SDavid Teigland 35185f0379aSDavid Teigland static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len) 35285f0379aSDavid Teigland { 35385f0379aSDavid Teigland struct dlm_rsb *r; 354*7210cb7aSDavid Teigland uint32_t hash, bucket; 355*7210cb7aSDavid Teigland int rv; 356*7210cb7aSDavid Teigland 357*7210cb7aSDavid Teigland hash = jhash(name, len, 0); 358*7210cb7aSDavid Teigland bucket = hash & (ls->ls_rsbtbl_size - 1); 359*7210cb7aSDavid Teigland 360*7210cb7aSDavid Teigland spin_lock(&ls->ls_rsbtbl[bucket].lock); 361*7210cb7aSDavid Teigland rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].keep, name, len, 0, &r); 362*7210cb7aSDavid Teigland if (rv) 363*7210cb7aSDavid Teigland rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].toss, 364*7210cb7aSDavid Teigland name, len, 0, &r); 365*7210cb7aSDavid Teigland spin_unlock(&ls->ls_rsbtbl[bucket].lock); 366*7210cb7aSDavid Teigland 367*7210cb7aSDavid Teigland if (!rv) 368*7210cb7aSDavid Teigland return r; 36985f0379aSDavid Teigland 37085f0379aSDavid Teigland down_read(&ls->ls_root_sem); 37185f0379aSDavid Teigland list_for_each_entry(r, &ls->ls_root_list, res_root_list) { 37285f0379aSDavid Teigland if (len == r->res_length && !memcmp(name, r->res_name, len)) { 37385f0379aSDavid Teigland up_read(&ls->ls_root_sem); 374*7210cb7aSDavid Teigland log_error(ls, "find_rsb_root revert to root_list %s", 375*7210cb7aSDavid Teigland r->res_name); 37685f0379aSDavid Teigland return r; 37785f0379aSDavid Teigland } 37885f0379aSDavid Teigland } 37985f0379aSDavid Teigland up_read(&ls->ls_root_sem); 38085f0379aSDavid Teigland return NULL; 38185f0379aSDavid Teigland } 38285f0379aSDavid Teigland 38385f0379aSDavid Teigland /* Find the rsb where we left off (or start again), then send rsb names 38485f0379aSDavid Teigland for rsb's we're master of and whose directory node matches the requesting 38585f0379aSDavid Teigland node. inbuf is the rsb name last sent, inlen is the name's length */ 386e7fd4179SDavid Teigland 387e7fd4179SDavid Teigland void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, 388e7fd4179SDavid Teigland char *outbuf, int outlen, int nodeid) 389e7fd4179SDavid Teigland { 390e7fd4179SDavid Teigland struct list_head *list; 39185f0379aSDavid Teigland struct dlm_rsb *r; 39285f0379aSDavid Teigland int offset = 0, dir_nodeid; 393cd8e4679SHarvey Harrison __be16 be_namelen; 394e7fd4179SDavid Teigland 395e7fd4179SDavid Teigland down_read(&ls->ls_root_sem); 39685f0379aSDavid Teigland 39785f0379aSDavid Teigland if (inlen > 1) { 39885f0379aSDavid Teigland r = find_rsb_root(ls, inbuf, inlen); 39985f0379aSDavid Teigland if (!r) { 40085f0379aSDavid Teigland inbuf[inlen - 1] = '\0'; 40185f0379aSDavid Teigland log_error(ls, "copy_master_names from %d start %d %s", 40285f0379aSDavid Teigland nodeid, inlen, inbuf); 40385f0379aSDavid Teigland goto out; 40485f0379aSDavid Teigland } 40585f0379aSDavid Teigland list = r->res_root_list.next; 40685f0379aSDavid Teigland } else { 407e7fd4179SDavid Teigland list = ls->ls_root_list.next; 40885f0379aSDavid Teigland } 409e7fd4179SDavid Teigland 410e7fd4179SDavid Teigland for (offset = 0; list != &ls->ls_root_list; list = list->next) { 411e7fd4179SDavid Teigland r = list_entry(list, struct dlm_rsb, res_root_list); 412e7fd4179SDavid Teigland if (r->res_nodeid) 413e7fd4179SDavid Teigland continue; 414e7fd4179SDavid Teigland 415e7fd4179SDavid Teigland dir_nodeid = dlm_dir_nodeid(r); 416e7fd4179SDavid Teigland if (dir_nodeid != nodeid) 417e7fd4179SDavid Teigland continue; 418e7fd4179SDavid Teigland 419e7fd4179SDavid Teigland /* 420e7fd4179SDavid Teigland * The block ends when we can't fit the following in the 421e7fd4179SDavid Teigland * remaining buffer space: 422e7fd4179SDavid Teigland * namelen (uint16_t) + 423e7fd4179SDavid Teigland * name (r->res_length) + 424e7fd4179SDavid Teigland * end-of-block record 0x0000 (uint16_t) 425e7fd4179SDavid Teigland */ 426e7fd4179SDavid Teigland 427e7fd4179SDavid Teigland if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) { 428e7fd4179SDavid Teigland /* Write end-of-block record */ 429cd8e4679SHarvey Harrison be_namelen = cpu_to_be16(0); 430cd8e4679SHarvey Harrison memcpy(outbuf + offset, &be_namelen, sizeof(__be16)); 431cd8e4679SHarvey Harrison offset += sizeof(__be16); 432e7fd4179SDavid Teigland goto out; 433e7fd4179SDavid Teigland } 434e7fd4179SDavid Teigland 435e7fd4179SDavid Teigland be_namelen = cpu_to_be16(r->res_length); 436cd8e4679SHarvey Harrison memcpy(outbuf + offset, &be_namelen, sizeof(__be16)); 437cd8e4679SHarvey Harrison offset += sizeof(__be16); 438e7fd4179SDavid Teigland memcpy(outbuf + offset, r->res_name, r->res_length); 439e7fd4179SDavid Teigland offset += r->res_length; 440e7fd4179SDavid Teigland } 441e7fd4179SDavid Teigland 442e7fd4179SDavid Teigland /* 443e7fd4179SDavid Teigland * If we've reached the end of the list (and there's room) write a 444e7fd4179SDavid Teigland * terminating record. 445e7fd4179SDavid Teigland */ 446e7fd4179SDavid Teigland 447e7fd4179SDavid Teigland if ((list == &ls->ls_root_list) && 448e7fd4179SDavid Teigland (offset + sizeof(uint16_t) <= outlen)) { 449cd8e4679SHarvey Harrison be_namelen = cpu_to_be16(0xFFFF); 450cd8e4679SHarvey Harrison memcpy(outbuf + offset, &be_namelen, sizeof(__be16)); 451cd8e4679SHarvey Harrison offset += sizeof(__be16); 452e7fd4179SDavid Teigland } 453e7fd4179SDavid Teigland 454e7fd4179SDavid Teigland out: 455e7fd4179SDavid Teigland up_read(&ls->ls_root_sem); 456e7fd4179SDavid Teigland } 457e7fd4179SDavid Teigland 458