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