📄 fsys_zfs.c
字号:
/* * Only use 28 bits, since we need 4 bits in the cookie for the * collision differentiator. We MUST use the high bits, since * those are the onces that we first pay attention to when * chosing the bucket. */ crc &= ~((1ULL << (64 - ZAP_HASHBITS)) - 1); return (crc);}/* * Only to be used on 8-bit arrays. * array_len is actual len in bytes (not encoded le_value_length). * buf is null-terminated. */static intzap_leaf_array_equal(zap_leaf_phys_t *l, int blksft, int chunk, int array_len, const char *buf){ int bseen = 0; while (bseen < array_len) { struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(l, blksft, chunk).l_array; int toread = MIN(array_len - bseen, ZAP_LEAF_ARRAY_BYTES); if (chunk >= ZAP_LEAF_NUMCHUNKS(blksft)) return (0); if (zfs_bcmp(la->la_array, buf + bseen, toread) != 0) break; chunk = la->la_next; bseen += toread; } return (bseen == array_len);}/* * Given a zap_leaf_phys_t, walk thru the zap leaf chunks to get the * value for the property "name". * * Return: * 0 - success * errnum - failure */static intzap_leaf_lookup(zap_leaf_phys_t *l, int blksft, uint64_t h, const char *name, uint64_t *value){ uint16_t chunk; struct zap_leaf_entry *le; /* Verify if this is a valid leaf block */ if (l->l_hdr.lh_block_type != ZBT_LEAF) return (ERR_FSYS_CORRUPT); if (l->l_hdr.lh_magic != ZAP_LEAF_MAGIC) return (ERR_FSYS_CORRUPT); for (chunk = l->l_hash[LEAF_HASH(blksft, h)]; chunk != CHAIN_END; chunk = le->le_next) { if (chunk >= ZAP_LEAF_NUMCHUNKS(blksft)) return (ERR_FSYS_CORRUPT); le = ZAP_LEAF_ENTRY(l, blksft, chunk); /* Verify the chunk entry */ if (le->le_type != ZAP_CHUNK_ENTRY) return (ERR_FSYS_CORRUPT); if (le->le_hash != h) continue; if (zap_leaf_array_equal(l, blksft, le->le_name_chunk, le->le_name_length, name)) { struct zap_leaf_array *la; uint8_t *ip; if (le->le_int_size != 8 || le->le_value_length != 1) return (ERR_FSYS_CORRUPT); /* get the uint64_t property value */ la = &ZAP_LEAF_CHUNK(l, blksft, le->le_value_chunk).l_array; ip = la->la_array; *value = (uint64_t)ip[0] << 56 | (uint64_t)ip[1] << 48 | (uint64_t)ip[2] << 40 | (uint64_t)ip[3] << 32 | (uint64_t)ip[4] << 24 | (uint64_t)ip[5] << 16 | (uint64_t)ip[6] << 8 | (uint64_t)ip[7]; return (0); } } return (ERR_FSYS_CORRUPT);}/* * Fat ZAP lookup * * Return: * 0 - success * errnum - failure */static intfzap_lookup(fsi_file_t *ffi, dnode_phys_t *zap_dnode, zap_phys_t *zap, char *name, uint64_t *value, char *stack){ zap_leaf_phys_t *l; uint64_t hash, idx, blkid; int blksft = zfs_log2(zap_dnode->dn_datablkszsec << DNODE_SHIFT); /* Verify if this is a fat zap header block */ if (zap->zap_magic != (uint64_t)ZAP_MAGIC) return (ERR_FSYS_CORRUPT); hash = zap_hash(ffi, zap->zap_salt, name); if (errnum) return (errnum); /* get block id from index */ if (zap->zap_ptrtbl.zt_numblks != 0) { /* external pointer tables not supported */ return (ERR_FSYS_CORRUPT); } idx = ZAP_HASH_IDX(hash, zap->zap_ptrtbl.zt_shift); blkid = ((uint64_t *)zap)[idx + (1<<(blksft-3-1))]; /* Get the leaf block */ l = (zap_leaf_phys_t *)stack; stack += 1<<blksft; if ((errnum = dmu_read(ffi, zap_dnode, blkid, l, stack))) return (errnum); return (zap_leaf_lookup(l, blksft, hash, name, value));}/* * Read in the data of a zap object and find the value for a matching * property name. * * Return: * 0 - success * errnum - failure */static intzap_lookup(fsi_file_t *ffi, dnode_phys_t *zap_dnode, char *name, uint64_t *val, char *stack){ uint64_t block_type; int size; void *zapbuf; /* Read in the first block of the zap object data. */ zapbuf = stack; size = zap_dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; stack += size; if ((errnum = dmu_read(ffi, zap_dnode, 0, zapbuf, stack))) return (errnum); block_type = *((uint64_t *)zapbuf); if (block_type == ZBT_MICRO) { return (mzap_lookup(zapbuf, size, name, val)); } else if (block_type == ZBT_HEADER) { /* this is a fat zap */ return (fzap_lookup(ffi, zap_dnode, zapbuf, name, val, stack)); } return (ERR_FSYS_CORRUPT);}/* * Get the dnode of an object number from the metadnode of an object set. * * Input * mdn - metadnode to get the object dnode * objnum - object number for the object dnode * buf - data buffer that holds the returning dnode * stack - scratch area * * Return: * 0 - success * errnum - failure */static intdnode_get(fsi_file_t *ffi, dnode_phys_t *mdn, uint64_t objnum, uint8_t type, dnode_phys_t *buf, char *stack){ uint64_t blkid, blksz; /* the block id this object dnode is in */ int epbs; /* shift of number of dnodes in a block */ int idx; /* index within a block */ dnode_phys_t *dnbuf; zfs_bootarea_t *zfs_ba = (zfs_bootarea_t *)ffi->ff_fsi->f_data; blksz = mdn->dn_datablkszsec << SPA_MINBLOCKSHIFT; epbs = zfs_log2(blksz) - DNODE_SHIFT; blkid = objnum >> epbs; idx = objnum & ((1<<epbs)-1); if (dnode_buf != NULL && dnode_mdn == mdn && objnum >= dnode_start && objnum < dnode_end) { grub_memmove(buf, &dnode_buf[idx], DNODE_SIZE); VERIFY_DN_TYPE(buf, type); return (0); } if (dnode_buf && blksz == 1<<DNODE_BLOCK_SHIFT) { dnbuf = dnode_buf; dnode_mdn = mdn; dnode_start = blkid << epbs; dnode_end = (blkid + 1) << epbs; } else { dnbuf = (dnode_phys_t *)stack; stack += blksz; } if ((errnum = dmu_read(ffi, mdn, blkid, (char *)dnbuf, stack))) return (errnum); grub_memmove(buf, &dnbuf[idx], DNODE_SIZE); VERIFY_DN_TYPE(buf, type); return (0);}/* * Check if this is a special file that resides at the top * dataset of the pool. Currently this is the GRUB menu, * boot signature and boot signature backup. * str starts with '/'. */static intis_top_dataset_file(char *str){ char *tptr; if (((tptr = strstr(str, "menu.lst"))) && (tptr[8] == '\0' || tptr[8] == ' ') && *(tptr-1) == '/') return (1); if (strncmp(str, BOOTSIGN_DIR"/", strlen(BOOTSIGN_DIR) + 1) == 0) return (1); if (strcmp(str, BOOTSIGN_BACKUP) == 0) return (1); return (0);}/* * Get the file dnode for a given file name where mdn is the meta dnode * for this ZFS object set. When found, place the file dnode in dn. * The 'path' argument will be mangled. * * Return: * 0 - success * errnum - failure */static intdnode_get_path(fsi_file_t *ffi, dnode_phys_t *mdn, char *path, dnode_phys_t *dn, char *stack){ uint64_t objnum, version; char *cname, ch; if ((errnum = dnode_get(ffi, mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, dn, stack))) return (errnum); if ((errnum = zap_lookup(ffi, dn, ZPL_VERSION_STR, &version, stack))) return (errnum); if (version > ZPL_VERSION) return (-1); if ((errnum = zap_lookup(ffi, dn, ZFS_ROOT_OBJ, &objnum, stack))) return (errnum); if ((errnum = dnode_get(ffi, mdn, objnum, DMU_OT_DIRECTORY_CONTENTS, dn, stack))) return (errnum); /* skip leading slashes */ while (*path == '/') path++; while (*path && !isspace((uint8_t)*path)) { /* get the next component name */ cname = path; while (*path && !isspace((uint8_t)*path) && *path != '/') path++; ch = *path; *path = 0; /* ensure null termination */ if ((errnum = zap_lookup(ffi, dn, cname, &objnum, stack))) return (errnum); objnum = ZFS_DIRENT_OBJ(objnum); if ((errnum = dnode_get(ffi, mdn, objnum, 0, dn, stack))) return (errnum); *path = ch; while (*path == '/') path++; } /* We found the dnode for this file. Verify if it is a plain file. */ VERIFY_DN_TYPE(dn, DMU_OT_PLAIN_FILE_CONTENTS); return (0);}/* * Get the default 'bootfs' property value from the rootpool. * * Return: * 0 - success * errnum -failure */static intget_default_bootfsobj(fsi_file_t *ffi, dnode_phys_t *mosmdn, uint64_t *obj, char *stack){ uint64_t objnum = 0; dnode_phys_t *dn = (dnode_phys_t *)stack; stack += DNODE_SIZE; if ((errnum = dnode_get(ffi, mosmdn, DMU_POOL_DIRECTORY_OBJECT, DMU_OT_OBJECT_DIRECTORY, dn, stack))) return (errnum); /* * find the object number for 'pool_props', and get the dnode * of the 'pool_props'. */ if (zap_lookup(ffi, dn, DMU_POOL_PROPS, &objnum, stack)) return (ERR_FILESYSTEM_NOT_FOUND); if ((errnum = dnode_get(ffi, mosmdn, objnum, DMU_OT_POOL_PROPS, dn, stack))) return (errnum); if (zap_lookup(ffi, dn, ZPOOL_PROP_BOOTFS, &objnum, stack)) return (ERR_FILESYSTEM_NOT_FOUND); if (!objnum) return (ERR_FILESYSTEM_NOT_FOUND); *obj = objnum; return (0);}/* * Given a MOS metadnode, get the metadnode of a given filesystem name (fsname), * e.g. pool/rootfs, or a given object number (obj), e.g. the object number * of pool/rootfs. * * If no fsname and no obj are given, return the DSL_DIR metadnode. * If fsname is given, return its metadnode and its matching object number. * If only obj is given, return the metadnode for this object number. * * Return: * 0 - success * errnum - failure */static intget_objset_mdn(fsi_file_t *ffi, dnode_phys_t *mosmdn, char *fsname, uint64_t *obj, dnode_phys_t *mdn, char *stack){ uint64_t objnum, headobj; char *cname, ch; blkptr_t *bp; objset_phys_t *osp; if (fsname == NULL && obj) { headobj = *obj; goto skip; } if ((errnum = dnode_get(ffi, mosmdn, DMU_POOL_DIRECTORY_OBJECT, DMU_OT_OBJECT_DIRECTORY, mdn, stack))) return (errnum); if ((errnum = zap_lookup(ffi, mdn, DMU_POOL_ROOT_DATASET, &objnum, stack))) return (errnum); if ((errnum = dnode_get(ffi, mosmdn, objnum, DMU_OT_DSL_DIR, mdn, stack))) return (errnum); if (fsname == NULL) { headobj = ((dsl_dir_phys_t *)DN_BONUS(mdn))->dd_head_dataset_obj; goto skip; } /* take out the pool name */ while (*fsname && !isspace((uint8_t)*fsname) && *fsname != '/') fsname++; while (*fsname && !isspace((uint8_t)*fsname)) { uint64_t childobj; while (*fsname == '/') fsname++; cname = fsname; while (*fsname && !isspace((uint8_t)*fsname) && *fsname != '/') fsname++; ch = *fsname; *fsname = 0; childobj = ((dsl_dir_phys_t *)DN_BONUS(mdn))->dd_child_dir_zapobj; if ((errnum = dnode_get(ffi, mosmdn, childobj, DMU_OT_DSL_DIR_CHILD_MAP, mdn, stack))) return (errnum); if (zap_lookup(ffi, mdn, cname, &objnum, stack)) return (ERR_FILESYSTEM_NOT_FOUND); if ((errnum = dnode_get(ffi, mosmdn, objnum, DMU_OT_DSL_DIR, mdn, stack))) return (errnum); *fsname = ch; } headobj = ((dsl_dir_phys_t *)DN_BONUS(mdn))->dd_head_dataset_obj; if (obj) *obj = headobj;skip: if ((errnum = dnode_get(ffi, mosmdn, headobj, DMU_OT_DSL_DATASET, mdn, stack))) return (errnum); /* TODO: Add snapshot support here - for fsname=snapshot-name */ bp = &((dsl_dataset_phys_t *)DN_BONUS(mdn))->ds_bp; osp = (objset_phys_t *)stack; stack += sizeof (objset_phys_t); if ((errnum = zio_read(ffi, bp, osp, stack))) return (errnum); grub_memmove((char *)mdn, (char *)&osp->os_meta_dnode, DNODE_SIZE); return (0);}/* * For a given XDR packed nvlist, verify the first 4 bytes and move on. * * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) : * * encoding method/host endian (4 bytes) * nvl_version (4 bytes) * nvl_nvflag (4 bytes) * encoded nvpairs: * encoded size of the nvpair (4 bytes) * decoded size of the nvpair (4 bytes) * name string size (4 bytes) * name string data (sizeof(NV_ALIGN4(string)) * data type (4 bytes) * # of elements in the nvpair (4 bytes) * data * 2 zero's for the last nvpair * (end of the entire list) (8 bytes) * * Return: * 0 - success * 1 - failure */static intnvlist_unpack(char *nvlist, char **out){ /* Verify if the 1st and 2nd byte in the nvlist are valid. */ if (nvlist[0] != NV_ENCODE_XDR || nvlist[1] != HOST_ENDIAN)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -