Page MenuHomeFreeBSD

D9706.id25602.diff
No OneTemporary

D9706.id25602.diff

Index: head/sys/boot/zfs/zfsimpl.c
===================================================================
--- head/sys/boot/zfs/zfsimpl.c
+++ head/sys/boot/zfs/zfsimpl.c
@@ -2264,6 +2264,61 @@
return (0);
}
+static int
+zfs_dnode_readlink(const spa_t *spa, dnode_phys_t *dn, char *path, size_t psize)
+{
+ int rc = 0;
+
+ if (dn->dn_bonustype == DMU_OT_SA) {
+ sa_hdr_phys_t *sahdrp = NULL;
+ size_t size = 0;
+ void *buf = NULL;
+ int hdrsize;
+ char *p;
+
+ if (dn->dn_bonuslen != 0)
+ sahdrp = (sa_hdr_phys_t *)DN_BONUS(dn);
+ else {
+ blkptr_t *bp;
+
+ if ((dn->dn_flags & DNODE_FLAG_SPILL_BLKPTR) == 0)
+ return (EIO);
+ bp = &dn->dn_spill;
+
+ size = BP_GET_LSIZE(bp);
+ buf = zfs_alloc(size);
+ rc = zio_read(spa, bp, buf);
+ if (rc != 0) {
+ zfs_free(buf, size);
+ return (rc);
+ }
+ sahdrp = buf;
+ }
+ hdrsize = SA_HDR_SIZE(sahdrp);
+ p = (char *)((uintptr_t)sahdrp + hdrsize + SA_SYMLINK_OFFSET);
+ memcpy(path, p, psize);
+ if (buf != NULL)
+ zfs_free(buf, size);
+ return (0);
+ }
+ /*
+ * Second test is purely to silence bogus compiler
+ * warning about accessing past the end of dn_bonus.
+ */
+ if (psize + sizeof(znode_phys_t) <= dn->dn_bonuslen &&
+ sizeof(znode_phys_t) <= sizeof(dn->dn_bonus)) {
+ memcpy(path, &dn->dn_bonus[sizeof(znode_phys_t)], psize);
+ } else {
+ rc = dnode_read(spa, dn, 0, path, psize);
+ }
+ return (rc);
+}
+
+struct obj_list {
+ uint64_t objnum;
+ STAILQ_ENTRY(obj_list) entry;
+};
+
/*
* Lookup a file and return its dnode.
*/
@@ -2271,7 +2326,7 @@
zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode)
{
int rc;
- uint64_t objnum, rootnum, parentnum;
+ uint64_t objnum;
const spa_t *spa;
dnode_phys_t dn;
const char *p, *q;
@@ -2279,6 +2334,8 @@
char path[1024];
int symlinks_followed = 0;
struct stat sb;
+ struct obj_list *entry;
+ STAILQ_HEAD(, obj_list) on_cache = STAILQ_HEAD_INITIALIZER(on_cache);
spa = mount->spa;
if (mount->objset.os_type != DMU_OST_ZFS) {
@@ -2287,87 +2344,119 @@
return (EIO);
}
+ if ((entry = malloc(sizeof(struct obj_list))) == NULL)
+ return (ENOMEM);
+
/*
* Get the root directory dnode.
*/
rc = objset_get_dnode(spa, &mount->objset, MASTER_NODE_OBJ, &dn);
- if (rc)
+ if (rc) {
+ free(entry);
return (rc);
+ }
- rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, sizeof (rootnum), 1, &rootnum);
- if (rc)
+ rc = zap_lookup(spa, &dn, ZFS_ROOT_OBJ, sizeof (objnum), 1, &objnum);
+ if (rc) {
+ free(entry);
return (rc);
+ }
+ entry->objnum = objnum;
+ STAILQ_INSERT_HEAD(&on_cache, entry, entry);
- rc = objset_get_dnode(spa, &mount->objset, rootnum, &dn);
- if (rc)
- return (rc);
+ rc = objset_get_dnode(spa, &mount->objset, objnum, &dn);
+ if (rc != 0)
+ goto done;
- objnum = rootnum;
p = upath;
while (p && *p) {
+ rc = objset_get_dnode(spa, &mount->objset, objnum, &dn);
+ if (rc != 0)
+ goto done;
+
while (*p == '/')
p++;
- if (!*p)
+ if (*p == '\0')
break;
- q = strchr(p, '/');
- if (q) {
- memcpy(element, p, q - p);
- element[q - p] = 0;
- p = q;
- } else {
- strcpy(element, p);
- p = NULL;
- }
+ q = p;
+ while (*q != '\0' && *q != '/')
+ q++;
- rc = zfs_dnode_stat(spa, &dn, &sb);
- if (rc)
- return (rc);
- if (!S_ISDIR(sb.st_mode))
- return (ENOTDIR);
+ /* skip dot */
+ if (p + 1 == q && p[0] == '.') {
+ p++;
+ continue;
+ }
+ /* double dot */
+ if (p + 2 == q && p[0] == '.' && p[1] == '.') {
+ p += 2;
+ if (STAILQ_FIRST(&on_cache) ==
+ STAILQ_LAST(&on_cache, obj_list, entry)) {
+ rc = ENOENT;
+ goto done;
+ }
+ entry = STAILQ_FIRST(&on_cache);
+ STAILQ_REMOVE_HEAD(&on_cache, entry);
+ free(entry);
+ objnum = (STAILQ_FIRST(&on_cache))->objnum;
+ continue;
+ }
+ if (q - p + 1 > sizeof(element)) {
+ rc = ENAMETOOLONG;
+ goto done;
+ }
+ memcpy(element, p, q - p);
+ element[q - p] = 0;
+ p = q;
+
+ if ((rc = zfs_dnode_stat(spa, &dn, &sb)) != 0)
+ goto done;
+ if (!S_ISDIR(sb.st_mode)) {
+ rc = ENOTDIR;
+ goto done;
+ }
- parentnum = objnum;
rc = zap_lookup(spa, &dn, element, sizeof (objnum), 1, &objnum);
if (rc)
- return (rc);
+ goto done;
objnum = ZFS_DIRENT_OBJ(objnum);
+ if ((entry = malloc(sizeof(struct obj_list))) == NULL) {
+ rc = ENOMEM;
+ goto done;
+ }
+ entry->objnum = objnum;
+ STAILQ_INSERT_HEAD(&on_cache, entry, entry);
rc = objset_get_dnode(spa, &mount->objset, objnum, &dn);
if (rc)
- return (rc);
+ goto done;
/*
* Check for symlink.
*/
rc = zfs_dnode_stat(spa, &dn, &sb);
if (rc)
- return (rc);
+ goto done;
if (S_ISLNK(sb.st_mode)) {
- if (symlinks_followed > 10)
- return (EMLINK);
+ if (symlinks_followed > 10) {
+ rc = EMLINK;
+ goto done;
+ }
symlinks_followed++;
/*
* Read the link value and copy the tail of our
* current path onto the end.
*/
- if (p)
- strcpy(&path[sb.st_size], p);
- else
- path[sb.st_size] = 0;
- /*
- * Second test is purely to silence bogus compiler
- * warning about accessing past the end of dn_bonus.
- */
- if (sb.st_size + sizeof(znode_phys_t) <=
- dn.dn_bonuslen && sizeof(znode_phys_t) <=
- sizeof(dn.dn_bonus)) {
- memcpy(path, &dn.dn_bonus[sizeof(znode_phys_t)],
- sb.st_size);
- } else {
- rc = dnode_read(spa, &dn, 0, path, sb.st_size);
- if (rc)
- return (rc);
+ if (sb.st_size + strlen(p) + 1 > sizeof(path)) {
+ rc = ENAMETOOLONG;
+ goto done;
}
+ strcpy(&path[sb.st_size], p);
+
+ rc = zfs_dnode_readlink(spa, &dn, path, sb.st_size);
+ if (rc != 0)
+ goto done;
/*
* Restart with the new path, starting either at
@@ -2375,14 +2464,25 @@
* not the link is relative.
*/
p = path;
- if (*p == '/')
- objnum = rootnum;
- else
- objnum = parentnum;
- objset_get_dnode(spa, &mount->objset, objnum, &dn);
+ if (*p == '/') {
+ while (STAILQ_FIRST(&on_cache) !=
+ STAILQ_LAST(&on_cache, obj_list, entry)) {
+ entry = STAILQ_FIRST(&on_cache);
+ STAILQ_REMOVE_HEAD(&on_cache, entry);
+ free(entry);
+ }
+ } else {
+ entry = STAILQ_FIRST(&on_cache);
+ STAILQ_REMOVE_HEAD(&on_cache, entry);
+ free(entry);
+ }
+ objnum = (STAILQ_FIRST(&on_cache))->objnum;
}
}
*dnode = dn;
- return (0);
+done:
+ STAILQ_FOREACH(entry, &on_cache, entry)
+ free(entry);
+ return (rc);
}
Index: head/sys/cddl/boot/zfs/zfsimpl.h
===================================================================
--- head/sys/cddl/boot/zfs/zfsimpl.h
+++ head/sys/cddl/boot/zfs/zfsimpl.h
@@ -1080,6 +1080,7 @@
#define SA_UID_OFFSET 24
#define SA_GID_OFFSET 32
#define SA_PARENT_OFFSET 40
+#define SA_SYMLINK_OFFSET 160
/*
* Intent log header - this on disk structure holds fields to manage

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 10, 8:13 PM (14 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31243102
Default Alt Text
D9706.id25602.diff (6 KB)

Event Timeline