]> granicus.if.org Git - zfs/commitdiff
Illumos 3139 - zdb dies when it tries to determine path of unlinked file
authorJeremy Jones <jeremy@delphix.com>
Thu, 31 Dec 2015 15:41:52 +0000 (16:41 +0100)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 5 Jan 2016 19:25:41 +0000 (11:25 -0800)
3139 zdb dies when it tries to determine path of unlinked file
Reviewed by: Matt Ahrens <matthew.ahrens@delphix.com>
Reviewed by: Christopher Siden <chris.siden@delphix.com>
Reviewed by: Eric Schrock <eric.schrock@delphix.com>
Approved by: Dan McDonald <danmcd@nexenta.com>

References:
  https://github.com/illumos/illumos-gate/commit/1ce39b5
  https://www.illumos.org/issues/3139

Ported-by: kernelOfTruth kerneloftruth@gmail.com
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
module/zfs/zfs_znode.c

index 1a5a84d681de0b1167213dbeb3ca9612ea042316..bd5f738a72461a7a1c91100073f240b41eaa729f 100644 (file)
@@ -1820,13 +1820,16 @@ zfs_release_sa_handle(sa_handle_t *hdl, dmu_buf_t *db, void *tag)
  * or not the object is an extended attribute directory.
  */
 static int
-zfs_obj_to_pobj(sa_handle_t *hdl, sa_attr_type_t *sa_table, uint64_t *pobjp,
-    int *is_xattrdir)
+zfs_obj_to_pobj(objset_t *osp, sa_handle_t *hdl, sa_attr_type_t *sa_table,
+    uint64_t *pobjp, int *is_xattrdir)
 {
        uint64_t parent;
        uint64_t pflags;
        uint64_t mode;
+       uint64_t parent_mode;
        sa_bulk_attr_t bulk[3];
+       sa_handle_t *sa_hdl;
+       dmu_buf_t *sa_db;
        int count = 0;
        int error;
 
@@ -1840,9 +1843,32 @@ zfs_obj_to_pobj(sa_handle_t *hdl, sa_attr_type_t *sa_table, uint64_t *pobjp,
        if ((error = sa_bulk_lookup(hdl, bulk, count)) != 0)
                return (error);
 
-       *pobjp = parent;
+       /*
+        * When a link is removed its parent pointer is not changed and will
+        * be invalid.  There are two cases where a link is removed but the
+        * file stays around, when it goes to the delete queue and when there
+        * are additional links.
+        */
+       error = zfs_grab_sa_handle(osp, parent, &sa_hdl, &sa_db, FTAG);
+       if (error != 0)
+               return (error);
+
+       error = sa_lookup(sa_hdl, ZPL_MODE, &parent_mode, sizeof (parent_mode));
+       zfs_release_sa_handle(sa_hdl, sa_db, FTAG);
+       if (error != 0)
+               return (error);
+
        *is_xattrdir = ((pflags & ZFS_XATTR) != 0) && S_ISDIR(mode);
 
+       /*
+        * Extended attributes can be applied to files, directories, etc.
+        * Otherwise the parent must be a directory.
+        */
+       if (!*is_xattrdir && !S_ISDIR(parent_mode))
+               return (EINVAL);
+
+       *pobjp = parent;
+
        return (0);
 }
 
@@ -1891,7 +1917,7 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
                if (prevdb)
                        zfs_release_sa_handle(prevhdl, prevdb, FTAG);
 
-               if ((error = zfs_obj_to_pobj(sa_hdl, sa_table, &pobj,
+               if ((error = zfs_obj_to_pobj(osp, sa_hdl, sa_table, &pobj,
                    &is_xattrdir)) != 0)
                        break;