@@ -46,6 +46,7 @@ static void file_free_rcu(struct rcu_head *head)
{
struct file *f = container_of(head, struct file, f_u.fu_rcuhead);
+ WARN_ON(!list_empty(&f->file_pins));
put_cred(f->f_cred);
kmem_cache_free(filp_cachep, f);
}
@@ -118,6 +119,9 @@ static struct file *__alloc_file(int flags, const struct cred *cred)
f->f_mode = OPEN_FMODE(flags);
/* f->f_version: 0 */
+ INIT_LIST_HEAD(&f->file_pins);
+ spin_lock_init(&f->fp_lock);
+
return f;
}
@@ -9,6 +9,7 @@
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/posix_types.h>
+#include <linux/kref.h>
struct file;
@@ -91,4 +92,52 @@ extern void fd_install(unsigned int fd, struct file *file);
extern void flush_delayed_fput(void);
extern void __fput_sync(struct file *);
+/**
+ * struct file_file_pin
+ *
+ * Associate a pin'ed file with another file owner.
+ *
+ * Subsystems such as RDMA have the ability to pin memory which is associated
+ * with a file descriptor which can be passed to other processes without
+ * necessarily having that memory accessed in the remote processes address
+ * space.
+ *
+ * @file file backing memory which was pined by a GUP caller
+ * @f_owner the file representing the GUP owner
+ * @list of all file pins this owner has
+ * (struct file *)->file_pins
+ * @ref number of times this pin was taken (roughly the number of pages pinned
+ * in the file)
+ */
+struct file_file_pin {
+ struct file *file;
+ struct file *f_owner;
+ struct list_head list;
+ struct kref ref;
+};
+
+/*
+ * struct mm_file_pin
+ *
+ * Some GUP callers do not have an "owning" file. Those pins are accounted for
+ * in the mm of the process that called GUP.
+ *
+ * The tuple {file, inode} is used to track this as a unique file pin and to
+ * track when this pin has been removed.
+ *
+ * @file file backing memory which was pined by a GUP caller
+ * @mm back point to owning mm
+ * @inode backing the file
+ * @list of all file pins this owner has
+ * (struct mm_struct *)->file_pins
+ * @ref number of times this pin was taken
+ */
+struct mm_file_pin {
+ struct file *file;
+ struct mm_struct *mm;
+ struct inode *inode;
+ struct list_head list;
+ struct kref ref;
+};
+
#endif /* __LINUX_FILE_H */
@@ -963,6 +963,8 @@ struct file {
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
errseq_t f_wb_err;
+ struct list_head file_pins;
+ spinlock_t fp_lock;
} __randomize_layout
__attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
@@ -516,6 +516,8 @@ struct mm_struct {
/* HMM needs to track a few things per mm */
struct hmm *hmm;
#endif
+ struct list_head file_pins;
+ spinlock_t fp_lock; /* lock file_pins */
} __randomize_layout;
/*
@@ -675,6 +675,7 @@ void __mmdrop(struct mm_struct *mm)
BUG_ON(mm == &init_mm);
WARN_ON_ONCE(mm == current->mm);
WARN_ON_ONCE(mm == current->active_mm);
+ WARN_ON(!list_empty(&mm->file_pins));
mm_free_pgd(mm);
destroy_context(mm);
mmu_notifier_mm_destroy(mm);
@@ -1013,6 +1014,8 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
mm->pmd_huge_pte = NULL;
#endif
mm_init_uprobes_state(mm);
+ INIT_LIST_HEAD(&mm->file_pins);
+ spin_lock_init(&mm->fp_lock);
if (current->mm) {
mm->flags = current->mm->flags & MMF_INIT_MASK;