[Ocfs2-devel] [PATCH]2.6 mechanism for holding private inode data

Rusty Lynch rusty at linux.co.intel.com
Wed Mar 10 20:49:38 CST 2004


The following patch is safe for the 2.4 kernel, but still incomplete 
for the 2.6 kernel.  I am sending this just incase there is any feedback
on what I am doing (and to give Sonic and Xiaofeng a chance to figure this
out while I'm asleep.)

So... struct inode changed in 2.6 such that the union on the end of the
struct now only contains "void *generic_ip", and therefore only adds
on sizeof(void *) to the end of the structure.  Our 2.6 code is still
attempting to read/write private data at the end of the inode struct,
and therefore writing past the end of the object.

The suggested new way of storing private data is to define a new
struct that contains your private data and has an inode imbedded inside.
Then the private data can be reached from an inode by doing a simple
container_of on the inode.  This is possible by hooking into inode
allocation/deallocation via the alloc_inode/destroy_inode function 
pointers in the super operations.

(See linux/Documentation/filesystems/port)

The following patch does this and also takes the liberty to convert the 
macros for getting/setting private data into inline functions (mainly
because stared at OCFS_GENERIC_IP and friends for way to long before
I realized what they were actually doing, and why that was freezing my
2.6 build.)

All this sounds good except... now d_alloc_root() oops's when it attempts
to initialize which attempts to d_initialize() which eventually dereferences
a new pointer while initializing a list_head.  I'm sure I missed a step
some place, but I'm spent for the night.

    --rusty

Index: src/super.c
===================================================================
--- src/super.c	(revision 769)
+++ src/super.c	(working copy)
@@ -135,6 +135,8 @@
 static void ocfs_free_mem_lists (void);
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static struct inode *ocfs_alloc_inode(struct super_block *sb);
+static void ocfs_destroy_inode(struct inode *inode);
 static int ocfs_statfs (struct super_block *sb, struct kstatfs *buf);
 #else
 static int ocfs_statfs (struct super_block *sb, struct statfs *buf);
@@ -146,7 +148,10 @@
 	.clear_inode = ocfs_clear_inode,
 	//put_inode =           force_delete,
 	//delete_inode =        ocfs_delete_inode, 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	.alloc_inode = ocfs_alloc_inode,
+	.destroy_inode = ocfs_destroy_inode,
+#else
 	.read_inode = ocfs_read_inode,
 	.read_inode2 = ocfs_read_inode2,
 #endif
@@ -154,9 +159,24 @@
 
 };
 
-
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 
+static struct inode *ocfs_alloc_inode(struct super_block *sb)
+{
+	struct ocfs_inode_info *i = (struct ocfs_inode_info *)kmem_cache_alloc(OcfsGlobalCtxt.inode_cache, GFP_NOFS);
+	if (!i) {
+		LOG_ERROR_STR("unable to allocate inode");
+		return NULL;
+	}
+
+	return &(i->vfs_inode);
+}
+
+static void ocfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(OcfsGlobalCtxt.inode_cache, OCFS_I(inode));
+}
+
 static int ocfs_fill_super (struct super_block *sb, void *data, int silent)
 {
 	struct dentry *root_dentry;
@@ -788,6 +808,11 @@
  */
 static int ocfs_initialize_mem_lists (void)
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)	
+	OcfsGlobalCtxt.inode_cache = kmem_cache_create ("ocfs2_inode",
+		sizeof (struct ocfs_inode_info) + OCFS_POINTER_SIZE, 0, SLAB_NO_REAP | SLAB_HWCACHE_ALIGN,
+		NULL, NULL);
+#endif
 	OcfsGlobalCtxt.oin_cache = kmem_cache_create ("ocfs2_oin",
 		sizeof (ocfs_inode) + OCFS_POINTER_SIZE, 0, SLAB_NO_REAP | SLAB_HWCACHE_ALIGN,
 		NULL, NULL);
@@ -826,6 +851,9 @@
  */
 static void ocfs_free_mem_lists (void)
 {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+	kmem_cache_destroy (OcfsGlobalCtxt.inode_cache);
+#endif
 	kmem_cache_destroy (OcfsGlobalCtxt.oin_cache);
 	kmem_cache_destroy (OcfsGlobalCtxt.ofile_cache);
 	kmem_cache_destroy (OcfsGlobalCtxt.fe_cache);
Index: src/inc/ocfs.h
===================================================================
--- src/inc/ocfs.h	(revision 769)
+++ src/inc/ocfs.h	(working copy)
@@ -227,8 +227,85 @@
 #define ocfs_getpid()               getpid()
 #endif
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 
+struct ocfs_inode_info {
+	/* fs-private stuff */
+	void *           generic_ip;
+	__u64            voteoff;
+	__u64            feoff;
+	atomic_t         i_clean_buffer_seq;
+	__u8             deleted; /* this can be a generic flags field later */
+	struct inode vfs_inode;
+};
 
+static inline struct ocfs_inode_info *OCFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct ocfs_inode_info, vfs_inode);
+}
+
+static inline atomic_t *GET_INODE_CLEAN_SEQ(struct inode *inode)
+{
+	return &(OCFS_I(inode)->i_clean_buffer_seq);
+}
+
+static inline int inode_data_is_oin(struct inode *inode)
+{
+	return (OCFS_I(inode)->generic_ip != NULL);
+}
+
+static inline __u8 INODE_DELETED(struct inode *inode)
+{
+	return OCFS_I(inode)->deleted;
+}
+
+static inline void SET_INODE_DELETED(struct inode *inode)
+{
+	OCFS_I(inode)->deleted = 1;
+}
+
+static inline void CLEAR_INODE_DELETED(struct inode *inode)
+{
+	OCFS_I(inode)->deleted = 0;
+}
+
+static inline void SET_INODE_VOTEOFF(struct inode *inode, __u64 voteoff)
+{
+	OCFS_I(inode)->voteoff = voteoff;
+}
+
+static inline __u64 GET_INODE_VOTEOFF(struct inode *inode)
+{
+	return OCFS_I(inode)->voteoff;
+}
+
+static inline void SET_INODE_FEOFF(struct inode *inode, __u64 feoff)
+{
+	OCFS_I(inode)->feoff = feoff;
+}
+
+static inline __u64 GET_INODE_FEOFF(struct inode *inode)
+{
+	return OCFS_I(inode)->feoff;
+}
+
+static inline void CLEAR_INODE_OIN(struct inode *inode)
+{
+	OCFS_I(inode)->generic_ip = (void *)NULL;
+}
+
+static inline void SET_INODE_OIN(struct inode *inode, void *oin)
+{
+	OCFS_I(inode)->generic_ip = oin;
+}
+
+static inline void *GET_INODE_OIN(struct inode *inode)
+{
+	return OCFS_I(inode)->generic_ip;
+}
+
+#else
+
 typedef struct _ocfs_inode_private
 {
 	void *           generic_ip;
@@ -277,6 +354,8 @@
 
 #define GET_INODE_OIN(i) ((ocfs_inode *)(OCFS_GENERIC_IP(i)->generic_ip))
 
+#endif /* 2.4.x kernel */
+
 #define FIRST_FILE_ENTRY(dir)   ((char *) ((char *)dir)+OCFS_SECTOR_SIZE)
 #define FILEENT(dir,idx)        (ocfs_file_entry *) ( ((char *)dir) + \
                                 ((dir->index[idx]+1) * OCFS_SECTOR_SIZE))
@@ -2059,6 +2138,7 @@
 	ocfs_obj_id obj_id;
 	ocfs_sem res;
 	struct list_head osb_next;	/* List of all volumes */
+	kmem_cache_t *inode_cache;
 	kmem_cache_t *oin_cache;
 	kmem_cache_t *ofile_cache;
 	kmem_cache_t *fe_cache;
Index: src/namei.c
===================================================================
--- src/namei.c	(revision 769)
+++ src/namei.c	(working copy)
@@ -935,7 +935,7 @@
 
 	/* new parent dir offset */
 	if (inode_data_is_oin (new_dir))
-		newDirOff = (GET_INODE_OIN(new_dir))->dir_disk_off;
+		newDirOff = ((ocfs_inode *)GET_INODE_OIN(new_dir))->dir_disk_off;
 	else
 		newDirOff = GET_INODE_VOTEOFF (new_dir);
 


More information about the Ocfs2-devel mailing list