<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=koi8-r">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<div>criu uses fhandle from fdinfo to dump inotify objects. cgroup super block has<br>
</div>
<div>no export operations, but .encode_fh and .fh_to_dentry are needed for<br>
</div>
<div>inotify_fdinfo function and open_by_handle_at syscall in order to correctly<br>
</div>
<div>open files located on cgroupfs by fhandle.<br>
</div>
<div>Add hash table as a storage for inodes with exported fhandle.<br>
</div>
<div><br>
</div>
<div>https://jira.sw.ru/browse/PSBM-105889<br>
</div>
<div>Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com><br>
</div>
<div>---<br>
</div>
<div> kernel/cgroup.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-<br>
</div>
<div> 1 file changed, 106 insertions(+), 1 deletion(-)<br>
</div>
<div><br>
</div>
<div>diff --git a/kernel/cgroup.c b/kernel/cgroup.c<br>
</div>
<div>index 9fdba79..a06c809 100644<br>
</div>
<div>--- a/kernel/cgroup.c<br>
</div>
<div>+++ b/kernel/cgroup.c<br>
</div>
<div>@@ -62,6 +62,7 @@<br>
</div>
<div> #include <linux/kthread.h><br>
</div>
<div> #include <linux/ve.h><br>
</div>
<div> #include <linux/stacktrace.h><br>
</div>
<div>+#include <linux/exportfs.h><br>
</div>
<div> <br>
</div>
<div> #include <linux/atomic.h><br>
</div>
<div> <br>
</div>
<div>@@ -1390,9 +1391,112 @@ out:<br>
</div>
<div> }<br>
</div>
<div> #endif<br>
</div>
<div> <br>
</div>
<div>+/*<br>
</div>
<div>+ * hashtable for inodes that have exported fhandles.<br>
</div>
<div>+ * When we export fhandle, we add it's inode into<br>
</div>
<div>+ * hashtable so we can find it fast<br>
</div>
<div>+ */<br>
</div>
<div>+<br>
</div>
<div>+#define CGROUP_INODE_HASH_BITS 10<br>
</div>
<div>+static DEFINE_HASHTABLE(cgroup_inode_table, CGROUP_INODE_HASH_BITS);<br>
</div>
<div>+static DEFINE_SPINLOCK(cgroup_inode_table_lock);<br>
</div>
<div>+<br>
</div>
<div>+struct cgroup_inode_hash_item {<br>
</div>
<div>+ struct inode* inode;<br>
</div>
<div>+ struct hlist_node hlist;<br>
</div>
<div>+};<br>
</div>
<div>+<br>
</div>
<div>+static inline unsigned long cgroup_inode_get_hash(unsigned int i_ino)<br>
</div>
<div>+{<br>
</div>
<div>+ return hash_32(i_ino, CGROUP_INODE_HASH_BITS);<br>
</div>
<div>+}<br>
</div>
<div>+<br>
</div>
<div>+static struct cgroup_inode_hash_item* cgroup_inode_hash_find(unsigned int i_ino)<br>
</div>
<div>+{<br>
</div>
<div>+ struct cgroup_inode_hash_item *i;<br>
</div>
<div>+ struct hlist_head *head = cgroup_inode_table + cgroup_inode_get_hash(i_ino);<br>
</div>
<div>+ struct cgroup_inode_hash_item* found = 0;<br>
</div>
<div>+<br>
</div>
<div>+ spin_lock(&cgroup_inode_table_lock);<br>
</div>
<div>+ hlist_for_each_entry(i, head, hlist) {<br>
</div>
<div>+ if(i->inode->i_ino == i_ino) {<br>
</div>
<div>+ found = i;<br>
</div>
<div>+ break;<br>
</div>
<div>+ }<br>
</div>
<div>+ }<br>
</div>
<div>+ spin_unlock(&cgroup_inode_table_lock);<br>
</div>
<div>+<br>
</div>
<div>+ return found;<br>
</div>
<div>+}<br>
</div>
<div>+<br>
</div>
<div>+static struct dentry *cgroup_fh_to_dentry(struct super_block *sb,<br>
</div>
<div>+ struct fid *fid, int fh_len, int fh_type)<br>
</div>
<div>+{<br>
</div>
<div>+ struct cgroup_inode_hash_item *item;<br>
</div>
<div>+ struct dentry *dentry = ERR_PTR(-ENOENT);<br>
</div>
<div>+<br>
</div>
<div>+ if (fh_len < 1)<br>
</div>
<div>+ return NULL;<br>
</div>
<div>+<br>
</div>
<div>+ item = cgroup_inode_hash_find(fid->raw[0]);<br>
</div>
<div>+ if (item)<br>
</div>
<div>+ dentry = d_find_alias(item->inode);<br>
</div>
<div>+<br>
</div>
<div>+ return dentry;<br>
</div>
<div>+}<br>
</div>
<div>+<br>
</div>
<div>+static int cgroup_encode_fh(struct inode *inode, __u32 *fh, int *len,<br>
</div>
<div>+ struct inode *parent)<br>
</div>
<div>+{<br>
</div>
<div>+ struct hlist_head *head = cgroup_inode_table + cgroup_inode_get_hash(inode->i_ino);<br>
</div>
<div>+ struct cgroup_inode_hash_item *item;<br>
</div>
<div>+<br>
</div>
<div>+ if (*len < 1) {<br>
</div>
<div>+ *len = 1;<br>
</div>
<div>+ return FILEID_INVALID;<br>
</div>
<div>+ }<br>
</div>
<div>+<br>
</div>
<div>+ if(cgroup_inode_hash_find(inode->i_ino) == 0) {<br>
</div>
<div>+ item = kmalloc(sizeof(struct cgroup_inode_hash_item), GFP_KERNEL);<br>
</div>
<div>+ /*<br>
</div>
<div>+ * encode_fh is expected to return 255 (FILEID_INVALID) in case of<br>
</div>
<div>+ * failure. We can't return ENOMEM, so return FILEID_INVALID at least<br>
</div>
<div>+ */<br>
</div>
<div>+ if(!item)<br>
</div>
<div>+ return FILEID_INVALID;<br>
</div>
<div>+ item->inode = inode;<br>
</div>
<div>+<br>
</div>
<div>+ spin_lock(&cgroup_inode_table_lock);<br>
</div>
<div>+ hlist_add_head(&item->hlist, head);<br>
</div>
<div>+ spin_unlock(&cgroup_inode_table_lock);<br>
</div>
<div>+ }<br>
</div>
<div>+<br>
</div>
<div>+ fh[0] = inode->i_ino;<br>
</div>
<div>+ *len = 1;<br>
</div>
<div>+ return 1;<br>
</div>
<div>+}<br>
</div>
<div>+<br>
</div>
<div>+static const struct export_operations cgroup_export_ops = {<br>
</div>
<div>+ .encode_fh = cgroup_encode_fh,<br>
</div>
<div>+ .fh_to_dentry = cgroup_fh_to_dentry,<br>
</div>
<div>+};<br>
</div>
<div>+<br>
</div>
<div>+static int cgroup_delete_inode(struct inode *inode){<br>
</div>
<div>+ struct cgroup_inode_hash_item *item = cgroup_inode_hash_find(inode->i_ino);<br>
</div>
<div>+ if(item) {<br>
</div>
<div>+ spin_lock(&cgroup_inode_table_lock);<br>
</div>
<div>+ hlist_del(&item->hlist);<br>
</div>
<div>+ spin_unlock(&cgroup_inode_table_lock);<br>
</div>
<div>+<br>
</div>
<div>+ kfree(item);<br>
</div>
<div>+ }<br>
</div>
<div>+<br>
</div>
<div>+ return generic_delete_inode(inode);<br>
</div>
<div>+}<br>
</div>
<div>+<br>
</div>
<div> static const struct super_operations cgroup_ops = {<br>
</div>
<div> .statfs = simple_statfs,<br>
</div>
<div>- .drop_inode = generic_delete_inode,<br>
</div>
<div>+ .drop_inode = cgroup_delete_inode,<br>
</div>
<div> .show_options = cgroup_show_options,<br>
</div>
<div> #ifdef CONFIG_VE<br>
</div>
<div> .show_path = cgroup_show_path,<br>
</div>
<div>@@ -1539,6 +1643,7 @@ static int cgroup_set_super(struct super_block *sb, void *data)<br>
</div>
<div> sb->s_blocksize_bits = PAGE_CACHE_SHIFT;<br>
</div>
<div> sb->s_magic = CGROUP_SUPER_MAGIC;<br>
</div>
<div> sb->s_op = &cgroup_ops;<br>
</div>
<div>+ sb->s_export_op = &cgroup_export_ops;<br>
</div>
<div> <br>
</div>
<div> return 0;<br>
</div>
<div> }<br>
</div>
<div>-- <br>
</div>
<div>1.8.3.1<br>
</div>
<span></span><br>
</div>
</body>
</html>