summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2017-03-23 18:26:50 -0700
committerGitHub <[email protected]>2017-03-23 18:26:50 -0700
commit8d703987407acfcbd992ba4a7926f2d76ca3779c (patch)
treec6f5f253f82729138ee0d8b26f7fd564ce7155d6
parentb25c5b0639e0d2281ccbd3b5766762dc3bebfc02 (diff)
Retry zfs_znode_alloc() in zfs_mknode()
For historical reasons zfs_mknode() was written such that it could never fail. This poses a problem for Linux since zfs_znode_alloc() could potentually failure due to low memory. Handle this gracefully by retrying zfs_znode_alloc() until it succeeds, direct reclaim will eventually be able to allocate memory. Reviewed-by: George Melikov <[email protected]> Reviewed-by: loli10K <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #5535 Closes #5908
-rw-r--r--module/zfs/zfs_znode.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/module/zfs/zfs_znode.c b/module/zfs/zfs_znode.c
index 1597940e6..93437afb3 100644
--- a/module/zfs/zfs_znode.c
+++ b/module/zfs/zfs_znode.c
@@ -915,7 +915,18 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
VERIFY(sa_replace_all_by_template(sa_hdl, sa_attrs, cnt, tx) == 0);
if (!(flag & IS_ROOT_NODE)) {
- *zpp = zfs_znode_alloc(zfsvfs, db, 0, obj_type, obj, sa_hdl);
+ /*
+ * The call to zfs_znode_alloc() may fail if memory is low
+ * via the call path: alloc_inode() -> inode_init_always() ->
+ * security_inode_alloc() -> inode_alloc_security(). Since
+ * the existing code is written such that zfs_mknode() can
+ * not fail retry until sufficient memory has been reclaimed.
+ */
+ do {
+ *zpp = zfs_znode_alloc(zfsvfs, db, 0, obj_type, obj,
+ sa_hdl);
+ } while (*zpp == NULL);
+
VERIFY(*zpp != NULL);
VERIFY(dzp != NULL);
} else {