diff options
author | Jeremy Jones <[email protected]> | 2015-12-31 16:41:52 +0100 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2016-01-05 11:25:41 -0800 |
commit | b23ad7f350222ac439a679d99bd8b0aa27604aef (patch) | |
tree | 897055f2d3ea90ca4377185f634e08c94f997b16 /module/zfs/zfs_znode.c | |
parent | cfe86c01d5b3eec4a490de16a1db79c1244395ed (diff) |
Illumos 3139 - zdb dies when it tries to determine path of unlinked file
3139 zdb dies when it tries to determine path of unlinked file
Reviewed by: Matt Ahrens <[email protected]>
Reviewed by: Christopher Siden <[email protected]>
Reviewed by: Eric Schrock <[email protected]>
Approved by: Dan McDonald <[email protected]>
References:
https://github.com/illumos/illumos-gate/commit/1ce39b5
https://www.illumos.org/issues/3139
Ported-by: kernelOfTruth [email protected]
Signed-off-by: Brian Behlendorf <[email protected]>
Diffstat (limited to 'module/zfs/zfs_znode.c')
-rw-r--r-- | module/zfs/zfs_znode.c | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/module/zfs/zfs_znode.c b/module/zfs/zfs_znode.c index 1a5a84d68..bd5f738a7 100644 --- a/module/zfs/zfs_znode.c +++ b/module/zfs/zfs_znode.c @@ -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; |