Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/sys/zfs_znode.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ extern int zfs_znode_hold_compare(const void *, const void *);
extern znode_hold_t *zfs_znode_hold_enter(zfsvfs_t *, uint64_t);
extern void zfs_znode_hold_exit(zfsvfs_t *, znode_hold_t *);
extern int zfs_zget(zfsvfs_t *, uint64_t, znode_t **);
extern int zfs_zget_impl(zfsvfs_t *, uint64_t, znode_t **, boolean_t);
extern int zfs_rezget(znode_t *);
extern void zfs_zinactive(znode_t *);
extern void zfs_znode_delete(znode_t *, dmu_tx_t *);
Expand Down
7 changes: 7 additions & 0 deletions module/os/freebsd/zfs/zfs_znode_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,13 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp)
return (err);
}

int
zfs_zget_impl(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp,
boolean_t check_sync)
{
return (zfs_zget(zfsvfs, obj_num, zpp));
}

int
zfs_rezget(znode_t *zp)
{
Expand Down
22 changes: 20 additions & 2 deletions module/os/linux/zfs/zfs_znode_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -1050,13 +1050,21 @@ zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx)

int
zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp)
{
return (zfs_zget_impl(zfsvfs, obj_num, zpp, B_FALSE));
}

int
zfs_zget_impl(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp,
boolean_t check_sync)
{
dmu_object_info_t doi;
dmu_buf_t *db;
znode_t *zp;
znode_hold_t *zh;
int err;
sa_handle_t *hdl;
boolean_t noloop = B_FALSE;

*zpp = NULL;

Expand Down Expand Up @@ -1115,8 +1123,18 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp)
if (igrab(ZTOI(zp)) == NULL) {
if (zp->z_unlinked)
err = SET_ERROR(ENOENT);
else
else {
err = SET_ERROR(EAGAIN);
/*
* In writeback path, I_SYNC flag will be set
* and block inode eviction. So we must not
* loop doing igrab in possible writeback
* path, i.e. zfs_get_data, if inode is being
* evicted and I_SYNC is also set.
*/
if (check_sync && (ZTOI(zp)->i_state & I_SYNC))
noloop = B_TRUE;
}
} else {
*zpp = zp;
err = 0;
Expand All @@ -1126,7 +1144,7 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp)
sa_buf_rele(db, NULL);
zfs_znode_hold_exit(zfsvfs, zh);

if (err == EAGAIN) {
if (err == EAGAIN && !noloop) {
/* inode might need this to finish evict */
cond_resched();
goto again;
Expand Down
13 changes: 12 additions & 1 deletion module/zfs/zfs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1342,10 +1342,21 @@ zfs_get_data(void *arg, uint64_t gen, lr_write_t *lr, char *buf,
ASSERT3P(lwb, !=, NULL);
ASSERT3U(size, !=, 0);

error = zfs_zget_impl(zfsvfs, object, &zp, B_TRUE);
#if defined(__linux__)
/*
* Under Linux, EAGAIN indicates the inode is being evicted and I_SYNC
* is also set possibly blocking eviction, so we can't loop in
* zfs_zget to avoid deadlock. Return EIO to force txg sync under such
* scenario.
*/
if (error == EAGAIN)
return (SET_ERROR(EIO));
#endif
/*
* Nothing to do if the file has been removed
*/
if (zfs_zget(zfsvfs, object, &zp) != 0)
if (error)
return (SET_ERROR(ENOENT));
if (zp->z_unlinked) {
/*
Expand Down
Loading