1240afd8cSMark Johnston /*- 2240afd8cSMark Johnston * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3240afd8cSMark Johnston * 4240afd8cSMark Johnston * Copyright (c) 2022 The FreeBSD Foundation 5240afd8cSMark Johnston * 6240afd8cSMark Johnston * This software was developed by Mark Johnston under sponsorship from 7240afd8cSMark Johnston * the FreeBSD Foundation. 8240afd8cSMark Johnston * 9240afd8cSMark Johnston * Redistribution and use in source and binary forms, with or without 10240afd8cSMark Johnston * modification, are permitted provided that the following conditions are 11240afd8cSMark Johnston * met: 12240afd8cSMark Johnston * 1. Redistributions of source code must retain the above copyright 13240afd8cSMark Johnston * notice, this list of conditions and the following disclaimer. 14240afd8cSMark Johnston * 2. Redistributions in binary form must reproduce the above copyright 15240afd8cSMark Johnston * notice, this list of conditions and the following disclaimer in 16240afd8cSMark Johnston * the documentation and/or other materials provided with the distribution. 17240afd8cSMark Johnston * 18240afd8cSMark Johnston * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19240afd8cSMark Johnston * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20240afd8cSMark Johnston * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21240afd8cSMark Johnston * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22240afd8cSMark Johnston * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23240afd8cSMark Johnston * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24240afd8cSMark Johnston * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25240afd8cSMark Johnston * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26240afd8cSMark Johnston * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27240afd8cSMark Johnston * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28240afd8cSMark Johnston * SUCH DAMAGE. 29240afd8cSMark Johnston */ 30240afd8cSMark Johnston 31240afd8cSMark Johnston #include <sys/dirent.h> 32240afd8cSMark Johnston #include <sys/stat.h> 33240afd8cSMark Johnston 34240afd8cSMark Johnston #include <assert.h> 35240afd8cSMark Johnston #include <fcntl.h> 36240afd8cSMark Johnston #include <string.h> 37240afd8cSMark Johnston #include <unistd.h> 38240afd8cSMark Johnston 39240afd8cSMark Johnston #include <util.h> 40240afd8cSMark Johnston 41240afd8cSMark Johnston #include "makefs.h" 42240afd8cSMark Johnston #include "zfs.h" 43240afd8cSMark Johnston 44240afd8cSMark Johnston typedef struct { 45240afd8cSMark Johnston const char *name; 46240afd8cSMark Johnston unsigned int id; 47240afd8cSMark Johnston uint16_t size; 48240afd8cSMark Johnston sa_bswap_type_t bs; 49240afd8cSMark Johnston } zfs_sattr_t; 50240afd8cSMark Johnston 51240afd8cSMark Johnston typedef struct zfs_fs { 52240afd8cSMark Johnston zfs_objset_t *os; 53240afd8cSMark Johnston 54240afd8cSMark Johnston /* Offset table for system attributes, indexed by a zpl_attr_t. */ 55240afd8cSMark Johnston uint16_t *saoffs; 56240afd8cSMark Johnston size_t sacnt; 57240afd8cSMark Johnston const zfs_sattr_t *satab; 58240afd8cSMark Johnston } zfs_fs_t; 59240afd8cSMark Johnston 60240afd8cSMark Johnston /* 61240afd8cSMark Johnston * The order of the attributes doesn't matter, this is simply the one hard-coded 62240afd8cSMark Johnston * by OpenZFS, based on a zdb dump of the SA_REGISTRY table. 63240afd8cSMark Johnston */ 64240afd8cSMark Johnston typedef enum zpl_attr { 65240afd8cSMark Johnston ZPL_ATIME, 66240afd8cSMark Johnston ZPL_MTIME, 67240afd8cSMark Johnston ZPL_CTIME, 68240afd8cSMark Johnston ZPL_CRTIME, 69240afd8cSMark Johnston ZPL_GEN, 70240afd8cSMark Johnston ZPL_MODE, 71240afd8cSMark Johnston ZPL_SIZE, 72240afd8cSMark Johnston ZPL_PARENT, 73240afd8cSMark Johnston ZPL_LINKS, 74240afd8cSMark Johnston ZPL_XATTR, 75240afd8cSMark Johnston ZPL_RDEV, 76240afd8cSMark Johnston ZPL_FLAGS, 77240afd8cSMark Johnston ZPL_UID, 78240afd8cSMark Johnston ZPL_GID, 79240afd8cSMark Johnston ZPL_PAD, 80240afd8cSMark Johnston ZPL_ZNODE_ACL, 81240afd8cSMark Johnston ZPL_DACL_COUNT, 82240afd8cSMark Johnston ZPL_SYMLINK, 83240afd8cSMark Johnston ZPL_SCANSTAMP, 84240afd8cSMark Johnston ZPL_DACL_ACES, 85240afd8cSMark Johnston ZPL_DXATTR, 86240afd8cSMark Johnston ZPL_PROJID, 87240afd8cSMark Johnston } zpl_attr_t; 88240afd8cSMark Johnston 89240afd8cSMark Johnston /* 90240afd8cSMark Johnston * This table must be kept in sync with zpl_attr_layout[] and zpl_attr_t. 91240afd8cSMark Johnston */ 92240afd8cSMark Johnston static const zfs_sattr_t zpl_attrs[] = { 93240afd8cSMark Johnston #define _ZPL_ATTR(n, s, b) { .name = #n, .id = n, .size = s, .bs = b } 94240afd8cSMark Johnston _ZPL_ATTR(ZPL_ATIME, sizeof(uint64_t) * 2, SA_UINT64_ARRAY), 95240afd8cSMark Johnston _ZPL_ATTR(ZPL_MTIME, sizeof(uint64_t) * 2, SA_UINT64_ARRAY), 96240afd8cSMark Johnston _ZPL_ATTR(ZPL_CTIME, sizeof(uint64_t) * 2, SA_UINT64_ARRAY), 97240afd8cSMark Johnston _ZPL_ATTR(ZPL_CRTIME, sizeof(uint64_t) * 2, SA_UINT64_ARRAY), 98240afd8cSMark Johnston _ZPL_ATTR(ZPL_GEN, sizeof(uint64_t), SA_UINT64_ARRAY), 99240afd8cSMark Johnston _ZPL_ATTR(ZPL_MODE, sizeof(uint64_t), SA_UINT64_ARRAY), 100240afd8cSMark Johnston _ZPL_ATTR(ZPL_SIZE, sizeof(uint64_t), SA_UINT64_ARRAY), 101240afd8cSMark Johnston _ZPL_ATTR(ZPL_PARENT, sizeof(uint64_t), SA_UINT64_ARRAY), 102240afd8cSMark Johnston _ZPL_ATTR(ZPL_LINKS, sizeof(uint64_t), SA_UINT64_ARRAY), 103240afd8cSMark Johnston _ZPL_ATTR(ZPL_XATTR, sizeof(uint64_t), SA_UINT64_ARRAY), 104240afd8cSMark Johnston _ZPL_ATTR(ZPL_RDEV, sizeof(uint64_t), SA_UINT64_ARRAY), 105240afd8cSMark Johnston _ZPL_ATTR(ZPL_FLAGS, sizeof(uint64_t), SA_UINT64_ARRAY), 106240afd8cSMark Johnston _ZPL_ATTR(ZPL_UID, sizeof(uint64_t), SA_UINT64_ARRAY), 107240afd8cSMark Johnston _ZPL_ATTR(ZPL_GID, sizeof(uint64_t), SA_UINT64_ARRAY), 108240afd8cSMark Johnston _ZPL_ATTR(ZPL_PAD, sizeof(uint64_t), SA_UINT64_ARRAY), 109240afd8cSMark Johnston _ZPL_ATTR(ZPL_ZNODE_ACL, 88, SA_UINT64_ARRAY), 110240afd8cSMark Johnston _ZPL_ATTR(ZPL_DACL_COUNT, sizeof(uint64_t), SA_UINT64_ARRAY), 111240afd8cSMark Johnston _ZPL_ATTR(ZPL_SYMLINK, 0, SA_UINT8_ARRAY), 112240afd8cSMark Johnston _ZPL_ATTR(ZPL_SCANSTAMP, sizeof(uint64_t) * 4, SA_UINT8_ARRAY), 113240afd8cSMark Johnston _ZPL_ATTR(ZPL_DACL_ACES, 0, SA_ACL), 114240afd8cSMark Johnston _ZPL_ATTR(ZPL_DXATTR, 0, SA_UINT8_ARRAY), 115240afd8cSMark Johnston _ZPL_ATTR(ZPL_PROJID, sizeof(uint64_t), SA_UINT64_ARRAY), 116240afd8cSMark Johnston #undef ZPL_ATTR 117240afd8cSMark Johnston }; 118240afd8cSMark Johnston 119240afd8cSMark Johnston /* 120240afd8cSMark Johnston * This layout matches that of a filesystem created using OpenZFS on FreeBSD. 121240afd8cSMark Johnston * It need not match in general, but FreeBSD's loader doesn't bother parsing the 122240afd8cSMark Johnston * layout and just hard-codes attribute offsets. 123240afd8cSMark Johnston */ 124240afd8cSMark Johnston static const sa_attr_type_t zpl_attr_layout[] = { 125240afd8cSMark Johnston ZPL_MODE, 126240afd8cSMark Johnston ZPL_SIZE, 127240afd8cSMark Johnston ZPL_GEN, 128240afd8cSMark Johnston ZPL_UID, 129240afd8cSMark Johnston ZPL_GID, 130240afd8cSMark Johnston ZPL_PARENT, 131240afd8cSMark Johnston ZPL_FLAGS, 132240afd8cSMark Johnston ZPL_ATIME, 133240afd8cSMark Johnston ZPL_MTIME, 134240afd8cSMark Johnston ZPL_CTIME, 135240afd8cSMark Johnston ZPL_CRTIME, 136240afd8cSMark Johnston ZPL_LINKS, 137240afd8cSMark Johnston ZPL_DACL_COUNT, 138240afd8cSMark Johnston ZPL_DACL_ACES, 139240afd8cSMark Johnston ZPL_SYMLINK, 140240afd8cSMark Johnston }; 141240afd8cSMark Johnston 142240afd8cSMark Johnston /* 143240afd8cSMark Johnston * Keys for the ZPL attribute tables in the SA layout ZAP. The first two 144240afd8cSMark Johnston * indices are reserved for legacy attribute encoding. 145240afd8cSMark Johnston */ 146240afd8cSMark Johnston #define SA_LAYOUT_INDEX_DEFAULT 2 147240afd8cSMark Johnston #define SA_LAYOUT_INDEX_SYMLINK 3 148240afd8cSMark Johnston 149240afd8cSMark Johnston struct fs_populate_dir { 150240afd8cSMark Johnston SLIST_ENTRY(fs_populate_dir) next; 151240afd8cSMark Johnston int dirfd; 152240afd8cSMark Johnston uint64_t objid; 153240afd8cSMark Johnston zfs_zap_t *zap; 154240afd8cSMark Johnston }; 155240afd8cSMark Johnston 156240afd8cSMark Johnston struct fs_populate_arg { 157240afd8cSMark Johnston zfs_opt_t *zfs; 158240afd8cSMark Johnston zfs_fs_t *fs; /* owning filesystem */ 159240afd8cSMark Johnston int dirfd; /* current directory fd */ 160240afd8cSMark Johnston uint64_t rootdirid; /* root directory dnode ID */ 161240afd8cSMark Johnston SLIST_HEAD(, fs_populate_dir) dirs; /* stack of directories */ 162240afd8cSMark Johnston }; 163240afd8cSMark Johnston 164240afd8cSMark Johnston static void fs_build_one(zfs_opt_t *, zfs_dsl_dir_t *, fsnode *, int); 165240afd8cSMark Johnston 166240afd8cSMark Johnston static bool 167240afd8cSMark Johnston fsnode_isroot(const fsnode *cur) 168240afd8cSMark Johnston { 169240afd8cSMark Johnston return (strcmp(cur->name, ".") == 0); 170240afd8cSMark Johnston } 171240afd8cSMark Johnston 172240afd8cSMark Johnston /* 173240afd8cSMark Johnston * Visit each node in a directory hierarchy, in pre-order depth-first order. 174240afd8cSMark Johnston */ 175240afd8cSMark Johnston static void 176240afd8cSMark Johnston fsnode_foreach(fsnode *root, int (*cb)(fsnode *, void *), void *arg) 177240afd8cSMark Johnston { 178240afd8cSMark Johnston assert(root->type == S_IFDIR); 179240afd8cSMark Johnston 180240afd8cSMark Johnston for (fsnode *cur = root; cur != NULL; cur = cur->next) { 181240afd8cSMark Johnston assert(cur->type == S_IFREG || cur->type == S_IFDIR || 182240afd8cSMark Johnston cur->type == S_IFLNK); 183240afd8cSMark Johnston 184240afd8cSMark Johnston if (cb(cur, arg) == 0) 185240afd8cSMark Johnston continue; 186240afd8cSMark Johnston if (cur->type == S_IFDIR && cur->child != NULL) 187240afd8cSMark Johnston fsnode_foreach(cur->child, cb, arg); 188240afd8cSMark Johnston } 189240afd8cSMark Johnston } 190240afd8cSMark Johnston 191240afd8cSMark Johnston static void 192240afd8cSMark Johnston fs_populate_dirent(struct fs_populate_arg *arg, fsnode *cur, uint64_t dnid) 193240afd8cSMark Johnston { 194240afd8cSMark Johnston struct fs_populate_dir *dir; 195240afd8cSMark Johnston uint64_t type; 196240afd8cSMark Johnston 197240afd8cSMark Johnston switch (cur->type) { 198240afd8cSMark Johnston case S_IFREG: 199240afd8cSMark Johnston type = DT_REG; 200240afd8cSMark Johnston break; 201240afd8cSMark Johnston case S_IFDIR: 202240afd8cSMark Johnston type = DT_DIR; 203240afd8cSMark Johnston break; 204240afd8cSMark Johnston case S_IFLNK: 205240afd8cSMark Johnston type = DT_LNK; 206240afd8cSMark Johnston break; 207240afd8cSMark Johnston default: 208240afd8cSMark Johnston assert(0); 209240afd8cSMark Johnston } 210240afd8cSMark Johnston 211240afd8cSMark Johnston dir = SLIST_FIRST(&arg->dirs); 212240afd8cSMark Johnston zap_add_uint64(dir->zap, cur->name, ZFS_DIRENT_MAKE(type, dnid)); 213240afd8cSMark Johnston } 214240afd8cSMark Johnston 215240afd8cSMark Johnston static void 216240afd8cSMark Johnston fs_populate_attr(zfs_fs_t *fs, char *attrbuf, const void *val, uint16_t ind, 217240afd8cSMark Johnston size_t *szp) 218240afd8cSMark Johnston { 219240afd8cSMark Johnston assert(ind < fs->sacnt); 220240afd8cSMark Johnston assert(fs->saoffs[ind] != 0xffff); 221240afd8cSMark Johnston 222240afd8cSMark Johnston memcpy(attrbuf + fs->saoffs[ind], val, fs->satab[ind].size); 223240afd8cSMark Johnston *szp += fs->satab[ind].size; 224240afd8cSMark Johnston } 225240afd8cSMark Johnston 226240afd8cSMark Johnston static void 227240afd8cSMark Johnston fs_populate_varszattr(zfs_fs_t *fs, char *attrbuf, const void *val, 228240afd8cSMark Johnston size_t valsz, size_t varoff, uint16_t ind, size_t *szp) 229240afd8cSMark Johnston { 230240afd8cSMark Johnston assert(ind < fs->sacnt); 231240afd8cSMark Johnston assert(fs->saoffs[ind] != 0xffff); 232240afd8cSMark Johnston assert(fs->satab[ind].size == 0); 233240afd8cSMark Johnston 234240afd8cSMark Johnston memcpy(attrbuf + fs->saoffs[ind] + varoff, val, valsz); 235240afd8cSMark Johnston *szp += valsz; 236240afd8cSMark Johnston } 237240afd8cSMark Johnston 238240afd8cSMark Johnston static void 239240afd8cSMark Johnston fs_populate_sattrs(struct fs_populate_arg *arg, const fsnode *cur, 240240afd8cSMark Johnston dnode_phys_t *dnode) 241240afd8cSMark Johnston { 242240afd8cSMark Johnston char target[PATH_MAX]; 243240afd8cSMark Johnston zfs_fs_t *fs; 244240afd8cSMark Johnston zfs_ace_hdr_t aces[3]; 245240afd8cSMark Johnston struct stat *sb; 246240afd8cSMark Johnston sa_hdr_phys_t *sahdr; 247240afd8cSMark Johnston uint64_t daclcount, flags, gen, gid, links, mode, parent, objsize, uid; 248240afd8cSMark Johnston char *attrbuf; 249240afd8cSMark Johnston size_t bonussz, hdrsz; 250240afd8cSMark Johnston int layout; 251240afd8cSMark Johnston 252240afd8cSMark Johnston assert(dnode->dn_bonustype == DMU_OT_SA); 253240afd8cSMark Johnston assert(dnode->dn_nblkptr == 1); 254240afd8cSMark Johnston 255240afd8cSMark Johnston fs = arg->fs; 256240afd8cSMark Johnston sb = &cur->inode->st; 257240afd8cSMark Johnston 258240afd8cSMark Johnston switch (cur->type) { 259240afd8cSMark Johnston case S_IFREG: 260240afd8cSMark Johnston layout = SA_LAYOUT_INDEX_DEFAULT; 261240afd8cSMark Johnston links = cur->inode->nlink; 262240afd8cSMark Johnston objsize = sb->st_size; 263240afd8cSMark Johnston parent = SLIST_FIRST(&arg->dirs)->objid; 264240afd8cSMark Johnston break; 265240afd8cSMark Johnston case S_IFDIR: 266240afd8cSMark Johnston layout = SA_LAYOUT_INDEX_DEFAULT; 267240afd8cSMark Johnston links = 1; /* .. */ 268240afd8cSMark Johnston objsize = 1; /* .. */ 269240afd8cSMark Johnston 270240afd8cSMark Johnston /* 271240afd8cSMark Johnston * The size of a ZPL directory is the number of entries 272240afd8cSMark Johnston * (including "." and ".."), and the link count is the number of 273240afd8cSMark Johnston * entries which are directories (including "." and ".."). 274240afd8cSMark Johnston */ 275240afd8cSMark Johnston for (fsnode *c = fsnode_isroot(cur) ? cur->next : cur->child; 276240afd8cSMark Johnston c != NULL; c = c->next) { 277240afd8cSMark Johnston if (c->type == S_IFDIR) 278240afd8cSMark Johnston links++; 279240afd8cSMark Johnston objsize++; 280240afd8cSMark Johnston } 281240afd8cSMark Johnston 282240afd8cSMark Johnston /* The root directory is its own parent. */ 283240afd8cSMark Johnston parent = SLIST_EMPTY(&arg->dirs) ? 284240afd8cSMark Johnston arg->rootdirid : SLIST_FIRST(&arg->dirs)->objid; 285240afd8cSMark Johnston break; 286240afd8cSMark Johnston case S_IFLNK: { 287240afd8cSMark Johnston ssize_t n; 288240afd8cSMark Johnston 289240afd8cSMark Johnston if ((n = readlinkat(SLIST_FIRST(&arg->dirs)->dirfd, cur->name, 290240afd8cSMark Johnston target, sizeof(target) - 1)) == -1) 291240afd8cSMark Johnston err(1, "readlinkat(%s)", cur->name); 292240afd8cSMark Johnston target[n] = '\0'; 293240afd8cSMark Johnston 294240afd8cSMark Johnston layout = SA_LAYOUT_INDEX_SYMLINK; 295240afd8cSMark Johnston links = 1; 296240afd8cSMark Johnston objsize = strlen(target); 297240afd8cSMark Johnston parent = SLIST_FIRST(&arg->dirs)->objid; 298240afd8cSMark Johnston break; 299240afd8cSMark Johnston } 300240afd8cSMark Johnston default: 301240afd8cSMark Johnston assert(0); 302240afd8cSMark Johnston } 303240afd8cSMark Johnston 304240afd8cSMark Johnston daclcount = nitems(aces); 305240afd8cSMark Johnston flags = ZFS_ACL_TRIVIAL | ZFS_ACL_AUTO_INHERIT | ZFS_NO_EXECS_DENIED | 306240afd8cSMark Johnston ZFS_ARCHIVE | ZFS_AV_MODIFIED; /* XXX-MJ */ 307240afd8cSMark Johnston gen = 1; 308240afd8cSMark Johnston gid = sb->st_gid; 309240afd8cSMark Johnston mode = sb->st_mode; 310240afd8cSMark Johnston uid = sb->st_uid; 311240afd8cSMark Johnston 312240afd8cSMark Johnston memset(aces, 0, sizeof(aces)); 313240afd8cSMark Johnston aces[0].z_flags = ACE_OWNER; 314240afd8cSMark Johnston aces[0].z_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 315240afd8cSMark Johnston aces[0].z_access_mask = ACE_WRITE_ATTRIBUTES | ACE_WRITE_OWNER | 316240afd8cSMark Johnston ACE_WRITE_ACL | ACE_WRITE_NAMED_ATTRS | ACE_READ_ACL | 317240afd8cSMark Johnston ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | ACE_SYNCHRONIZE; 318240afd8cSMark Johnston if ((mode & S_IRUSR) != 0) 319240afd8cSMark Johnston aces[0].z_access_mask |= ACE_READ_DATA; 320240afd8cSMark Johnston if ((mode & S_IWUSR) != 0) 321240afd8cSMark Johnston aces[0].z_access_mask |= ACE_WRITE_DATA | ACE_APPEND_DATA; 322240afd8cSMark Johnston if ((mode & S_IXUSR) != 0) 323240afd8cSMark Johnston aces[0].z_access_mask |= ACE_EXECUTE; 324240afd8cSMark Johnston 325240afd8cSMark Johnston aces[1].z_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP; 326240afd8cSMark Johnston aces[1].z_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 327240afd8cSMark Johnston aces[1].z_access_mask = ACE_READ_ACL | ACE_READ_ATTRIBUTES | 328240afd8cSMark Johnston ACE_READ_NAMED_ATTRS | ACE_SYNCHRONIZE; 329240afd8cSMark Johnston if ((mode & S_IRGRP) != 0) 330240afd8cSMark Johnston aces[1].z_access_mask |= ACE_READ_DATA; 331240afd8cSMark Johnston if ((mode & S_IWGRP) != 0) 332240afd8cSMark Johnston aces[1].z_access_mask |= ACE_WRITE_DATA | ACE_APPEND_DATA; 333240afd8cSMark Johnston if ((mode & S_IXGRP) != 0) 334240afd8cSMark Johnston aces[1].z_access_mask |= ACE_EXECUTE; 335240afd8cSMark Johnston 336240afd8cSMark Johnston aces[2].z_flags = ACE_EVERYONE; 337240afd8cSMark Johnston aces[2].z_type = ACE_ACCESS_ALLOWED_ACE_TYPE; 338240afd8cSMark Johnston aces[2].z_access_mask = ACE_READ_ACL | ACE_READ_ATTRIBUTES | 339240afd8cSMark Johnston ACE_READ_NAMED_ATTRS | ACE_SYNCHRONIZE; 340240afd8cSMark Johnston if ((mode & S_IROTH) != 0) 341240afd8cSMark Johnston aces[2].z_access_mask |= ACE_READ_DATA; 342240afd8cSMark Johnston if ((mode & S_IWOTH) != 0) 343240afd8cSMark Johnston aces[2].z_access_mask |= ACE_WRITE_DATA | ACE_APPEND_DATA; 344240afd8cSMark Johnston if ((mode & S_IXOTH) != 0) 345240afd8cSMark Johnston aces[2].z_access_mask |= ACE_EXECUTE; 346240afd8cSMark Johnston 347240afd8cSMark Johnston switch (layout) { 348240afd8cSMark Johnston case SA_LAYOUT_INDEX_DEFAULT: 349240afd8cSMark Johnston /* At most one variable-length attribute. */ 350240afd8cSMark Johnston hdrsz = sizeof(uint64_t); 351240afd8cSMark Johnston break; 352240afd8cSMark Johnston case SA_LAYOUT_INDEX_SYMLINK: 353240afd8cSMark Johnston /* At most five variable-length attributes. */ 354240afd8cSMark Johnston hdrsz = sizeof(uint64_t) * 2; 355240afd8cSMark Johnston break; 356240afd8cSMark Johnston default: 357240afd8cSMark Johnston assert(0); 358240afd8cSMark Johnston } 359240afd8cSMark Johnston 360240afd8cSMark Johnston sahdr = (sa_hdr_phys_t *)DN_BONUS(dnode); 361240afd8cSMark Johnston sahdr->sa_magic = SA_MAGIC; 362240afd8cSMark Johnston SA_HDR_LAYOUT_INFO_ENCODE(sahdr->sa_layout_info, layout, hdrsz); 363240afd8cSMark Johnston 364240afd8cSMark Johnston bonussz = SA_HDR_SIZE(sahdr); 365240afd8cSMark Johnston attrbuf = (char *)sahdr + SA_HDR_SIZE(sahdr); 366240afd8cSMark Johnston 367240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &daclcount, ZPL_DACL_COUNT, &bonussz); 368240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &flags, ZPL_FLAGS, &bonussz); 369240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &gen, ZPL_GEN, &bonussz); 370240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &gid, ZPL_GID, &bonussz); 371240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &links, ZPL_LINKS, &bonussz); 372240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &mode, ZPL_MODE, &bonussz); 373240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &parent, ZPL_PARENT, &bonussz); 374240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &objsize, ZPL_SIZE, &bonussz); 375240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &uid, ZPL_UID, &bonussz); 376240afd8cSMark Johnston 377240afd8cSMark Johnston /* 378240afd8cSMark Johnston * We deliberately set atime = mtime here to ensure that images are 379240afd8cSMark Johnston * reproducible. 380240afd8cSMark Johnston */ 381240afd8cSMark Johnston assert(sizeof(sb->st_mtim) == fs->satab[ZPL_ATIME].size); 382240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &sb->st_mtim, ZPL_ATIME, &bonussz); 383240afd8cSMark Johnston assert(sizeof(sb->st_ctim) == fs->satab[ZPL_CTIME].size); 384240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &sb->st_ctim, ZPL_CTIME, &bonussz); 385240afd8cSMark Johnston assert(sizeof(sb->st_mtim) == fs->satab[ZPL_MTIME].size); 386240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &sb->st_mtim, ZPL_MTIME, &bonussz); 387240afd8cSMark Johnston assert(sizeof(sb->st_birthtim) == fs->satab[ZPL_CRTIME].size); 388240afd8cSMark Johnston fs_populate_attr(fs, attrbuf, &sb->st_birthtim, ZPL_CRTIME, &bonussz); 389240afd8cSMark Johnston 390240afd8cSMark Johnston fs_populate_varszattr(fs, attrbuf, aces, sizeof(aces), 0, 391240afd8cSMark Johnston ZPL_DACL_ACES, &bonussz); 392240afd8cSMark Johnston sahdr->sa_lengths[0] = sizeof(aces); 393240afd8cSMark Johnston 394240afd8cSMark Johnston if (cur->type == S_IFLNK) { 395240afd8cSMark Johnston assert(layout == SA_LAYOUT_INDEX_SYMLINK); 396240afd8cSMark Johnston /* Need to use a spill block pointer if the target is long. */ 397240afd8cSMark Johnston assert(bonussz + objsize <= DN_OLD_MAX_BONUSLEN); 398240afd8cSMark Johnston fs_populate_varszattr(fs, attrbuf, target, objsize, 399240afd8cSMark Johnston sahdr->sa_lengths[0], ZPL_SYMLINK, &bonussz); 400240afd8cSMark Johnston sahdr->sa_lengths[1] = (uint16_t)objsize; 401240afd8cSMark Johnston } 402240afd8cSMark Johnston 403240afd8cSMark Johnston dnode->dn_bonuslen = bonussz; 404240afd8cSMark Johnston } 405240afd8cSMark Johnston 406240afd8cSMark Johnston static void 407240afd8cSMark Johnston fs_populate_file(fsnode *cur, struct fs_populate_arg *arg) 408240afd8cSMark Johnston { 409240afd8cSMark Johnston struct dnode_cursor *c; 410240afd8cSMark Johnston dnode_phys_t *dnode; 411240afd8cSMark Johnston zfs_opt_t *zfs; 412240afd8cSMark Johnston char *buf; 413240afd8cSMark Johnston uint64_t dnid; 414240afd8cSMark Johnston ssize_t n; 415240afd8cSMark Johnston size_t bufsz; 416240afd8cSMark Johnston off_t size, target; 417240afd8cSMark Johnston int fd; 418240afd8cSMark Johnston 419240afd8cSMark Johnston assert(cur->type == S_IFREG); 420240afd8cSMark Johnston assert((cur->inode->flags & FI_ROOT) == 0); 421240afd8cSMark Johnston 422240afd8cSMark Johnston zfs = arg->zfs; 423240afd8cSMark Johnston 424240afd8cSMark Johnston assert(cur->inode->ino != 0); 425240afd8cSMark Johnston if ((cur->inode->flags & FI_ALLOCATED) != 0) { 426240afd8cSMark Johnston /* 427240afd8cSMark Johnston * This is a hard link of an existing file. 428240afd8cSMark Johnston * 429240afd8cSMark Johnston * XXX-MJ need to check whether it crosses datasets, add a test 430240afd8cSMark Johnston * case for that 431240afd8cSMark Johnston */ 432240afd8cSMark Johnston fs_populate_dirent(arg, cur, cur->inode->ino); 433240afd8cSMark Johnston return; 434240afd8cSMark Johnston } 435240afd8cSMark Johnston 436240afd8cSMark Johnston dnode = objset_dnode_bonus_alloc(arg->fs->os, 437240afd8cSMark Johnston DMU_OT_PLAIN_FILE_CONTENTS, DMU_OT_SA, 0, &dnid); 438240afd8cSMark Johnston cur->inode->ino = dnid; 439240afd8cSMark Johnston cur->inode->flags |= FI_ALLOCATED; 440240afd8cSMark Johnston 441240afd8cSMark Johnston fd = openat(SLIST_FIRST(&arg->dirs)->dirfd, cur->name, O_RDONLY); 442240afd8cSMark Johnston if (fd == -1) 443240afd8cSMark Johnston err(1, "openat(%s)", cur->name); 444240afd8cSMark Johnston 445240afd8cSMark Johnston buf = zfs->filebuf; 446240afd8cSMark Johnston bufsz = sizeof(zfs->filebuf); 447240afd8cSMark Johnston size = cur->inode->st.st_size; 448240afd8cSMark Johnston c = dnode_cursor_init(zfs, arg->fs->os, dnode, size, 0); 449240afd8cSMark Johnston for (off_t foff = 0; foff < size; foff += target) { 450240afd8cSMark Johnston off_t loc, sofar; 451240afd8cSMark Johnston 452240afd8cSMark Johnston /* 453240afd8cSMark Johnston * Fill up our buffer, handling partial reads. 454240afd8cSMark Johnston * 455240afd8cSMark Johnston * It might be profitable to use copy_file_range(2) here. 456240afd8cSMark Johnston */ 457240afd8cSMark Johnston sofar = 0; 458240afd8cSMark Johnston target = MIN(size - foff, (off_t)bufsz); 459240afd8cSMark Johnston do { 460240afd8cSMark Johnston n = read(fd, buf + sofar, target); 461240afd8cSMark Johnston if (n < 0) 462240afd8cSMark Johnston err(1, "reading from '%s'", cur->name); 463240afd8cSMark Johnston if (n == 0) 464240afd8cSMark Johnston errx(1, "unexpected EOF reading '%s'", 465240afd8cSMark Johnston cur->name); 466240afd8cSMark Johnston sofar += n; 467240afd8cSMark Johnston } while (sofar < target); 468240afd8cSMark Johnston 469240afd8cSMark Johnston if (target < (off_t)bufsz) 470240afd8cSMark Johnston memset(buf + target, 0, bufsz - target); 471240afd8cSMark Johnston 472240afd8cSMark Johnston loc = objset_space_alloc(zfs, arg->fs->os, &target); 473240afd8cSMark Johnston vdev_pwrite_dnode_indir(zfs, dnode, 0, 1, buf, target, loc, 474240afd8cSMark Johnston dnode_cursor_next(zfs, c, foff)); 475240afd8cSMark Johnston } 476240afd8cSMark Johnston if (close(fd) != 0) 477240afd8cSMark Johnston err(1, "close"); 478240afd8cSMark Johnston dnode_cursor_finish(zfs, c); 479240afd8cSMark Johnston 480240afd8cSMark Johnston fs_populate_sattrs(arg, cur, dnode); 481240afd8cSMark Johnston fs_populate_dirent(arg, cur, dnid); 482240afd8cSMark Johnston } 483240afd8cSMark Johnston 484240afd8cSMark Johnston static void 485240afd8cSMark Johnston fs_populate_dir(fsnode *cur, struct fs_populate_arg *arg) 486240afd8cSMark Johnston { 487240afd8cSMark Johnston dnode_phys_t *dnode; 488240afd8cSMark Johnston zfs_objset_t *os; 489240afd8cSMark Johnston uint64_t dnid; 490240afd8cSMark Johnston int dirfd; 491240afd8cSMark Johnston 492240afd8cSMark Johnston assert(cur->type == S_IFDIR); 493240afd8cSMark Johnston assert((cur->inode->flags & FI_ALLOCATED) == 0); 494240afd8cSMark Johnston 495240afd8cSMark Johnston os = arg->fs->os; 496240afd8cSMark Johnston 497240afd8cSMark Johnston dnode = objset_dnode_bonus_alloc(os, DMU_OT_DIRECTORY_CONTENTS, 498240afd8cSMark Johnston DMU_OT_SA, 0, &dnid); 499240afd8cSMark Johnston 500240afd8cSMark Johnston /* 501240afd8cSMark Johnston * Add an entry to the parent directory and open this directory. 502240afd8cSMark Johnston */ 503240afd8cSMark Johnston if (!SLIST_EMPTY(&arg->dirs)) { 504240afd8cSMark Johnston fs_populate_dirent(arg, cur, dnid); 505240afd8cSMark Johnston dirfd = openat(SLIST_FIRST(&arg->dirs)->dirfd, cur->name, 506240afd8cSMark Johnston O_DIRECTORY); 507240afd8cSMark Johnston if (dirfd < 0) 508240afd8cSMark Johnston err(1, "open(%s)", cur->name); 509240afd8cSMark Johnston } else { 510240afd8cSMark Johnston arg->rootdirid = dnid; 511240afd8cSMark Johnston dirfd = arg->dirfd; 512240afd8cSMark Johnston } 513240afd8cSMark Johnston 514240afd8cSMark Johnston /* 515240afd8cSMark Johnston * Set ZPL attributes. 516240afd8cSMark Johnston */ 517240afd8cSMark Johnston fs_populate_sattrs(arg, cur, dnode); 518240afd8cSMark Johnston 519240afd8cSMark Johnston /* 520240afd8cSMark Johnston * If this is a root directory, then its children belong to a different 521240afd8cSMark Johnston * dataset and this directory remains empty in the current objset. 522240afd8cSMark Johnston */ 523240afd8cSMark Johnston if ((cur->inode->flags & FI_ROOT) == 0) { 524240afd8cSMark Johnston struct fs_populate_dir *dir; 525240afd8cSMark Johnston 526240afd8cSMark Johnston dir = ecalloc(1, sizeof(*dir)); 527240afd8cSMark Johnston dir->dirfd = dirfd; 528240afd8cSMark Johnston dir->objid = dnid; 529240afd8cSMark Johnston dir->zap = zap_alloc(os, dnode); 530240afd8cSMark Johnston SLIST_INSERT_HEAD(&arg->dirs, dir, next); 531240afd8cSMark Johnston } else { 532240afd8cSMark Johnston zap_write(arg->zfs, zap_alloc(os, dnode)); 533240afd8cSMark Johnston fs_build_one(arg->zfs, cur->inode->param, cur->child, dirfd); 534240afd8cSMark Johnston } 535240afd8cSMark Johnston } 536240afd8cSMark Johnston 537240afd8cSMark Johnston static void 538240afd8cSMark Johnston fs_populate_symlink(fsnode *cur, struct fs_populate_arg *arg) 539240afd8cSMark Johnston { 540240afd8cSMark Johnston dnode_phys_t *dnode; 541240afd8cSMark Johnston uint64_t dnid; 542240afd8cSMark Johnston 543240afd8cSMark Johnston assert(cur->type == S_IFLNK); 544240afd8cSMark Johnston assert((cur->inode->flags & (FI_ALLOCATED | FI_ROOT)) == 0); 545240afd8cSMark Johnston 546240afd8cSMark Johnston dnode = objset_dnode_bonus_alloc(arg->fs->os, 547240afd8cSMark Johnston DMU_OT_PLAIN_FILE_CONTENTS, DMU_OT_SA, 0, &dnid); 548240afd8cSMark Johnston 549240afd8cSMark Johnston fs_populate_dirent(arg, cur, dnid); 550240afd8cSMark Johnston 551240afd8cSMark Johnston fs_populate_sattrs(arg, cur, dnode); 552240afd8cSMark Johnston } 553240afd8cSMark Johnston 554240afd8cSMark Johnston static int 555240afd8cSMark Johnston fs_foreach_populate(fsnode *cur, void *_arg) 556240afd8cSMark Johnston { 557240afd8cSMark Johnston struct fs_populate_arg *arg; 558240afd8cSMark Johnston struct fs_populate_dir *dir; 559240afd8cSMark Johnston int ret; 560240afd8cSMark Johnston 561240afd8cSMark Johnston arg = _arg; 562240afd8cSMark Johnston switch (cur->type) { 563240afd8cSMark Johnston case S_IFREG: 564240afd8cSMark Johnston fs_populate_file(cur, arg); 565240afd8cSMark Johnston break; 566240afd8cSMark Johnston case S_IFDIR: 567240afd8cSMark Johnston if (fsnode_isroot(cur)) 568240afd8cSMark Johnston break; 569240afd8cSMark Johnston fs_populate_dir(cur, arg); 570240afd8cSMark Johnston break; 571240afd8cSMark Johnston case S_IFLNK: 572240afd8cSMark Johnston fs_populate_symlink(cur, arg); 573240afd8cSMark Johnston break; 574240afd8cSMark Johnston default: 575240afd8cSMark Johnston assert(0); 576240afd8cSMark Johnston } 577240afd8cSMark Johnston 578240afd8cSMark Johnston ret = (cur->inode->flags & FI_ROOT) != 0 ? 0 : 1; 579240afd8cSMark Johnston 580240afd8cSMark Johnston if (cur->next == NULL && 581240afd8cSMark Johnston (cur->child == NULL || (cur->inode->flags & FI_ROOT) != 0)) { 582240afd8cSMark Johnston /* 583240afd8cSMark Johnston * We reached a terminal node in a subtree. Walk back up and 584240afd8cSMark Johnston * write out directories. We're done once we hit the root of a 585240afd8cSMark Johnston * dataset or find a level where we're not on the edge of the 586240afd8cSMark Johnston * tree. 587240afd8cSMark Johnston */ 588240afd8cSMark Johnston do { 589240afd8cSMark Johnston dir = SLIST_FIRST(&arg->dirs); 590240afd8cSMark Johnston SLIST_REMOVE_HEAD(&arg->dirs, next); 591240afd8cSMark Johnston zap_write(arg->zfs, dir->zap); 592240afd8cSMark Johnston if (dir->dirfd != -1 && close(dir->dirfd) != 0) 593240afd8cSMark Johnston err(1, "close"); 594240afd8cSMark Johnston free(dir); 595240afd8cSMark Johnston cur = cur->parent; 596240afd8cSMark Johnston } while (cur != NULL && cur->next == NULL && 597240afd8cSMark Johnston (cur->inode->flags & FI_ROOT) == 0); 598240afd8cSMark Johnston } 599240afd8cSMark Johnston 600240afd8cSMark Johnston return (ret); 601240afd8cSMark Johnston } 602240afd8cSMark Johnston 603240afd8cSMark Johnston static void 604240afd8cSMark Johnston fs_add_zpl_attr_layout(zfs_zap_t *zap, unsigned int index, 605240afd8cSMark Johnston const sa_attr_type_t layout[], size_t sacnt) 606240afd8cSMark Johnston { 607240afd8cSMark Johnston char ti[16]; 608240afd8cSMark Johnston 609240afd8cSMark Johnston assert(sizeof(layout[0]) == 2); 610240afd8cSMark Johnston 611240afd8cSMark Johnston snprintf(ti, sizeof(ti), "%u", index); 612240afd8cSMark Johnston zap_add(zap, ti, sizeof(sa_attr_type_t), sacnt, 613240afd8cSMark Johnston (const uint8_t *)layout); 614240afd8cSMark Johnston } 615240afd8cSMark Johnston 616240afd8cSMark Johnston /* 617240afd8cSMark Johnston * Initialize system attribute tables. 618240afd8cSMark Johnston * 619240afd8cSMark Johnston * There are two elements to this. First, we write the zpl_attrs[] and 620240afd8cSMark Johnston * zpl_attr_layout[] tables to disk. Then we create a lookup table which 621240afd8cSMark Johnston * allows us to set file attributes quickly. 622240afd8cSMark Johnston */ 623240afd8cSMark Johnston static uint64_t 624240afd8cSMark Johnston fs_set_zpl_attrs(zfs_opt_t *zfs, zfs_fs_t *fs) 625240afd8cSMark Johnston { 626240afd8cSMark Johnston zfs_zap_t *sazap, *salzap, *sarzap; 627240afd8cSMark Johnston zfs_objset_t *os; 628240afd8cSMark Johnston dnode_phys_t *saobj, *salobj, *sarobj; 629240afd8cSMark Johnston uint64_t saobjid, salobjid, sarobjid; 630240afd8cSMark Johnston uint16_t offset; 631240afd8cSMark Johnston 632240afd8cSMark Johnston os = fs->os; 633240afd8cSMark Johnston 634240afd8cSMark Johnston /* 635240afd8cSMark Johnston * The on-disk tables are stored in two ZAP objects, the registry object 636240afd8cSMark Johnston * and the layout object. Individual attributes are described by 637240afd8cSMark Johnston * entries in the registry object; for example, the value for the 638240afd8cSMark Johnston * "ZPL_SIZE" key gives the size and encoding of the ZPL_SIZE attribute. 639240afd8cSMark Johnston * The attributes of a file are ordered according to one of the layouts 640240afd8cSMark Johnston * defined in the layout object. The master node object is simply used 641240afd8cSMark Johnston * to locate the registry and layout objects. 642240afd8cSMark Johnston */ 643240afd8cSMark Johnston saobj = objset_dnode_alloc(os, DMU_OT_SA_MASTER_NODE, &saobjid); 644240afd8cSMark Johnston salobj = objset_dnode_alloc(os, DMU_OT_SA_ATTR_LAYOUTS, &salobjid); 645240afd8cSMark Johnston sarobj = objset_dnode_alloc(os, DMU_OT_SA_ATTR_REGISTRATION, &sarobjid); 646240afd8cSMark Johnston 647240afd8cSMark Johnston sarzap = zap_alloc(os, sarobj); 648240afd8cSMark Johnston for (size_t i = 0; i < nitems(zpl_attrs); i++) { 649240afd8cSMark Johnston const zfs_sattr_t *sa; 650240afd8cSMark Johnston uint64_t attr; 651240afd8cSMark Johnston 652240afd8cSMark Johnston attr = 0; 653240afd8cSMark Johnston sa = &zpl_attrs[i]; 654240afd8cSMark Johnston SA_ATTR_ENCODE(attr, (uint64_t)i, sa->size, sa->bs); 655240afd8cSMark Johnston zap_add_uint64(sarzap, sa->name, attr); 656240afd8cSMark Johnston } 657240afd8cSMark Johnston zap_write(zfs, sarzap); 658240afd8cSMark Johnston 659240afd8cSMark Johnston /* 660240afd8cSMark Johnston * Layouts are arrays of indices into the registry. We define two 661240afd8cSMark Johnston * layouts for use by the ZPL, one for non-symlinks and one for 662240afd8cSMark Johnston * symlinks. They are identical except that the symlink layout includes 663240afd8cSMark Johnston * ZPL_SYMLINK as its final attribute. 664240afd8cSMark Johnston */ 665240afd8cSMark Johnston salzap = zap_alloc(os, salobj); 666240afd8cSMark Johnston assert(zpl_attr_layout[nitems(zpl_attr_layout) - 1] == ZPL_SYMLINK); 667240afd8cSMark Johnston fs_add_zpl_attr_layout(salzap, SA_LAYOUT_INDEX_DEFAULT, 668240afd8cSMark Johnston zpl_attr_layout, nitems(zpl_attr_layout) - 1); 669240afd8cSMark Johnston fs_add_zpl_attr_layout(salzap, SA_LAYOUT_INDEX_SYMLINK, 670240afd8cSMark Johnston zpl_attr_layout, nitems(zpl_attr_layout)); 671240afd8cSMark Johnston zap_write(zfs, salzap); 672240afd8cSMark Johnston 673240afd8cSMark Johnston sazap = zap_alloc(os, saobj); 674240afd8cSMark Johnston zap_add_uint64(sazap, SA_LAYOUTS, salobjid); 675240afd8cSMark Johnston zap_add_uint64(sazap, SA_REGISTRY, sarobjid); 676240afd8cSMark Johnston zap_write(zfs, sazap); 677240afd8cSMark Johnston 678240afd8cSMark Johnston /* Sanity check. */ 679240afd8cSMark Johnston for (size_t i = 0; i < nitems(zpl_attrs); i++) 680240afd8cSMark Johnston assert(i == zpl_attrs[i].id); 681240afd8cSMark Johnston 682240afd8cSMark Johnston /* 683240afd8cSMark Johnston * Build the offset table used when setting file attributes. File 684240afd8cSMark Johnston * attributes are stored in the object's bonus buffer; this table 685240afd8cSMark Johnston * provides the buffer offset of attributes referenced by the layout 686240afd8cSMark Johnston * table. 687240afd8cSMark Johnston */ 688240afd8cSMark Johnston fs->sacnt = nitems(zpl_attrs); 689240afd8cSMark Johnston fs->saoffs = ecalloc(fs->sacnt, sizeof(*fs->saoffs)); 690240afd8cSMark Johnston for (size_t i = 0; i < fs->sacnt; i++) 691240afd8cSMark Johnston fs->saoffs[i] = 0xffff; 692240afd8cSMark Johnston offset = 0; 693240afd8cSMark Johnston for (size_t i = 0; i < nitems(zpl_attr_layout); i++) { 694240afd8cSMark Johnston uint16_t size; 695240afd8cSMark Johnston 696240afd8cSMark Johnston assert(zpl_attr_layout[i] < fs->sacnt); 697240afd8cSMark Johnston 698240afd8cSMark Johnston fs->saoffs[zpl_attr_layout[i]] = offset; 699240afd8cSMark Johnston size = zpl_attrs[zpl_attr_layout[i]].size; 700240afd8cSMark Johnston offset += size; 701240afd8cSMark Johnston } 702240afd8cSMark Johnston fs->satab = zpl_attrs; 703240afd8cSMark Johnston 704240afd8cSMark Johnston return (saobjid); 705240afd8cSMark Johnston } 706240afd8cSMark Johnston 707240afd8cSMark Johnston static void 708240afd8cSMark Johnston fs_layout_one(zfs_opt_t *zfs, zfs_dsl_dir_t *dsldir, void *arg) 709240afd8cSMark Johnston { 710240afd8cSMark Johnston char *mountpoint, *origmountpoint, *name, *next; 711240afd8cSMark Johnston fsnode *cur, *root; 712240afd8cSMark Johnston uint64_t canmount; 713240afd8cSMark Johnston 714240afd8cSMark Johnston if (!dsl_dir_has_dataset(dsldir)) 715240afd8cSMark Johnston return; 716240afd8cSMark Johnston 717*78d7704bSMark Johnston if (dsl_dir_get_canmount(dsldir, &canmount) == 0 && canmount == 0) 718*78d7704bSMark Johnston return; 719240afd8cSMark Johnston mountpoint = dsl_dir_get_mountpoint(zfs, dsldir); 720240afd8cSMark Johnston if (mountpoint == NULL) 721240afd8cSMark Johnston return; 722240afd8cSMark Johnston 723240afd8cSMark Johnston /* 724240afd8cSMark Johnston * If we were asked to specify a bootfs, set it here. 725240afd8cSMark Johnston */ 726240afd8cSMark Johnston if (zfs->bootfs != NULL && strcmp(zfs->bootfs, 727240afd8cSMark Johnston dsl_dir_fullname(dsldir)) == 0) { 728240afd8cSMark Johnston zap_add_uint64(zfs->poolprops, "bootfs", 729240afd8cSMark Johnston dsl_dir_dataset_id(dsldir)); 730240afd8cSMark Johnston } 731240afd8cSMark Johnston 732240afd8cSMark Johnston origmountpoint = mountpoint; 733240afd8cSMark Johnston 734240afd8cSMark Johnston /* 735240afd8cSMark Johnston * Figure out which fsnode corresponds to our mountpoint. 736240afd8cSMark Johnston */ 737240afd8cSMark Johnston root = arg; 738240afd8cSMark Johnston cur = root; 739240afd8cSMark Johnston if (strcmp(mountpoint, zfs->rootpath) != 0) { 740240afd8cSMark Johnston mountpoint += strlen(zfs->rootpath); 741240afd8cSMark Johnston 742240afd8cSMark Johnston /* 743240afd8cSMark Johnston * Look up the directory in the staged tree. For example, if 744240afd8cSMark Johnston * the dataset's mount point is /foo/bar/baz, we'll search the 745240afd8cSMark Johnston * root directory for "foo", search "foo" for "baz", and so on. 746240afd8cSMark Johnston * Each intermediate name must refer to a directory; the final 747240afd8cSMark Johnston * component need not exist. 748240afd8cSMark Johnston */ 749240afd8cSMark Johnston cur = root; 750240afd8cSMark Johnston for (next = name = mountpoint; next != NULL;) { 751240afd8cSMark Johnston for (; *next == '/'; next++) 752240afd8cSMark Johnston ; 753240afd8cSMark Johnston name = strsep(&next, "/"); 754240afd8cSMark Johnston 755240afd8cSMark Johnston for (; cur != NULL && strcmp(cur->name, name) != 0; 756240afd8cSMark Johnston cur = cur->next) 757240afd8cSMark Johnston ; 758240afd8cSMark Johnston if (cur == NULL) { 759240afd8cSMark Johnston if (next == NULL) 760240afd8cSMark Johnston break; 761240afd8cSMark Johnston errx(1, "missing mountpoint directory for `%s'", 762240afd8cSMark Johnston dsl_dir_fullname(dsldir)); 763240afd8cSMark Johnston } 764240afd8cSMark Johnston if (cur->type != S_IFDIR) { 765240afd8cSMark Johnston errx(1, 766240afd8cSMark Johnston "mountpoint for `%s' is not a directory", 767240afd8cSMark Johnston dsl_dir_fullname(dsldir)); 768240afd8cSMark Johnston } 769240afd8cSMark Johnston if (next != NULL) 770240afd8cSMark Johnston cur = cur->child; 771240afd8cSMark Johnston } 772240afd8cSMark Johnston } 773240afd8cSMark Johnston 774240afd8cSMark Johnston if (cur != NULL) { 775240afd8cSMark Johnston assert(cur->type == S_IFDIR); 776240afd8cSMark Johnston 777240afd8cSMark Johnston /* 778240afd8cSMark Johnston * Multiple datasets shouldn't share a mountpoint. It's 779240afd8cSMark Johnston * technically allowed, but it's not clear what makefs should do 780240afd8cSMark Johnston * in that case. 781240afd8cSMark Johnston */ 782240afd8cSMark Johnston assert((cur->inode->flags & FI_ROOT) == 0); 783240afd8cSMark Johnston if (cur != root) 784240afd8cSMark Johnston cur->inode->flags |= FI_ROOT; 785240afd8cSMark Johnston assert(cur->inode->param == NULL); 786240afd8cSMark Johnston cur->inode->param = dsldir; 787240afd8cSMark Johnston } 788240afd8cSMark Johnston 789240afd8cSMark Johnston free(origmountpoint); 790240afd8cSMark Johnston } 791240afd8cSMark Johnston 792240afd8cSMark Johnston static int 793240afd8cSMark Johnston fs_foreach_mark(fsnode *cur, void *arg) 794240afd8cSMark Johnston { 795240afd8cSMark Johnston uint64_t *countp; 796240afd8cSMark Johnston 797240afd8cSMark Johnston countp = arg; 798240afd8cSMark Johnston if (cur->type == S_IFDIR && fsnode_isroot(cur)) 799240afd8cSMark Johnston return (1); 800240afd8cSMark Johnston 801240afd8cSMark Johnston if (cur->inode->ino == 0) { 802240afd8cSMark Johnston cur->inode->ino = ++(*countp); 803240afd8cSMark Johnston cur->inode->nlink = 1; 804240afd8cSMark Johnston } else { 805240afd8cSMark Johnston cur->inode->nlink++; 806240afd8cSMark Johnston } 807240afd8cSMark Johnston 808240afd8cSMark Johnston return ((cur->inode->flags & FI_ROOT) != 0 ? 0 : 1); 809240afd8cSMark Johnston } 810240afd8cSMark Johnston 811240afd8cSMark Johnston /* 812240afd8cSMark Johnston * Create a filesystem dataset. More specifically: 813240afd8cSMark Johnston * - create an object set for the dataset, 814240afd8cSMark Johnston * - add required metadata (SA tables, property definitions, etc.) to that 815240afd8cSMark Johnston * object set, 816240afd8cSMark Johnston * - optionally populate the object set with file objects, using "root" as the 817240afd8cSMark Johnston * root directory. 818240afd8cSMark Johnston * 819240afd8cSMark Johnston * "dirfd" is a directory descriptor for the directory referenced by "root". It 820240afd8cSMark Johnston * is closed before returning. 821240afd8cSMark Johnston */ 822240afd8cSMark Johnston static void 823240afd8cSMark Johnston fs_build_one(zfs_opt_t *zfs, zfs_dsl_dir_t *dsldir, fsnode *root, int dirfd) 824240afd8cSMark Johnston { 825240afd8cSMark Johnston struct fs_populate_arg arg; 826240afd8cSMark Johnston zfs_fs_t fs; 827240afd8cSMark Johnston zfs_zap_t *masterzap; 828240afd8cSMark Johnston zfs_objset_t *os; 829240afd8cSMark Johnston dnode_phys_t *deleteq, *masterobj; 830240afd8cSMark Johnston uint64_t deleteqid, dnodecount, moid, rootdirid, saobjid; 831240afd8cSMark Johnston bool fakedroot; 832240afd8cSMark Johnston 833240afd8cSMark Johnston /* 834240afd8cSMark Johnston * This dataset's mountpoint doesn't exist in the staging tree, or the 835240afd8cSMark Johnston * dataset doesn't have a mountpoint at all. In either case we still 836240afd8cSMark Johnston * need a root directory. Fake up a root fsnode to handle this case. 837240afd8cSMark Johnston */ 838240afd8cSMark Johnston fakedroot = root == NULL; 839240afd8cSMark Johnston if (fakedroot) { 840240afd8cSMark Johnston struct stat *stp; 841240afd8cSMark Johnston 842240afd8cSMark Johnston assert(dirfd == -1); 843240afd8cSMark Johnston 844240afd8cSMark Johnston root = ecalloc(1, sizeof(*root)); 845240afd8cSMark Johnston root->inode = ecalloc(1, sizeof(*root->inode)); 846240afd8cSMark Johnston root->name = estrdup("."); 847240afd8cSMark Johnston root->type = S_IFDIR; 848240afd8cSMark Johnston 849240afd8cSMark Johnston stp = &root->inode->st; 850240afd8cSMark Johnston stp->st_uid = 0; 851240afd8cSMark Johnston stp->st_gid = 0; 852240afd8cSMark Johnston stp->st_mode = S_IFDIR | 0755; 853240afd8cSMark Johnston } 854240afd8cSMark Johnston assert(root->type == S_IFDIR); 855240afd8cSMark Johnston assert(fsnode_isroot(root)); 856240afd8cSMark Johnston 857240afd8cSMark Johnston /* 858240afd8cSMark Johnston * Initialize the object set for this dataset. 859240afd8cSMark Johnston */ 860240afd8cSMark Johnston os = objset_alloc(zfs, DMU_OST_ZFS); 861240afd8cSMark Johnston masterobj = objset_dnode_alloc(os, DMU_OT_MASTER_NODE, &moid); 862240afd8cSMark Johnston assert(moid == MASTER_NODE_OBJ); 863240afd8cSMark Johnston 864240afd8cSMark Johnston memset(&fs, 0, sizeof(fs)); 865240afd8cSMark Johnston fs.os = os; 866240afd8cSMark Johnston 867240afd8cSMark Johnston /* 868240afd8cSMark Johnston * Create the ZAP SA layout now since filesystem object dnodes will 869240afd8cSMark Johnston * refer to those attributes. 870240afd8cSMark Johnston */ 871240afd8cSMark Johnston saobjid = fs_set_zpl_attrs(zfs, &fs); 872240afd8cSMark Johnston 873240afd8cSMark Johnston /* 874240afd8cSMark Johnston * Make a pass over the staged directory to detect hard links and assign 875240afd8cSMark Johnston * virtual dnode numbers. 876240afd8cSMark Johnston */ 877240afd8cSMark Johnston dnodecount = 1; /* root directory */ 878240afd8cSMark Johnston fsnode_foreach(root, fs_foreach_mark, &dnodecount); 879240afd8cSMark Johnston 880240afd8cSMark Johnston /* 881240afd8cSMark Johnston * Make a second pass to populate the dataset with files from the 882240afd8cSMark Johnston * staged directory. Most of our runtime is spent here. 883240afd8cSMark Johnston */ 884240afd8cSMark Johnston arg.dirfd = dirfd; 885240afd8cSMark Johnston arg.zfs = zfs; 886240afd8cSMark Johnston arg.fs = &fs; 887240afd8cSMark Johnston SLIST_INIT(&arg.dirs); 888240afd8cSMark Johnston fs_populate_dir(root, &arg); 889240afd8cSMark Johnston assert(!SLIST_EMPTY(&arg.dirs)); 890240afd8cSMark Johnston fsnode_foreach(root, fs_foreach_populate, &arg); 891240afd8cSMark Johnston assert(SLIST_EMPTY(&arg.dirs)); 892240afd8cSMark Johnston rootdirid = arg.rootdirid; 893240afd8cSMark Johnston 894240afd8cSMark Johnston /* 895240afd8cSMark Johnston * Create an empty delete queue. We don't do anything with it, but 896240afd8cSMark Johnston * OpenZFS will refuse to mount filesystems that don't have one. 897240afd8cSMark Johnston */ 898240afd8cSMark Johnston deleteq = objset_dnode_alloc(os, DMU_OT_UNLINKED_SET, &deleteqid); 899240afd8cSMark Johnston zap_write(zfs, zap_alloc(os, deleteq)); 900240afd8cSMark Johnston 901240afd8cSMark Johnston /* 902240afd8cSMark Johnston * Populate and write the master node object. This is a ZAP object 903240afd8cSMark Johnston * containing various dataset properties and the object IDs of the root 904240afd8cSMark Johnston * directory and delete queue. 905240afd8cSMark Johnston */ 906240afd8cSMark Johnston masterzap = zap_alloc(os, masterobj); 907240afd8cSMark Johnston zap_add_uint64(masterzap, ZFS_ROOT_OBJ, rootdirid); 908240afd8cSMark Johnston zap_add_uint64(masterzap, ZFS_UNLINKED_SET, deleteqid); 909240afd8cSMark Johnston zap_add_uint64(masterzap, ZFS_SA_ATTRS, saobjid); 910240afd8cSMark Johnston zap_add_uint64(masterzap, ZPL_VERSION_OBJ, 5 /* ZPL_VERSION_SA */); 911240afd8cSMark Johnston zap_add_uint64(masterzap, "normalization", 0 /* off */); 912240afd8cSMark Johnston zap_add_uint64(masterzap, "utf8only", 0 /* off */); 913240afd8cSMark Johnston zap_add_uint64(masterzap, "casesensitivity", 0 /* case sensitive */); 914240afd8cSMark Johnston zap_add_uint64(masterzap, "acltype", 2 /* NFSv4 */); 915240afd8cSMark Johnston zap_write(zfs, masterzap); 916240afd8cSMark Johnston 917240afd8cSMark Johnston /* 918240afd8cSMark Johnston * All finished with this object set, we may as well write it now. 919240afd8cSMark Johnston * The DSL layer will sum up the bytes consumed by each dataset using 920240afd8cSMark Johnston * information stored in the object set, so it can't be freed just yet. 921240afd8cSMark Johnston */ 922240afd8cSMark Johnston dsl_dir_dataset_write(zfs, os, dsldir); 923240afd8cSMark Johnston 924240afd8cSMark Johnston if (fakedroot) { 925240afd8cSMark Johnston free(root->inode); 926240afd8cSMark Johnston free(root->name); 927240afd8cSMark Johnston free(root); 928240afd8cSMark Johnston } 929240afd8cSMark Johnston free(fs.saoffs); 930240afd8cSMark Johnston } 931240afd8cSMark Johnston 932240afd8cSMark Johnston /* 933240afd8cSMark Johnston * Create an object set for each DSL directory which has a dataset and doesn't 934240afd8cSMark Johnston * already have an object set. 935240afd8cSMark Johnston */ 936240afd8cSMark Johnston static void 937240afd8cSMark Johnston fs_build_unmounted(zfs_opt_t *zfs, zfs_dsl_dir_t *dsldir, void *arg __unused) 938240afd8cSMark Johnston { 939240afd8cSMark Johnston if (dsl_dir_has_dataset(dsldir) && !dsl_dir_dataset_has_objset(dsldir)) 940240afd8cSMark Johnston fs_build_one(zfs, dsldir, NULL, -1); 941240afd8cSMark Johnston } 942240afd8cSMark Johnston 943240afd8cSMark Johnston /* 944240afd8cSMark Johnston * Create our datasets and populate them with files. 945240afd8cSMark Johnston */ 946240afd8cSMark Johnston void 947240afd8cSMark Johnston fs_build(zfs_opt_t *zfs, int dirfd, fsnode *root) 948240afd8cSMark Johnston { 949240afd8cSMark Johnston /* 950240afd8cSMark Johnston * Run through our datasets and find the root fsnode for each one. Each 951240afd8cSMark Johnston * root fsnode is flagged so that we can figure out which dataset it 952240afd8cSMark Johnston * belongs to. 953240afd8cSMark Johnston */ 954240afd8cSMark Johnston dsl_dir_foreach(zfs, zfs->rootdsldir, fs_layout_one, root); 955240afd8cSMark Johnston 956240afd8cSMark Johnston /* 957240afd8cSMark Johnston * Did we find our boot filesystem? 958240afd8cSMark Johnston */ 959240afd8cSMark Johnston if (zfs->bootfs != NULL && !zap_entry_exists(zfs->poolprops, "bootfs")) 960240afd8cSMark Johnston errx(1, "no mounted dataset matches bootfs property `%s'", 961240afd8cSMark Johnston zfs->bootfs); 962240afd8cSMark Johnston 963240afd8cSMark Johnston /* 964240afd8cSMark Johnston * Traverse the file hierarchy starting from the root fsnode. One 965240afd8cSMark Johnston * dataset, not necessarily the root dataset, must "own" the root 966240afd8cSMark Johnston * directory by having its mountpoint be equal to the root path. 967240afd8cSMark Johnston * 968240afd8cSMark Johnston * As roots of other datasets are encountered during the traversal, 969240afd8cSMark Johnston * fs_build_one() recursively creates the corresponding object sets and 970240afd8cSMark Johnston * populates them. Once this function has returned, all datasets will 971240afd8cSMark Johnston * have been fully populated. 972240afd8cSMark Johnston */ 973240afd8cSMark Johnston fs_build_one(zfs, root->inode->param, root, dirfd); 974240afd8cSMark Johnston 975240afd8cSMark Johnston /* 976240afd8cSMark Johnston * Now create object sets for datasets whose mountpoints weren't found 977240afd8cSMark Johnston * in the staging directory, either because there is no mountpoint, or 978240afd8cSMark Johnston * because the mountpoint doesn't correspond to an existing directory. 979240afd8cSMark Johnston */ 980240afd8cSMark Johnston dsl_dir_foreach(zfs, zfs->rootdsldir, fs_build_unmounted, NULL); 981240afd8cSMark Johnston } 982