Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151658859
D9706.id25602.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D9706.id25602.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D9706: loader: update symlink support in zfs reader
Attached
Detach File
Event Timeline
Log In to Comment