1*e7fd4179SDavid Teigland /****************************************************************************** 2*e7fd4179SDavid Teigland ******************************************************************************* 3*e7fd4179SDavid Teigland ** 4*e7fd4179SDavid Teigland ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. 5*e7fd4179SDavid Teigland ** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. 6*e7fd4179SDavid Teigland ** 7*e7fd4179SDavid Teigland ** This copyrighted material is made available to anyone wishing to use, 8*e7fd4179SDavid Teigland ** modify, copy, or redistribute it subject to the terms and conditions 9*e7fd4179SDavid Teigland ** of the GNU General Public License v.2. 10*e7fd4179SDavid Teigland ** 11*e7fd4179SDavid Teigland ******************************************************************************* 12*e7fd4179SDavid Teigland ******************************************************************************/ 13*e7fd4179SDavid Teigland 14*e7fd4179SDavid Teigland #include "dlm_internal.h" 15*e7fd4179SDavid Teigland #include "lockspace.h" 16*e7fd4179SDavid Teigland #include "member.h" 17*e7fd4179SDavid Teigland #include "lowcomms.h" 18*e7fd4179SDavid Teigland #include "rcom.h" 19*e7fd4179SDavid Teigland #include "config.h" 20*e7fd4179SDavid Teigland #include "memory.h" 21*e7fd4179SDavid Teigland #include "recover.h" 22*e7fd4179SDavid Teigland #include "util.h" 23*e7fd4179SDavid Teigland #include "lock.h" 24*e7fd4179SDavid Teigland #include "dir.h" 25*e7fd4179SDavid Teigland 26*e7fd4179SDavid Teigland 27*e7fd4179SDavid Teigland static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de) 28*e7fd4179SDavid Teigland { 29*e7fd4179SDavid Teigland spin_lock(&ls->ls_recover_list_lock); 30*e7fd4179SDavid Teigland list_add(&de->list, &ls->ls_recover_list); 31*e7fd4179SDavid Teigland spin_unlock(&ls->ls_recover_list_lock); 32*e7fd4179SDavid Teigland } 33*e7fd4179SDavid Teigland 34*e7fd4179SDavid Teigland static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len) 35*e7fd4179SDavid Teigland { 36*e7fd4179SDavid Teigland int found = FALSE; 37*e7fd4179SDavid Teigland struct dlm_direntry *de; 38*e7fd4179SDavid Teigland 39*e7fd4179SDavid Teigland spin_lock(&ls->ls_recover_list_lock); 40*e7fd4179SDavid Teigland list_for_each_entry(de, &ls->ls_recover_list, list) { 41*e7fd4179SDavid Teigland if (de->length == len) { 42*e7fd4179SDavid Teigland list_del(&de->list); 43*e7fd4179SDavid Teigland de->master_nodeid = 0; 44*e7fd4179SDavid Teigland memset(de->name, 0, len); 45*e7fd4179SDavid Teigland found = TRUE; 46*e7fd4179SDavid Teigland break; 47*e7fd4179SDavid Teigland } 48*e7fd4179SDavid Teigland } 49*e7fd4179SDavid Teigland spin_unlock(&ls->ls_recover_list_lock); 50*e7fd4179SDavid Teigland 51*e7fd4179SDavid Teigland if (!found) 52*e7fd4179SDavid Teigland de = allocate_direntry(ls, len); 53*e7fd4179SDavid Teigland return de; 54*e7fd4179SDavid Teigland } 55*e7fd4179SDavid Teigland 56*e7fd4179SDavid Teigland void dlm_clear_free_entries(struct dlm_ls *ls) 57*e7fd4179SDavid Teigland { 58*e7fd4179SDavid Teigland struct dlm_direntry *de; 59*e7fd4179SDavid Teigland 60*e7fd4179SDavid Teigland spin_lock(&ls->ls_recover_list_lock); 61*e7fd4179SDavid Teigland while (!list_empty(&ls->ls_recover_list)) { 62*e7fd4179SDavid Teigland de = list_entry(ls->ls_recover_list.next, struct dlm_direntry, 63*e7fd4179SDavid Teigland list); 64*e7fd4179SDavid Teigland list_del(&de->list); 65*e7fd4179SDavid Teigland free_direntry(de); 66*e7fd4179SDavid Teigland } 67*e7fd4179SDavid Teigland spin_unlock(&ls->ls_recover_list_lock); 68*e7fd4179SDavid Teigland } 69*e7fd4179SDavid Teigland 70*e7fd4179SDavid Teigland /* 71*e7fd4179SDavid Teigland * We use the upper 16 bits of the hash value to select the directory node. 72*e7fd4179SDavid Teigland * Low bits are used for distribution of rsb's among hash buckets on each node. 73*e7fd4179SDavid Teigland * 74*e7fd4179SDavid Teigland * To give the exact range wanted (0 to num_nodes-1), we apply a modulus of 75*e7fd4179SDavid Teigland * num_nodes to the hash value. This value in the desired range is used as an 76*e7fd4179SDavid Teigland * offset into the sorted list of nodeid's to give the particular nodeid. 77*e7fd4179SDavid Teigland */ 78*e7fd4179SDavid Teigland 79*e7fd4179SDavid Teigland int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash) 80*e7fd4179SDavid Teigland { 81*e7fd4179SDavid Teigland struct list_head *tmp; 82*e7fd4179SDavid Teigland struct dlm_member *memb = NULL; 83*e7fd4179SDavid Teigland uint32_t node, n = 0; 84*e7fd4179SDavid Teigland int nodeid; 85*e7fd4179SDavid Teigland 86*e7fd4179SDavid Teigland if (ls->ls_num_nodes == 1) { 87*e7fd4179SDavid Teigland nodeid = dlm_our_nodeid(); 88*e7fd4179SDavid Teigland goto out; 89*e7fd4179SDavid Teigland } 90*e7fd4179SDavid Teigland 91*e7fd4179SDavid Teigland if (ls->ls_node_array) { 92*e7fd4179SDavid Teigland node = (hash >> 16) % ls->ls_total_weight; 93*e7fd4179SDavid Teigland nodeid = ls->ls_node_array[node]; 94*e7fd4179SDavid Teigland goto out; 95*e7fd4179SDavid Teigland } 96*e7fd4179SDavid Teigland 97*e7fd4179SDavid Teigland /* make_member_array() failed to kmalloc ls_node_array... */ 98*e7fd4179SDavid Teigland 99*e7fd4179SDavid Teigland node = (hash >> 16) % ls->ls_num_nodes; 100*e7fd4179SDavid Teigland 101*e7fd4179SDavid Teigland list_for_each(tmp, &ls->ls_nodes) { 102*e7fd4179SDavid Teigland if (n++ != node) 103*e7fd4179SDavid Teigland continue; 104*e7fd4179SDavid Teigland memb = list_entry(tmp, struct dlm_member, list); 105*e7fd4179SDavid Teigland break; 106*e7fd4179SDavid Teigland } 107*e7fd4179SDavid Teigland 108*e7fd4179SDavid Teigland DLM_ASSERT(memb , printk("num_nodes=%u n=%u node=%u\n", 109*e7fd4179SDavid Teigland ls->ls_num_nodes, n, node);); 110*e7fd4179SDavid Teigland nodeid = memb->nodeid; 111*e7fd4179SDavid Teigland out: 112*e7fd4179SDavid Teigland return nodeid; 113*e7fd4179SDavid Teigland } 114*e7fd4179SDavid Teigland 115*e7fd4179SDavid Teigland int dlm_dir_nodeid(struct dlm_rsb *r) 116*e7fd4179SDavid Teigland { 117*e7fd4179SDavid Teigland return dlm_hash2nodeid(r->res_ls, r->res_hash); 118*e7fd4179SDavid Teigland } 119*e7fd4179SDavid Teigland 120*e7fd4179SDavid Teigland static inline uint32_t dir_hash(struct dlm_ls *ls, char *name, int len) 121*e7fd4179SDavid Teigland { 122*e7fd4179SDavid Teigland uint32_t val; 123*e7fd4179SDavid Teigland 124*e7fd4179SDavid Teigland val = jhash(name, len, 0); 125*e7fd4179SDavid Teigland val &= (ls->ls_dirtbl_size - 1); 126*e7fd4179SDavid Teigland 127*e7fd4179SDavid Teigland return val; 128*e7fd4179SDavid Teigland } 129*e7fd4179SDavid Teigland 130*e7fd4179SDavid Teigland static void add_entry_to_hash(struct dlm_ls *ls, struct dlm_direntry *de) 131*e7fd4179SDavid Teigland { 132*e7fd4179SDavid Teigland uint32_t bucket; 133*e7fd4179SDavid Teigland 134*e7fd4179SDavid Teigland bucket = dir_hash(ls, de->name, de->length); 135*e7fd4179SDavid Teigland list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list); 136*e7fd4179SDavid Teigland } 137*e7fd4179SDavid Teigland 138*e7fd4179SDavid Teigland static struct dlm_direntry *search_bucket(struct dlm_ls *ls, char *name, 139*e7fd4179SDavid Teigland int namelen, uint32_t bucket) 140*e7fd4179SDavid Teigland { 141*e7fd4179SDavid Teigland struct dlm_direntry *de; 142*e7fd4179SDavid Teigland 143*e7fd4179SDavid Teigland list_for_each_entry(de, &ls->ls_dirtbl[bucket].list, list) { 144*e7fd4179SDavid Teigland if (de->length == namelen && !memcmp(name, de->name, namelen)) 145*e7fd4179SDavid Teigland goto out; 146*e7fd4179SDavid Teigland } 147*e7fd4179SDavid Teigland de = NULL; 148*e7fd4179SDavid Teigland out: 149*e7fd4179SDavid Teigland return de; 150*e7fd4179SDavid Teigland } 151*e7fd4179SDavid Teigland 152*e7fd4179SDavid Teigland void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen) 153*e7fd4179SDavid Teigland { 154*e7fd4179SDavid Teigland struct dlm_direntry *de; 155*e7fd4179SDavid Teigland uint32_t bucket; 156*e7fd4179SDavid Teigland 157*e7fd4179SDavid Teigland bucket = dir_hash(ls, name, namelen); 158*e7fd4179SDavid Teigland 159*e7fd4179SDavid Teigland write_lock(&ls->ls_dirtbl[bucket].lock); 160*e7fd4179SDavid Teigland 161*e7fd4179SDavid Teigland de = search_bucket(ls, name, namelen, bucket); 162*e7fd4179SDavid Teigland 163*e7fd4179SDavid Teigland if (!de) { 164*e7fd4179SDavid Teigland log_error(ls, "remove fr %u none", nodeid); 165*e7fd4179SDavid Teigland goto out; 166*e7fd4179SDavid Teigland } 167*e7fd4179SDavid Teigland 168*e7fd4179SDavid Teigland if (de->master_nodeid != nodeid) { 169*e7fd4179SDavid Teigland log_error(ls, "remove fr %u ID %u", nodeid, de->master_nodeid); 170*e7fd4179SDavid Teigland goto out; 171*e7fd4179SDavid Teigland } 172*e7fd4179SDavid Teigland 173*e7fd4179SDavid Teigland list_del(&de->list); 174*e7fd4179SDavid Teigland free_direntry(de); 175*e7fd4179SDavid Teigland out: 176*e7fd4179SDavid Teigland write_unlock(&ls->ls_dirtbl[bucket].lock); 177*e7fd4179SDavid Teigland } 178*e7fd4179SDavid Teigland 179*e7fd4179SDavid Teigland void dlm_dir_clear(struct dlm_ls *ls) 180*e7fd4179SDavid Teigland { 181*e7fd4179SDavid Teigland struct list_head *head; 182*e7fd4179SDavid Teigland struct dlm_direntry *de; 183*e7fd4179SDavid Teigland int i; 184*e7fd4179SDavid Teigland 185*e7fd4179SDavid Teigland DLM_ASSERT(list_empty(&ls->ls_recover_list), ); 186*e7fd4179SDavid Teigland 187*e7fd4179SDavid Teigland for (i = 0; i < ls->ls_dirtbl_size; i++) { 188*e7fd4179SDavid Teigland write_lock(&ls->ls_dirtbl[i].lock); 189*e7fd4179SDavid Teigland head = &ls->ls_dirtbl[i].list; 190*e7fd4179SDavid Teigland while (!list_empty(head)) { 191*e7fd4179SDavid Teigland de = list_entry(head->next, struct dlm_direntry, list); 192*e7fd4179SDavid Teigland list_del(&de->list); 193*e7fd4179SDavid Teigland put_free_de(ls, de); 194*e7fd4179SDavid Teigland } 195*e7fd4179SDavid Teigland write_unlock(&ls->ls_dirtbl[i].lock); 196*e7fd4179SDavid Teigland } 197*e7fd4179SDavid Teigland } 198*e7fd4179SDavid Teigland 199*e7fd4179SDavid Teigland int dlm_recover_directory(struct dlm_ls *ls) 200*e7fd4179SDavid Teigland { 201*e7fd4179SDavid Teigland struct dlm_member *memb; 202*e7fd4179SDavid Teigland struct dlm_direntry *de; 203*e7fd4179SDavid Teigland char *b, *last_name = NULL; 204*e7fd4179SDavid Teigland int error = -ENOMEM, last_len, count = 0; 205*e7fd4179SDavid Teigland uint16_t namelen; 206*e7fd4179SDavid Teigland 207*e7fd4179SDavid Teigland log_debug(ls, "dlm_recover_directory"); 208*e7fd4179SDavid Teigland 209*e7fd4179SDavid Teigland if (dlm_no_directory(ls)) 210*e7fd4179SDavid Teigland goto out_status; 211*e7fd4179SDavid Teigland 212*e7fd4179SDavid Teigland dlm_dir_clear(ls); 213*e7fd4179SDavid Teigland 214*e7fd4179SDavid Teigland last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_KERNEL); 215*e7fd4179SDavid Teigland if (!last_name) 216*e7fd4179SDavid Teigland goto out; 217*e7fd4179SDavid Teigland 218*e7fd4179SDavid Teigland list_for_each_entry(memb, &ls->ls_nodes, list) { 219*e7fd4179SDavid Teigland memset(last_name, 0, DLM_RESNAME_MAXLEN); 220*e7fd4179SDavid Teigland last_len = 0; 221*e7fd4179SDavid Teigland 222*e7fd4179SDavid Teigland for (;;) { 223*e7fd4179SDavid Teigland error = dlm_recovery_stopped(ls); 224*e7fd4179SDavid Teigland if (error) 225*e7fd4179SDavid Teigland goto out_free; 226*e7fd4179SDavid Teigland 227*e7fd4179SDavid Teigland error = dlm_rcom_names(ls, memb->nodeid, 228*e7fd4179SDavid Teigland last_name, last_len); 229*e7fd4179SDavid Teigland if (error) 230*e7fd4179SDavid Teigland goto out_free; 231*e7fd4179SDavid Teigland 232*e7fd4179SDavid Teigland schedule(); 233*e7fd4179SDavid Teigland 234*e7fd4179SDavid Teigland /* 235*e7fd4179SDavid Teigland * pick namelen/name pairs out of received buffer 236*e7fd4179SDavid Teigland */ 237*e7fd4179SDavid Teigland 238*e7fd4179SDavid Teigland b = ls->ls_recover_buf + sizeof(struct dlm_rcom); 239*e7fd4179SDavid Teigland 240*e7fd4179SDavid Teigland for (;;) { 241*e7fd4179SDavid Teigland memcpy(&namelen, b, sizeof(uint16_t)); 242*e7fd4179SDavid Teigland namelen = be16_to_cpu(namelen); 243*e7fd4179SDavid Teigland b += sizeof(uint16_t); 244*e7fd4179SDavid Teigland 245*e7fd4179SDavid Teigland /* namelen of 0xFFFFF marks end of names for 246*e7fd4179SDavid Teigland this node; namelen of 0 marks end of the 247*e7fd4179SDavid Teigland buffer */ 248*e7fd4179SDavid Teigland 249*e7fd4179SDavid Teigland if (namelen == 0xFFFF) 250*e7fd4179SDavid Teigland goto done; 251*e7fd4179SDavid Teigland if (!namelen) 252*e7fd4179SDavid Teigland break; 253*e7fd4179SDavid Teigland 254*e7fd4179SDavid Teigland error = -ENOMEM; 255*e7fd4179SDavid Teigland de = get_free_de(ls, namelen); 256*e7fd4179SDavid Teigland if (!de) 257*e7fd4179SDavid Teigland goto out_free; 258*e7fd4179SDavid Teigland 259*e7fd4179SDavid Teigland de->master_nodeid = memb->nodeid; 260*e7fd4179SDavid Teigland de->length = namelen; 261*e7fd4179SDavid Teigland last_len = namelen; 262*e7fd4179SDavid Teigland memcpy(de->name, b, namelen); 263*e7fd4179SDavid Teigland memcpy(last_name, b, namelen); 264*e7fd4179SDavid Teigland b += namelen; 265*e7fd4179SDavid Teigland 266*e7fd4179SDavid Teigland add_entry_to_hash(ls, de); 267*e7fd4179SDavid Teigland count++; 268*e7fd4179SDavid Teigland } 269*e7fd4179SDavid Teigland } 270*e7fd4179SDavid Teigland done: 271*e7fd4179SDavid Teigland ; 272*e7fd4179SDavid Teigland } 273*e7fd4179SDavid Teigland 274*e7fd4179SDavid Teigland out_status: 275*e7fd4179SDavid Teigland error = 0; 276*e7fd4179SDavid Teigland dlm_set_recover_status(ls, DLM_RS_DIR); 277*e7fd4179SDavid Teigland log_debug(ls, "dlm_recover_directory %d entries", count); 278*e7fd4179SDavid Teigland out_free: 279*e7fd4179SDavid Teigland kfree(last_name); 280*e7fd4179SDavid Teigland out: 281*e7fd4179SDavid Teigland dlm_clear_free_entries(ls); 282*e7fd4179SDavid Teigland return error; 283*e7fd4179SDavid Teigland } 284*e7fd4179SDavid Teigland 285*e7fd4179SDavid Teigland static int get_entry(struct dlm_ls *ls, int nodeid, char *name, 286*e7fd4179SDavid Teigland int namelen, int *r_nodeid) 287*e7fd4179SDavid Teigland { 288*e7fd4179SDavid Teigland struct dlm_direntry *de, *tmp; 289*e7fd4179SDavid Teigland uint32_t bucket; 290*e7fd4179SDavid Teigland 291*e7fd4179SDavid Teigland bucket = dir_hash(ls, name, namelen); 292*e7fd4179SDavid Teigland 293*e7fd4179SDavid Teigland write_lock(&ls->ls_dirtbl[bucket].lock); 294*e7fd4179SDavid Teigland de = search_bucket(ls, name, namelen, bucket); 295*e7fd4179SDavid Teigland if (de) { 296*e7fd4179SDavid Teigland *r_nodeid = de->master_nodeid; 297*e7fd4179SDavid Teigland write_unlock(&ls->ls_dirtbl[bucket].lock); 298*e7fd4179SDavid Teigland if (*r_nodeid == nodeid) 299*e7fd4179SDavid Teigland return -EEXIST; 300*e7fd4179SDavid Teigland return 0; 301*e7fd4179SDavid Teigland } 302*e7fd4179SDavid Teigland 303*e7fd4179SDavid Teigland write_unlock(&ls->ls_dirtbl[bucket].lock); 304*e7fd4179SDavid Teigland 305*e7fd4179SDavid Teigland de = allocate_direntry(ls, namelen); 306*e7fd4179SDavid Teigland if (!de) 307*e7fd4179SDavid Teigland return -ENOMEM; 308*e7fd4179SDavid Teigland 309*e7fd4179SDavid Teigland de->master_nodeid = nodeid; 310*e7fd4179SDavid Teigland de->length = namelen; 311*e7fd4179SDavid Teigland memcpy(de->name, name, namelen); 312*e7fd4179SDavid Teigland 313*e7fd4179SDavid Teigland write_lock(&ls->ls_dirtbl[bucket].lock); 314*e7fd4179SDavid Teigland tmp = search_bucket(ls, name, namelen, bucket); 315*e7fd4179SDavid Teigland if (tmp) { 316*e7fd4179SDavid Teigland free_direntry(de); 317*e7fd4179SDavid Teigland de = tmp; 318*e7fd4179SDavid Teigland } else { 319*e7fd4179SDavid Teigland list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list); 320*e7fd4179SDavid Teigland } 321*e7fd4179SDavid Teigland *r_nodeid = de->master_nodeid; 322*e7fd4179SDavid Teigland write_unlock(&ls->ls_dirtbl[bucket].lock); 323*e7fd4179SDavid Teigland return 0; 324*e7fd4179SDavid Teigland } 325*e7fd4179SDavid Teigland 326*e7fd4179SDavid Teigland int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen, 327*e7fd4179SDavid Teigland int *r_nodeid) 328*e7fd4179SDavid Teigland { 329*e7fd4179SDavid Teigland return get_entry(ls, nodeid, name, namelen, r_nodeid); 330*e7fd4179SDavid Teigland } 331*e7fd4179SDavid Teigland 332*e7fd4179SDavid Teigland /* Copy the names of master rsb's into the buffer provided. 333*e7fd4179SDavid Teigland Only select names whose dir node is the given nodeid. */ 334*e7fd4179SDavid Teigland 335*e7fd4179SDavid Teigland void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen, 336*e7fd4179SDavid Teigland char *outbuf, int outlen, int nodeid) 337*e7fd4179SDavid Teigland { 338*e7fd4179SDavid Teigland struct list_head *list; 339*e7fd4179SDavid Teigland struct dlm_rsb *start_r = NULL, *r = NULL; 340*e7fd4179SDavid Teigland int offset = 0, start_namelen, error, dir_nodeid; 341*e7fd4179SDavid Teigland char *start_name; 342*e7fd4179SDavid Teigland uint16_t be_namelen; 343*e7fd4179SDavid Teigland 344*e7fd4179SDavid Teigland /* 345*e7fd4179SDavid Teigland * Find the rsb where we left off (or start again) 346*e7fd4179SDavid Teigland */ 347*e7fd4179SDavid Teigland 348*e7fd4179SDavid Teigland start_namelen = inlen; 349*e7fd4179SDavid Teigland start_name = inbuf; 350*e7fd4179SDavid Teigland 351*e7fd4179SDavid Teigland if (start_namelen > 1) { 352*e7fd4179SDavid Teigland /* 353*e7fd4179SDavid Teigland * We could also use a find_rsb_root() function here that 354*e7fd4179SDavid Teigland * searched the ls_root_list. 355*e7fd4179SDavid Teigland */ 356*e7fd4179SDavid Teigland error = dlm_find_rsb(ls, start_name, start_namelen, R_MASTER, 357*e7fd4179SDavid Teigland &start_r); 358*e7fd4179SDavid Teigland DLM_ASSERT(!error && start_r, 359*e7fd4179SDavid Teigland printk("error %d\n", error);); 360*e7fd4179SDavid Teigland DLM_ASSERT(!list_empty(&start_r->res_root_list), 361*e7fd4179SDavid Teigland dlm_print_rsb(start_r);); 362*e7fd4179SDavid Teigland dlm_put_rsb(start_r); 363*e7fd4179SDavid Teigland } 364*e7fd4179SDavid Teigland 365*e7fd4179SDavid Teigland /* 366*e7fd4179SDavid Teigland * Send rsb names for rsb's we're master of and whose directory node 367*e7fd4179SDavid Teigland * matches the requesting node. 368*e7fd4179SDavid Teigland */ 369*e7fd4179SDavid Teigland 370*e7fd4179SDavid Teigland down_read(&ls->ls_root_sem); 371*e7fd4179SDavid Teigland if (start_r) 372*e7fd4179SDavid Teigland list = start_r->res_root_list.next; 373*e7fd4179SDavid Teigland else 374*e7fd4179SDavid Teigland list = ls->ls_root_list.next; 375*e7fd4179SDavid Teigland 376*e7fd4179SDavid Teigland for (offset = 0; list != &ls->ls_root_list; list = list->next) { 377*e7fd4179SDavid Teigland r = list_entry(list, struct dlm_rsb, res_root_list); 378*e7fd4179SDavid Teigland if (r->res_nodeid) 379*e7fd4179SDavid Teigland continue; 380*e7fd4179SDavid Teigland 381*e7fd4179SDavid Teigland dir_nodeid = dlm_dir_nodeid(r); 382*e7fd4179SDavid Teigland if (dir_nodeid != nodeid) 383*e7fd4179SDavid Teigland continue; 384*e7fd4179SDavid Teigland 385*e7fd4179SDavid Teigland /* 386*e7fd4179SDavid Teigland * The block ends when we can't fit the following in the 387*e7fd4179SDavid Teigland * remaining buffer space: 388*e7fd4179SDavid Teigland * namelen (uint16_t) + 389*e7fd4179SDavid Teigland * name (r->res_length) + 390*e7fd4179SDavid Teigland * end-of-block record 0x0000 (uint16_t) 391*e7fd4179SDavid Teigland */ 392*e7fd4179SDavid Teigland 393*e7fd4179SDavid Teigland if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) { 394*e7fd4179SDavid Teigland /* Write end-of-block record */ 395*e7fd4179SDavid Teigland be_namelen = 0; 396*e7fd4179SDavid Teigland memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t)); 397*e7fd4179SDavid Teigland offset += sizeof(uint16_t); 398*e7fd4179SDavid Teigland goto out; 399*e7fd4179SDavid Teigland } 400*e7fd4179SDavid Teigland 401*e7fd4179SDavid Teigland be_namelen = cpu_to_be16(r->res_length); 402*e7fd4179SDavid Teigland memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t)); 403*e7fd4179SDavid Teigland offset += sizeof(uint16_t); 404*e7fd4179SDavid Teigland memcpy(outbuf + offset, r->res_name, r->res_length); 405*e7fd4179SDavid Teigland offset += r->res_length; 406*e7fd4179SDavid Teigland } 407*e7fd4179SDavid Teigland 408*e7fd4179SDavid Teigland /* 409*e7fd4179SDavid Teigland * If we've reached the end of the list (and there's room) write a 410*e7fd4179SDavid Teigland * terminating record. 411*e7fd4179SDavid Teigland */ 412*e7fd4179SDavid Teigland 413*e7fd4179SDavid Teigland if ((list == &ls->ls_root_list) && 414*e7fd4179SDavid Teigland (offset + sizeof(uint16_t) <= outlen)) { 415*e7fd4179SDavid Teigland be_namelen = 0xFFFF; 416*e7fd4179SDavid Teigland memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t)); 417*e7fd4179SDavid Teigland offset += sizeof(uint16_t); 418*e7fd4179SDavid Teigland } 419*e7fd4179SDavid Teigland 420*e7fd4179SDavid Teigland out: 421*e7fd4179SDavid Teigland up_read(&ls->ls_root_sem); 422*e7fd4179SDavid Teigland } 423*e7fd4179SDavid Teigland 424