[Ocfs2-devel] [PATCH]2.6 mechanism for holding private inode data
Rusty Lynch
rusty at linux.co.intel.com
Thu Mar 11 13:53:00 CST 2004
On Wed, Mar 10, 2004 at 08:49:38PM -0800, Rusty Lynch wrote:
> 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.
>
What I was missing was the initialization of the newly allocated inode via
the kmem_cache_create constructor function pointer. The following patch
applies cleanly against v770 of svn (latest greatest as of this email.)
I think this path is ready for the tree.
--rusty
Index: src/super.c
===================================================================
--- src/super.c (revision 770)
+++ 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;
@@ -782,12 +802,34 @@
}
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
+{
+ struct ocfs_inode_info *i = (struct ocfs_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ i->generic_ip = NULL;
+ i->voteoff = 0;
+ i->feoff = 0;
+ atomic_set(&i->i_clean_buffer_seq, 0);
+ inode_init_once(&i->vfs_inode);
+ }
+}
+#endif
+
/*
* ocfs_initialize_mem_lists()
*
*/
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), 0,
+ SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT,
+ init_once, 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 +868,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 770)
+++ 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))
@@ -2077,6 +2156,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 770)
+++ 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