@@ -1208,7 +1208,7 @@ int ll_iocontrol(struct inode *inode, struct file *file,
void ll_umount_begin(struct super_block *sb);
int ll_remount_fs(struct super_block *sb, int *flags, char *data);
int ll_show_options(struct seq_file *seq, struct dentry *dentry);
-void ll_dirty_page_discard_warn(struct page *page, int ioret);
+void ll_dirty_page_discard_warn(struct inode *inode, int ioret);
int ll_prep_inode(struct inode **inode, struct req_capsule *pill,
struct super_block *sb, struct lookup_intent *it);
int ll_obd_statfs(struct inode *inode, void __user *arg);
@@ -3334,18 +3334,36 @@ int ll_get_obd_name(struct inode *inode, unsigned int cmd, unsigned long arg)
return 0;
}
-void ll_dirty_page_discard_warn(struct page *page, int ioret)
+struct dname_buf {
+ struct work_struct db_work;
+ struct dentry *db_dentry;
+ /* Let's hope the path is not too long, 32 bytes for the work struct
+ * on my kernel
+ */
+ char buf[PAGE_SIZE - sizeof(struct work_struct) - sizeof(void *)];
+};
+
+static void ll_dput_later(struct work_struct *work)
{
- char *buf, *path = NULL;
+ struct dname_buf *db = container_of(work, struct dname_buf, db_work);
+
+ dput(db->db_dentry);
+ free_page((unsigned long)db);
+}
+
+void ll_dirty_page_discard_warn(struct inode *inode, int ioret)
+{
+ struct dname_buf *db;
+ char *path = NULL;
struct dentry *dentry = NULL;
- struct inode *inode = page->mapping->host;
/* this can be called inside spin lock so use GFP_ATOMIC. */
- buf = (char *)__get_free_page(GFP_ATOMIC);
- if (buf) {
+ db = (struct dname_buf *)__get_free_page(GFP_ATOMIC);
+ if (db) {
dentry = d_find_alias(inode);
if (dentry)
- path = dentry_path_raw(dentry, buf, PAGE_SIZE);
+ path = dentry_path_raw(dentry, db->buf,
+ sizeof(db->buf));
}
/* The below message is checked in recovery-small.sh test_24b */
@@ -3356,11 +3374,20 @@ void ll_dirty_page_discard_warn(struct page *page, int ioret)
PFID(ll_inode2fid(inode)),
(path && !IS_ERR(path)) ? path : "", ioret);
- if (dentry)
- dput(dentry);
-
- if (buf)
- free_page((unsigned long)buf);
+ if (dentry) {
+ /* We cannot dput here since if we happen to be the last holder
+ * then we can end up waiting for page evictions that
+ * in turn wait for RPCs that need this instance of ptlrpcd
+ * (callng brw_interpret->*page_completion*->vmpage_error->here)
+ * LU-15340
+ */
+ INIT_WORK(&db->db_work, ll_dput_later);
+ db->db_dentry = dentry;
+ schedule_work(&db->db_work);
+ } else {
+ if (db)
+ free_page((unsigned long)db);
+ }
}
ssize_t ll_copy_user_md(const struct lov_user_md __user *md,
@@ -244,7 +244,7 @@ static void vvp_vmpage_error(struct inode *inode, struct page *vmpage,
if ((ioret == -ESHUTDOWN || ioret == -EINTR ||
ioret == -EIO) && obj->vob_discard_page_warned == 0) {
obj->vob_discard_page_warned = 1;
- ll_dirty_page_discard_warn(vmpage, ioret);
+ ll_dirty_page_discard_warn(inode, ioret);
}
}
}