From 7acd6638ffedb2b0f8ab2025c8560336ca1977bc Mon Sep 17 00:00:00 2001 From: braam Date: Mon, 26 May 2003 08:55:42 +0000 Subject: [PATCH] - add llite to 2.5 compile chain. - start abstracting super.c commonality in llite_lib.c - fix obvious problems - start restoring the vfs_intent patch for 2.5 to one that hinges on path_release not the sprinkle of intent_release stuff from calsoft. --- .../patches/vfs_intent_2.5.69_rev1.patch | 283 ++++------ lustre/llite/Makefile.mk | 4 +- lustre/llite/llite_lib.c | 575 +++++++++++++++++++++ 3 files changed, 687 insertions(+), 175 deletions(-) create mode 100644 lustre/llite/llite_lib.c diff --git a/lustre/kernel_patches/patches/vfs_intent_2.5.69_rev1.patch b/lustre/kernel_patches/patches/vfs_intent_2.5.69_rev1.patch index 5b83e14..04f9329 100644 --- a/lustre/kernel_patches/patches/vfs_intent_2.5.69_rev1.patch +++ b/lustre/kernel_patches/patches/vfs_intent_2.5.69_rev1.patch @@ -1,6 +1,19 @@ ---- ./fs/nfsd/vfs.c.lustre 2003-05-21 16:46:55.000000000 -0700 -+++ ./fs/nfsd/vfs.c 2003-05-21 16:52:09.000000000 -0700 -@@ -1348,7 +1348,7 @@ + fs/dcache.c | 15 ++++- + fs/namei.c | 124 +++++++++++++++++++++++++++++++++++++------------ + fs/namespace.c | 1 + fs/nfsd/vfs.c | 2 + fs/open.c | 34 +++++++++++-- + fs/sysfs/inode.c | 2 + include/linux/dcache.h | 28 +++++++++++ + include/linux/fs.h | 21 +++++++- + include/linux/namei.h | 3 - + kernel/ksyms.c | 7 ++ + net/unix/af_unix.c | 2 + 11 files changed, 197 insertions(+), 42 deletions(-) + +--- uml-2.5/fs/nfsd/vfs.c~vfs_intent_2.5.69_rev1 2003-05-25 20:47:04.000000000 -0600 ++++ uml-2.5-braam/fs/nfsd/vfs.c 2003-05-25 23:19:05.000000000 -0600 +@@ -1348,7 +1348,7 @@ nfsd_rename(struct svc_rqst *rqstp, stru err = nfserr_perm; } else #endif @@ -9,9 +22,9 @@ if (!err && EX_ISSYNC(tfhp->fh_export)) { nfsd_sync_dir(tdentry); nfsd_sync_dir(fdentry); ---- ./fs/sysfs/inode.c.lustre 2003-05-21 16:46:59.000000000 -0700 -+++ ./fs/sysfs/inode.c 2003-05-21 16:52:09.000000000 -0700 -@@ -80,7 +80,7 @@ +--- uml-2.5/fs/sysfs/inode.c~vfs_intent_2.5.69_rev1 2003-05-25 20:47:10.000000000 -0600 ++++ uml-2.5-braam/fs/sysfs/inode.c 2003-05-25 23:19:05.000000000 -0600 +@@ -80,7 +80,7 @@ struct dentry * sysfs_get_dentry(struct qstr.name = name; qstr.len = strlen(name); qstr.hash = full_name_hash(name,qstr.len); @@ -20,24 +33,34 @@ } void sysfs_hash_and_remove(struct dentry * dir, const char * name) ---- ./fs/namei.c.lustre 2003-05-21 16:46:47.000000000 -0700 -+++ ./fs/namei.c 2003-05-21 16:54:59.000000000 -0700 -@@ -101,6 +101,14 @@ +--- uml-2.5/fs/namei.c~vfs_intent_2.5.69_rev1 2003-05-25 20:46:58.000000000 -0600 ++++ uml-2.5-braam/fs/namei.c 2003-05-26 02:42:14.000000000 -0600 +@@ -101,6 +101,8 @@ * any extra contention... */ ++ ++ + /* In order to reduce some races, while at the same time doing additional + * checking and hopefully speeding things up, we copy filenames to the + * kernel data space before using them.. +@@ -263,8 +265,15 @@ int deny_write_access(struct file * file + return 0; + } + +void intent_release(struct dentry *de, struct lookup_intent *it) +{ + if (it && de->d_op && de->d_op->d_intent_release) + de->d_op->d_intent_release(de, it); -+ +} + -+ - /* In order to reduce some races, while at the same time doing additional - * checking and hopefully speeding things up, we copy filenames to the - * kernel data space before using them.. -@@ -273,7 +281,7 @@ + void path_release(struct nameidata *nd) + { ++ intent_release(nd->dentry, &nd->it); + dput(nd->dentry); + mntput(nd->mnt); + } +@@ -273,7 +282,7 @@ void path_release(struct nameidata *nd) * Internal lookup() using the new generic dcache. * SMP-safe */ @@ -46,7 +69,7 @@ { struct dentry * dentry = __d_lookup(parent, name); -@@ -283,6 +291,14 @@ +@@ -283,6 +292,14 @@ static struct dentry * cached_lookup(str if (!dentry) dentry = d_lookup(parent, name); @@ -61,7 +84,7 @@ if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) { dput(dentry); -@@ -336,7 +352,7 @@ +@@ -336,7 +353,7 @@ ok: * make sure that nobody added the entry to the dcache in the meantime.. * SMP-safe */ @@ -70,7 +93,7 @@ { struct dentry * result; struct inode *dir = parent->d_inode; -@@ -361,7 +377,10 @@ +@@ -361,7 +378,10 @@ static struct dentry * real_lookup(struc struct dentry * dentry = d_alloc(parent, name); result = ERR_PTR(-ENOMEM); if (dentry) { @@ -82,7 +105,7 @@ if (result) dput(dentry); else -@@ -381,6 +400,12 @@ +@@ -381,6 +401,12 @@ static struct dentry * real_lookup(struc dput(result); result = ERR_PTR(-ENOENT); } @@ -95,15 +118,7 @@ } return result; } -@@ -410,6 +435,7 @@ - current->link_count--; - return err; - loop: -+ intent_release(dentry, &nd->it); - path_release(nd); - return err; - } -@@ -455,15 +481,26 @@ +@@ -455,15 +481,25 @@ static int follow_mount(struct vfsmount return res; } @@ -123,7 +138,6 @@ + opc = it->it_op; + mode = it->it_mode; + } -+ intent_release(*dentry, it); + if (it) { + it->it_op = opc; + it->it_mode = mode; @@ -131,7 +145,7 @@ dput(*dentry); mntput(mounted->mnt_parent); *dentry = dget(mounted->mnt_root); -@@ -475,7 +512,7 @@ +@@ -475,7 +511,7 @@ static inline int __follow_down(struct v int follow_down(struct vfsmount **mnt, struct dentry **dentry) { @@ -140,7 +154,7 @@ } static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry) -@@ -539,7 +576,7 @@ +@@ -539,7 +575,7 @@ done: return 0; need_lookup: @@ -149,7 +163,7 @@ if (IS_ERR(dentry)) goto fail; goto done; -@@ -673,7 +710,7 @@ +@@ -673,7 +709,7 @@ int link_path_walk(const char * name, st nd->dentry = next.dentry; } err = -ENOTDIR; @@ -158,7 +172,7 @@ break; continue; /* here ends the main loop */ -@@ -724,7 +761,8 @@ +@@ -724,7 +760,8 @@ last_component: break; if (lookup_flags & LOOKUP_DIRECTORY) { err = -ENOTDIR; @@ -168,15 +182,7 @@ break; } goto return_base; -@@ -743,6 +781,7 @@ - dput(next.dentry); - break; - } -+ intent_release(nd->dentry, &nd->it); - path_release(nd); - return_err: - return err; -@@ -866,7 +905,8 @@ +@@ -866,7 +903,8 @@ int path_lookup(const char *name, unsign * needs parent already locked. Doesn't follow mounts. * SMP-safe. */ @@ -186,7 +192,7 @@ { struct dentry * dentry; struct inode *inode; -@@ -889,13 +929,16 @@ +@@ -889,13 +927,16 @@ struct dentry * lookup_hash(struct qstr goto out; } @@ -205,7 +211,7 @@ if (!dentry) dentry = new; else -@@ -906,7 +949,7 @@ +@@ -906,7 +947,7 @@ out: } /* SMP-safe */ @@ -214,7 +220,7 @@ { unsigned long hash; struct qstr this; -@@ -926,11 +969,16 @@ +@@ -926,11 +967,16 @@ struct dentry * lookup_one_len(const cha } this.hash = end_name_hash(hash); @@ -232,7 +238,7 @@ /* * namei() * -@@ -1232,6 +1280,9 @@ +@@ -1232,6 +1278,9 @@ int open_namei(const char * pathname, in /* * Create - we need to know the parent. */ @@ -242,7 +248,7 @@ error = path_lookup(pathname, LOOKUP_PARENT, nd); if (error) return error; -@@ -1247,7 +1298,7 @@ +@@ -1247,7 +1296,7 @@ int open_namei(const char * pathname, in dir = nd->dentry; down(&dir->d_inode->i_sem); @@ -251,7 +257,7 @@ do_last: error = PTR_ERR(dentry); -@@ -1255,7 +1306,8 @@ +@@ -1255,7 +1304,8 @@ do_last: up(&dir->d_inode->i_sem); goto exit; } @@ -261,7 +267,7 @@ /* Negative dentry, just create the file */ if (!dentry->d_inode) { if (!IS_POSIXACL(dir->d_inode)) -@@ -1285,7 +1337,7 @@ +@@ -1285,7 +1335,7 @@ do_last: error = -ELOOP; if (flag & O_NOFOLLOW) goto exit_dput; @@ -270,18 +276,7 @@ } error = -ENOENT; if (!dentry->d_inode) -@@ -1305,8 +1357,10 @@ - return 0; - - exit_dput: -+ intent_release(dentry, &nd->it); - dput(dentry); - exit: -+ intent_release(nd->dentry, &nd->it); - path_release(nd); - return error; - -@@ -1328,7 +1382,12 @@ +@@ -1328,7 +1378,10 @@ do_link: if (error) goto exit_dput; UPDATE_ATIME(dentry->d_inode); @@ -290,12 +285,10 @@ + error = dentry->d_inode->i_op->follow_link2(dentry, nd, &nd->it); + else + error = dentry->d_inode->i_op->follow_link(dentry, nd); -+ if (error) -+ intent_release(dentry, &nd->it); dput(dentry); if (error) return error; -@@ -1350,7 +1409,7 @@ +@@ -1350,7 +1403,7 @@ do_link: } dir = nd->dentry; down(&dir->d_inode->i_sem); @@ -304,7 +297,7 @@ putname(nd->last.name); goto do_last; } -@@ -1364,7 +1423,7 @@ +@@ -1364,7 +1417,7 @@ static struct dentry *lookup_create(stru dentry = ERR_PTR(-EEXIST); if (nd->last_type != LAST_NORM) goto fail; @@ -313,7 +306,7 @@ if (IS_ERR(dentry)) goto fail; if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode) -@@ -1596,7 +1655,7 @@ +@@ -1596,7 +1649,7 @@ asmlinkage long sys_rmdir(const char __u goto exit1; } down(&nd.dentry->d_inode->i_sem); @@ -322,7 +315,7 @@ error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { error = vfs_rmdir(nd.dentry->d_inode, dentry); -@@ -1662,8 +1721,18 @@ +@@ -1662,8 +1715,18 @@ asmlinkage long sys_unlink(const char __ error = -EISDIR; if (nd.last_type != LAST_NORM) goto exit1; @@ -342,7 +335,7 @@ error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { /* Why not before? Because we want correct error value */ -@@ -1867,7 +1936,8 @@ +@@ -1867,7 +1930,8 @@ exit: * locking]. */ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, @@ -352,15 +345,7 @@ { int error = 0; struct inode *target; -@@ -1895,6 +1965,7 @@ - error = -EBUSY; - else - error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); -+ intent_release(new_dentry, it); - if (target) { - if (!error) - target->i_flags |= S_DEAD; -@@ -1912,7 +1983,8 @@ +@@ -1912,7 +1976,8 @@ int vfs_rename_dir(struct inode *old_dir } int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, @@ -370,15 +355,7 @@ { struct inode *target; int error; -@@ -1929,6 +2001,7 @@ - error = -EBUSY; - else - error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); -+ intent_release(new_dentry, it); - if (!error) { - /* The following d_move() should become unconditional */ - if (!(old_dir->i_sb->s_type->fs_flags & FS_ODD_RENAME)) -@@ -1942,7 +2015,8 @@ +@@ -1942,7 +2007,8 @@ int vfs_rename_other(struct inode *old_d } int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, @@ -388,7 +365,7 @@ { int error; int is_dir = S_ISDIR(old_dentry->d_inode->i_mode); -@@ -1968,9 +2042,9 @@ +@@ -1968,9 +2034,9 @@ int vfs_rename(struct inode *old_dir, st DQUOT_INIT(new_dir); if (is_dir) @@ -400,7 +377,7 @@ if (!error) { if (old_dir == new_dir) inode_dir_notify(old_dir, DN_RENAME); -@@ -2013,7 +2087,7 @@ +@@ -2013,7 +2079,7 @@ static inline int do_rename(const char * trap = lock_rename(new_dir, old_dir); @@ -409,7 +386,7 @@ error = PTR_ERR(old_dentry); if (IS_ERR(old_dentry)) goto exit3; -@@ -2033,7 +2107,7 @@ +@@ -2033,7 +2099,7 @@ static inline int do_rename(const char * error = -EINVAL; if (old_dentry == trap) goto exit4; @@ -418,7 +395,7 @@ error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) goto exit4; -@@ -2043,7 +2117,7 @@ +@@ -2043,7 +2109,7 @@ static inline int do_rename(const char * goto exit5; error = vfs_rename(old_dir->d_inode, old_dentry, @@ -427,9 +404,9 @@ exit5: dput(new_dentry); exit4: ---- ./fs/dcache.c.lustre 2003-05-21 16:46:47.000000000 -0700 -+++ ./fs/dcache.c 2003-05-21 16:56:51.000000000 -0700 -@@ -1134,14 +1134,23 @@ +--- uml-2.5/fs/dcache.c~vfs_intent_2.5.69_rev1 2003-05-25 20:46:58.000000000 -0600 ++++ uml-2.5-braam/fs/dcache.c 2003-05-25 23:19:05.000000000 -0600 +@@ -1134,14 +1134,23 @@ void d_delete(struct dentry * dentry) * Adds a dentry to the hash according to its name. */ @@ -456,9 +433,9 @@ } #define do_switch(x,y) do { \ ---- ./fs/namespace.c.lustre 2003-05-21 16:46:47.000000000 -0700 -+++ ./fs/namespace.c 2003-05-21 16:52:09.000000000 -0700 -@@ -927,6 +927,7 @@ +--- uml-2.5/fs/namespace.c~vfs_intent_2.5.69_rev1 2003-05-25 20:46:58.000000000 -0600 ++++ uml-2.5-braam/fs/namespace.c 2003-05-25 23:19:05.000000000 -0600 +@@ -927,6 +927,7 @@ void set_fs_pwd(struct fs_struct *fs, st mntput(old_pwdmnt); } } @@ -466,9 +443,9 @@ static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) { ---- ./fs/open.c.lustre 2003-05-21 16:46:48.000000000 -0700 -+++ ./fs/open.c 2003-05-21 16:52:10.000000000 -0700 -@@ -97,7 +97,8 @@ +--- uml-2.5/fs/open.c~vfs_intent_2.5.69_rev1 2003-05-25 20:46:58.000000000 -0600 ++++ uml-2.5-braam/fs/open.c 2003-05-26 02:42:14.000000000 -0600 +@@ -97,7 +97,8 @@ static inline long do_sys_truncate(const struct nameidata nd; struct inode * inode; int error; @@ -478,21 +455,7 @@ error = -EINVAL; if (length < 0) /* sorry, but loff_t says... */ goto out; -@@ -142,11 +143,13 @@ - error = locks_verify_truncate(inode, NULL, length); - if (!error) { - DQUOT_INIT(inode); -+ intent_release(nd.dentry, &nd.it); - error = do_truncate(nd.dentry, length); - } - put_write_access(inode); - - dput_and_out: -+ intent_release(nd.dentry, &nd.it); - path_release(&nd); - out: - return error; -@@ -340,6 +343,8 @@ +@@ -340,6 +341,8 @@ asmlinkage long sys_access(const char __ int old_fsuid, old_fsgid; kernel_cap_t old_cap; int res; @@ -501,16 +464,15 @@ if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ return -EINVAL; -@@ -371,6 +376,8 @@ +@@ -371,6 +374,7 @@ asmlinkage long sys_access(const char __ if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) && !special_file(nd.dentry->d_inode->i_mode)) res = -EROFS; + -+ intent_release(nd.dentry, &nd.it); path_release(&nd); } -@@ -385,6 +392,8 @@ +@@ -385,6 +389,8 @@ asmlinkage long sys_chdir(const char __u { struct nameidata nd; int error; @@ -519,15 +481,7 @@ error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd); if (error) -@@ -397,6 +406,7 @@ - set_fs_pwd(current->fs, nd.mnt, nd.dentry); - - dput_and_out: -+ intent_release(nd.dentry, &nd.it); - path_release(&nd); - out: - return error; -@@ -436,6 +446,8 @@ +@@ -436,6 +442,8 @@ asmlinkage long sys_chroot(const char __ { struct nameidata nd; int error; @@ -536,7 +490,7 @@ error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd); if (error) -@@ -508,6 +520,18 @@ +@@ -508,6 +516,18 @@ asmlinkage long sys_chmod(const char __u error = -EROFS; if (IS_RDONLY(inode)) goto dput_and_out; @@ -555,7 +509,7 @@ error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) -@@ -619,7 +643,10 @@ +@@ -619,7 +639,10 @@ asmlinkage long sys_fchown(unsigned int struct file *filp_open(const char * filename, int flags, int mode) { int namei_flags, error; @@ -566,7 +520,7 @@ namei_flags = flags; if ((namei_flags+1) & O_ACCMODE) -@@ -628,9 +655,11 @@ +@@ -628,9 +651,10 @@ struct file *filp_open(const char * file namei_flags |= 2; error = open_namei(filename, namei_flags, mode, &nd); @@ -575,13 +529,12 @@ - + if (!error) { + temp_filp = dentry_open(nd.dentry, nd.mnt, flags); -+ intent_release(nd.dentry,&nd.it); + return temp_filp; + } return ERR_PTR(error); } -@@ -675,7 +704,7 @@ +@@ -675,7 +699,7 @@ struct file *dentry_open(struct dentry * goto cleanup_all; } } @@ -590,26 +543,8 @@ return f; cleanup_all: ---- ./fs/stat.c.lustre 2003-05-21 16:46:48.000000000 -0700 -+++ ./fs/stat.c 2003-05-21 16:52:10.000000000 -0700 -@@ -64,6 +64,7 @@ - error = user_path_walk(name, &nd); - if (!error) { - error = vfs_getattr(nd.mnt, nd.dentry, stat); -+ intent_release(nd.dentry, &nd.it); - path_release(&nd); - } - return error; -@@ -77,6 +78,7 @@ - error = user_path_walk_link(name, &nd); - if (!error) { - error = vfs_getattr(nd.mnt, nd.dentry, stat); -+ intent_release(nd.dentry, &nd.it); - path_release(&nd); - } - return error; ---- ./include/linux/dcache.h.lustre 2003-05-21 16:47:30.000000000 -0700 -+++ ./include/linux/dcache.h 2003-05-21 16:57:26.000000000 -0700 +--- uml-2.5/include/linux/dcache.h~vfs_intent_2.5.69_rev1 2003-05-25 20:47:22.000000000 -0600 ++++ uml-2.5-braam/include/linux/dcache.h 2003-05-25 23:19:05.000000000 -0600 @@ -12,6 +12,27 @@ struct vfsmount; @@ -638,7 +573,7 @@ /* * linux/include/linux/dcache.h * -@@ -34,6 +55,8 @@ +@@ -34,6 +55,8 @@ struct qstr { char name_str[0]; }; @@ -647,7 +582,7 @@ struct dentry_stat_t { int nr_dentry; int nr_unused; -@@ -97,6 +120,7 @@ +@@ -97,6 +120,7 @@ struct dentry { unsigned long d_move_count; /* to indicated moved dentry while lockless lookup */ struct qstr * d_qstr; /* quick str ptr used in lockless lookup and concurrent d_move */ struct dentry * d_parent; /* parent directory */ @@ -655,7 +590,7 @@ struct qstr d_name; struct hlist_node d_hash; /* lookup hash list */ struct hlist_head * d_bucket; /* lookup hash bucket */ -@@ -112,6 +136,8 @@ +@@ -112,6 +136,8 @@ struct dentry_operations { int (*d_delete)(struct dentry *); void (*d_release)(struct dentry *); void (*d_iput)(struct dentry *, struct inode *); @@ -664,7 +599,7 @@ }; /* the dentry parameter passed to d_hash and d_compare is the parent -@@ -152,6 +178,8 @@ +@@ -152,6 +178,8 @@ d_iput: no no yes #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */ #define DCACHE_UNHASHED 0x0010 @@ -673,9 +608,9 @@ extern spinlock_t dcache_lock; ---- ./include/linux/fs.h.lustre 2003-05-21 16:47:30.000000000 -0700 -+++ ./include/linux/fs.h 2003-05-21 20:52:59.000000000 -0700 -@@ -237,6 +237,9 @@ +--- uml-2.5/include/linux/fs.h~vfs_intent_2.5.69_rev1 2003-05-25 20:47:22.000000000 -0600 ++++ uml-2.5-braam/include/linux/fs.h 2003-05-25 23:19:05.000000000 -0600 +@@ -237,6 +237,9 @@ typedef int (get_blocks_t)(struct inode #define ATTR_ATTR_FLAG 1024 #define ATTR_KILL_SUID 2048 #define ATTR_KILL_SGID 4096 @@ -685,7 +620,7 @@ /* * This is the Inode Attributes structure, used for notify_change(). It -@@ -644,7 +647,7 @@ +@@ -644,7 +647,7 @@ extern int vfs_symlink(struct inode *, s extern int vfs_link(struct dentry *, struct inode *, struct dentry *); extern int vfs_rmdir(struct inode *, struct dentry *); extern int vfs_unlink(struct inode *, struct dentry *); @@ -694,7 +629,7 @@ /* * File types -@@ -730,19 +733,33 @@ +@@ -730,19 +733,33 @@ struct file_operations { struct inode_operations { int (*create) (struct inode *,struct dentry *,int); struct dentry * (*lookup) (struct inode *,struct dentry *); @@ -728,7 +663,7 @@ int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); -@@ -956,6 +973,7 @@ +@@ -956,6 +973,7 @@ extern int register_filesystem(struct fi extern int unregister_filesystem(struct file_system_type *); extern struct vfsmount *kern_mount(struct file_system_type *); extern int may_umount(struct vfsmount *); @@ -736,7 +671,7 @@ extern long do_mount(char *, char *, char *, unsigned long, void *); extern int vfs_statfs(struct super_block *, struct statfs *); -@@ -1116,6 +1134,7 @@ +@@ -1116,6 +1134,7 @@ extern void sync_filesystems(int wait); extern sector_t bmap(struct inode *, sector_t); extern int setattr_mask(unsigned int); extern int notify_change(struct dentry *, struct iattr *); @@ -744,9 +679,9 @@ extern int permission(struct inode *, int); extern int vfs_permission(struct inode *, int); extern int get_write_access(struct inode *); ---- ./include/linux/namei.h.lustre 2003-05-21 16:47:31.000000000 -0700 -+++ ./include/linux/namei.h 2003-05-21 16:52:09.000000000 -0700 -@@ -11,6 +11,7 @@ +--- uml-2.5/include/linux/namei.h~vfs_intent_2.5.69_rev1 2003-05-25 20:47:23.000000000 -0600 ++++ uml-2.5-braam/include/linux/namei.h 2003-05-25 23:19:05.000000000 -0600 +@@ -11,6 +11,7 @@ struct nameidata { struct qstr last; unsigned int flags; int last_type; @@ -754,7 +689,7 @@ }; /* -@@ -44,7 +45,7 @@ +@@ -44,7 +45,7 @@ extern int FASTCALL(link_path_walk(const extern void path_release(struct nameidata *); extern struct dentry * lookup_one_len(const char *, struct dentry *, int); @@ -763,9 +698,9 @@ extern int follow_down(struct vfsmount **, struct dentry **); extern int follow_up(struct vfsmount **, struct dentry **); ---- ./kernel/ksyms.c.lustre 2003-05-21 16:47:40.000000000 -0700 -+++ ./kernel/ksyms.c 2003-05-21 16:52:09.000000000 -0700 -@@ -374,6 +374,7 @@ +--- uml-2.5/kernel/ksyms.c~vfs_intent_2.5.69_rev1 2003-05-25 20:47:36.000000000 -0600 ++++ uml-2.5-braam/kernel/ksyms.c 2003-05-25 23:19:05.000000000 -0600 +@@ -374,6 +374,7 @@ EXPORT_SYMBOL(unregister_filesystem); EXPORT_SYMBOL(kern_mount); EXPORT_SYMBOL(__mntput); EXPORT_SYMBOL(may_umount); @@ -773,7 +708,7 @@ /* executable format registration */ EXPORT_SYMBOL(register_binfmt); -@@ -404,6 +405,12 @@ +@@ -404,6 +405,12 @@ EXPORT_SYMBOL(request_irq); EXPORT_SYMBOL(free_irq); EXPORT_SYMBOL(irq_stat); @@ -786,9 +721,9 @@ /* waitqueue handling */ EXPORT_SYMBOL(add_wait_queue); EXPORT_SYMBOL(add_wait_queue_exclusive); ---- ./net/unix/af_unix.c.lustre 2003-05-21 16:47:50.000000000 -0700 -+++ ./net/unix/af_unix.c 2003-05-21 16:52:09.000000000 -0700 -@@ -721,7 +721,7 @@ +--- uml-2.5/net/unix/af_unix.c~vfs_intent_2.5.69_rev1 2003-05-25 20:47:44.000000000 -0600 ++++ uml-2.5-braam/net/unix/af_unix.c 2003-05-25 23:19:05.000000000 -0600 +@@ -721,7 +721,7 @@ static int unix_bind(struct socket *sock /* * Do the final lookup. */ @@ -797,3 +732,5 @@ err = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out_mknod_unlock; + +_ diff --git a/lustre/llite/Makefile.mk b/lustre/llite/Makefile.mk index 1b182ce..e735949 100644 --- a/lustre/llite/Makefile.mk +++ b/lustre/llite/Makefile.mk @@ -6,5 +6,5 @@ include $(src)/../portals/Kernelenv obj-y += llite.o -llite-objs := dcache.o commit_callback.o super.o rw.o iod.o super25.o \ - file.o dir.o sysctl.o symlink.o namei.o lproc_llite.o +llite-objs := llite_lib.o dcache.o commit_callback.o super.o rw.o iod.o \ + super25.o file.o dir.o sysctl.o symlink.o namei.o lproc_llite.o diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c new file mode 100644 index 0000000..22f7f2f --- /dev/null +++ b/lustre/llite/llite_lib.c @@ -0,0 +1,575 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Lustre Light Super operations + * + * Copyright (c) 2002, 2003 Cluster File Systems, Inc. + * + * This file is part of Lustre, http://www.lustre.org. + * + * Lustre is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * Lustre is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define DEBUG_SUBSYSTEM S_LLITE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/* whole file is conditional, but we need KERNEL_VERSION and friends */ +kmem_cache_t *ll_file_data_slab; +struct super_operations ll_super_operations; + +/* /proc/lustre/llite root that tracks llite mount points */ +struct proc_dir_entry *proc_lustre_fs_root = NULL; + + +char *ll_read_opt(const char *opt, char *data) +{ + char *value; + char *retval; + ENTRY; + + CDEBUG(D_SUPER, "option: %s, data %s\n", opt, data); + if (strncmp(opt, data, strlen(opt))) + RETURN(NULL); + if ((value = strchr(data, '=')) == NULL) + RETURN(NULL); + + value++; + OBD_ALLOC(retval, strlen(value) + 1); + if (!retval) { + CERROR("out of memory!\n"); + RETURN(NULL); + } + + memcpy(retval, value, strlen(value)+1); + CDEBUG(D_SUPER, "Assigned option: %s, value %s\n", opt, retval); + RETURN(retval); +} + +int ll_set_opt(const char *opt, char *data, int fl) +{ + ENTRY; + + CDEBUG(D_SUPER, "option: %s, data %s\n", opt, data); + if (strncmp(opt, data, strlen(opt))) + RETURN(0); + else + RETURN(fl); +} + +void ll_options(char *options, char **ost, char **mds, int *flags) +{ + char *this_char, *opt_ptr; + ENTRY; + + if (!options) { + EXIT; + return; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + for (this_char = strtok (options, ","); + this_char != NULL; + this_char = strtok (NULL, ",")) { +#else + while ((this_char = strsep (&opt_ptr, ",")) != NULL) { +#endif + CDEBUG(D_SUPER, "this_char %s\n", this_char); + if ((!*ost && (*ost = ll_read_opt("osc", this_char)))|| + (!*mds && (*mds = ll_read_opt("mdc", this_char)))|| + (!(*flags & LL_SBI_NOLCK) && + ((*flags) = (*flags) | + ll_set_opt("nolock", this_char, LL_SBI_NOLCK)))) + continue; + } + EXIT; +} + +struct super_block *ll_fill_super(struct super_block *sb, + void *data, int silent) +{ + struct inode *root = 0; + struct obd_device *obd; + struct ll_sb_info *sbi; + char *osc = NULL; + char *mdc = NULL; + int err; + struct ll_fid rootfid; + struct obd_statfs osfs; + struct ptlrpc_request *request = NULL; + struct ptlrpc_connection *mdc_conn; + struct ll_read_inode2_cookie lic; + class_uuid_t uuid; + struct obd_uuid param_uuid; + + ENTRY; + + CDEBUG(D_VFSTRACE, "VFS Op:\n"); + OBD_ALLOC(sbi, sizeof(*sbi)); + if (!sbi) + RETURN(NULL); + + INIT_LIST_HEAD(&sbi->ll_conn_chain); + INIT_HLIST_HEAD(&sbi->ll_orphan_dentry_list); + generate_random_uuid(uuid); + spin_lock_init(&sbi->ll_iostats.fis_lock); + class_uuid_unparse(uuid, &sbi->ll_sb_uuid); + + ll_s2sbi(sb) = sbi; + + ll_options(data, &osc, &mdc, &sbi->ll_flags); + + if (!osc) { + CERROR("no osc\n"); + GOTO(out_free, sb = NULL); + } + + if (!mdc) { + CERROR("no mdc\n"); + GOTO(out_free, sb = NULL); + } + + strncpy(param_uuid.uuid, mdc, sizeof(param_uuid.uuid)); + obd = class_uuid2obd(¶m_uuid); + if (!obd) { + CERROR("MDC %s: not setup or attached\n", mdc); + GOTO(out_free, sb = NULL); + } + + err = obd_connect(&sbi->ll_mdc_conn, obd, &sbi->ll_sb_uuid); + if (err) { + CERROR("cannot connect to %s: rc = %d\n", mdc, err); + GOTO(out_free, sb = NULL); + } + + mdc_conn = sbi2mdc(sbi)->cl_import->imp_connection; + + strncpy(param_uuid.uuid, osc, sizeof(param_uuid.uuid)); + obd = class_uuid2obd(¶m_uuid); + if (!obd) { + CERROR("OSC %s: not setup or attached\n", osc); + GOTO(out_mdc, sb = NULL); + } + + err = obd_connect(&sbi->ll_osc_conn, obd, &sbi->ll_sb_uuid); + if (err) { + CERROR("cannot connect to %s: rc = %d\n", osc, err); + GOTO(out_mdc, sb = NULL); + } + + err = mdc_getstatus(&sbi->ll_mdc_conn, &rootfid); + if (err) { + CERROR("cannot mds_connect: rc = %d\n", err); + GOTO(out_osc, sb = NULL); + } + CDEBUG(D_SUPER, "rootfid "LPU64"\n", rootfid.id); + sbi->ll_rootino = rootfid.id; + + memset(&osfs, 0, sizeof(osfs)); + err = obd_statfs(&sbi->ll_mdc_conn, &osfs); + sb->s_blocksize = osfs.os_bsize; + sb->s_blocksize_bits = log2(osfs.os_bsize); + sb->s_magic = LL_SUPER_MAGIC; + sb->s_maxbytes = (1ULL << (32 + 9)) - osfs.os_bsize; + + sb->s_op = &ll_super_operations; + + /* make root inode + * XXX: move this to after cbd setup? */ + err = mdc_getattr(&sbi->ll_mdc_conn, &rootfid, + OBD_MD_FLNOTOBD|OBD_MD_FLBLOCKS, 0, &request); + if (err) { + CERROR("mdc_getattr failed for root: rc = %d\n", err); + GOTO(out_osc, sb = NULL); + } + + /* initialize committed transaction callback daemon */ + spin_lock_init(&sbi->ll_commitcbd_lock); + init_waitqueue_head(&sbi->ll_commitcbd_waitq); + init_waitqueue_head(&sbi->ll_commitcbd_ctl_waitq); + sbi->ll_commitcbd_flags = 0; + err = ll_commitcbd_setup(sbi); + if (err) { + CERROR("failed to start commit callback daemon: rc = %d\n",err); + ptlrpc_req_finished (request); + GOTO(out_osc, sb = NULL); + } + + lic.lic_body = lustre_msg_buf(request->rq_repmsg, 0, + sizeof(*lic.lic_body)); + LASSERT (lic.lic_body != NULL); /* checked by mdc_getattr() */ + LASSERT_REPSWABBED (request, 0); /* swabbed by mdc_getattr() */ + + lic.lic_lsm = NULL; + + LASSERT(sbi->ll_rootino != 0); + root = ll_iget(sb, sbi->ll_rootino, &lic); + + ptlrpc_req_finished(request); + + if (root == NULL || is_bad_inode(root)) { + /* XXX might need iput() for bad inode */ + CERROR("lustre_lite: bad iget4 for root\n"); + GOTO(out_cbd, sb = NULL); + } + + sb->s_root = d_alloc_root(root); + + if (proc_lustre_fs_root) { + err = lprocfs_register_mountpoint(proc_lustre_fs_root, sb, + osc, mdc); + if (err < 0) + CERROR("could not register mount in /proc/lustre"); + } + +out_dev: + if (mdc) + OBD_FREE(mdc, strlen(mdc) + 1); + if (osc) + OBD_FREE(osc, strlen(osc) + 1); + + RETURN(sb); + +out_cbd: + ll_commitcbd_cleanup(sbi); +out_osc: + obd_disconnect(&sbi->ll_osc_conn, 0); +out_mdc: + obd_disconnect(&sbi->ll_mdc_conn, 0); +out_free: + OBD_FREE(sbi, sizeof(*sbi)); + + goto out_dev; +} /* ll_read_super */ + +int ll_statfs(struct super_block *sb, struct statfs *sfs) +{ + struct ll_sb_info *sbi = ll_s2sbi(sb); + struct obd_statfs osfs; + int rc; + ENTRY; + + CDEBUG(D_VFSTRACE, "VFS Op:\n"); + memset(sfs, 0, sizeof(*sfs)); + rc = obd_statfs(&sbi->ll_mdc_conn, &osfs); + statfs_unpack(sfs, &osfs); + if (rc) + CERROR("mdc_statfs fails: rc = %d\n", rc); + else + CDEBUG(D_SUPER, "mdc_statfs shows blocks "LPU64"/"LPU64 + " objects "LPU64"/"LPU64"\n", + osfs.os_bavail, osfs.os_blocks, + osfs.os_ffree, osfs.os_files); + + /* temporary until mds_statfs returns statfs info for all OSTs */ + if (!rc) { + rc = obd_statfs(&sbi->ll_osc_conn, &osfs); + if (rc) { + CERROR("obd_statfs fails: rc = %d\n", rc); + GOTO(out, rc); + } + CDEBUG(D_SUPER, "obd_statfs shows blocks "LPU64"/"LPU64 + " objects "LPU64"/"LPU64"\n", + osfs.os_bavail, osfs.os_blocks, + osfs.os_ffree, osfs.os_files); + + while (osfs.os_blocks > ~0UL) { + sfs->f_bsize <<= 1; + + osfs.os_blocks >>= 1; + osfs.os_bfree >>= 1; + osfs.os_bavail >>= 1; + } + sfs->f_blocks = osfs.os_blocks; + sfs->f_bfree = osfs.os_bfree; + sfs->f_bavail = osfs.os_bavail; + if (osfs.os_ffree < (__u64)sfs->f_ffree) + sfs->f_ffree = osfs.os_ffree; + } + +out: + RETURN(rc); +} +/* like inode_setattr, but doesn't mark the inode dirty */ +static int ll_attr2inode(struct inode *inode, struct iattr *attr, int trunc) +{ + unsigned int ia_valid = attr->ia_valid; + int error = 0; + + if ((ia_valid & ATTR_SIZE) && trunc) { + error = vmtruncate(inode, attr->ia_size); + if (error) + goto out; + } else if (ia_valid & ATTR_SIZE) + inode->i_size = attr->ia_size; + + if (ia_valid & ATTR_UID) + inode->i_uid = attr->ia_uid; + if (ia_valid & ATTR_GID) + inode->i_gid = attr->ia_gid; + if (ia_valid & ATTR_ATIME) + inode->i_atime = attr->ia_atime; + if (ia_valid & ATTR_MTIME) + inode->i_mtime = attr->ia_mtime; + if (ia_valid & ATTR_CTIME) + inode->i_ctime = attr->ia_ctime; + if (ia_valid & ATTR_MODE) { + inode->i_mode = attr->ia_mode; + if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) + inode->i_mode &= ~S_ISGID; + } +out: + return error; +} + +int ll_inode_setattr(struct inode *inode, struct iattr *attr, int do_trunc) +{ + struct ptlrpc_request *request = NULL; + struct ll_sb_info *sbi = ll_i2sbi(inode); + int err = 0; + ENTRY; + + /* change incore inode */ + ll_attr2inode(inode, attr, do_trunc); + + /* Don't send size changes to MDS to avoid "fast EA" problems, and + * also avoid a pointless RPC (we get file size from OST anyways). + */ + attr->ia_valid &= ~ATTR_SIZE; + if (attr->ia_valid) { + struct mdc_op_data op_data; + + ll_prepare_mdc_op_data(&op_data, inode, NULL, NULL, 0, 0); + err = mdc_setattr(&sbi->ll_mdc_conn, &op_data, + attr, NULL, 0, &request); + if (err) + CERROR("mdc_setattr fails: err = %d\n", err); + + ptlrpc_req_finished(request); + if (S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_MTIME_SET) { + struct lov_stripe_md *lsm = ll_i2info(inode)->lli_smd; + struct obdo oa; + int err2; + + CDEBUG(D_INODE, "set mtime on OST inode %lu to %Lu\n", + inode->i_ino, ll_ts2u64(&attr->ia_mtime)); + oa.o_id = lsm->lsm_object_id; + oa.o_mode = S_IFREG; + oa.o_valid = OBD_MD_FLID |OBD_MD_FLTYPE |OBD_MD_FLMTIME; + oa.o_mtime = ll_ts2u64(&attr->ia_mtime); + err2 = obd_setattr(&sbi->ll_osc_conn, &oa, lsm, NULL); + if (err2) { + CERROR("obd_setattr fails: rc=%d\n", err); + if (!err) + err = err2; + } + } + } + + RETURN(err); +} + +int ll_setattr_raw(struct inode *inode, struct iattr *attr) +{ + struct lov_stripe_md *lsm = ll_i2info(inode)->lli_smd; + struct ll_sb_info *sbi = ll_i2sbi(inode); + struct ptlrpc_request *request = NULL; + struct mdc_op_data op_data; + int rc = 0, err; + ENTRY; + CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu\n", inode->i_ino); + + if ((attr->ia_valid & ATTR_SIZE)) { + struct ldlm_extent extent = {attr->ia_size, OBD_OBJECT_EOF}; + struct lustre_handle lockh = { 0, 0 }; + + /* If this file doesn't have stripes yet, it is already, + by definition, truncated. */ + if (attr->ia_valid & ATTR_FROM_OPEN && lsm == NULL) { + LASSERT(attr->ia_size == 0); + GOTO(skip_extent_lock, rc = 0); + } + + /* we really need to get our PW lock before we change + * inode->i_size. if we don't we can race with other + * i_size updaters on our node, like ll_file_read. we + * can also race with i_size propogation to other + * nodes through dirtying and writeback of final cached + * pages. this last one is especially bad for racing + * o_append users on other nodes. */ + rc = ll_extent_lock_no_validate(NULL, inode, lsm, LCK_PW, + &extent, &lockh); + if (rc != ELDLM_OK) { + if (rc > 0) + RETURN(-ENOLCK); + RETURN(rc); + } + + rc = vmtruncate(inode, attr->ia_size); + if (rc == 0) + set_bit(LLI_F_HAVE_SIZE_LOCK, + &ll_i2info(inode)->lli_flags); + + /* unlock now as we don't mind others file lockers racing with + * the mds updates below? */ + err = ll_extent_unlock(NULL, inode, lsm, LCK_PW, &lockh); + if (err) + CERROR("ll_extent_unlock failed: %d\n", err); + if (rc) + RETURN(rc); + } + +skip_extent_lock: + /* Don't send size changes to MDS to avoid "fast EA" problems, and + * also avoid a pointless RPC (we get file size from OST anyways). + */ + attr->ia_valid &= ~ATTR_SIZE; + if (!attr->ia_valid) + RETURN(0); + + ll_prepare_mdc_op_data(&op_data, inode, NULL, NULL, 0, 0); + + err = mdc_setattr(&sbi->ll_mdc_conn, &op_data, + attr, NULL, 0, &request); + if (err) + CERROR("mdc_setattr fails: err = %d\n", err); + + ptlrpc_req_finished(request); + + if (S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_MTIME_SET) { + struct lov_stripe_md *lsm = ll_i2info(inode)->lli_smd; + struct obdo oa; + int err2; + + CDEBUG(D_INODE, "set mtime on OST inode %lu to %Lu\n", + inode->i_ino, ll_ts2u64(&attr->ia_mtime)); + oa.o_id = lsm->lsm_object_id; + oa.o_mode = S_IFREG; + oa.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMTIME; + oa.o_mtime = ll_ts2u64(&attr->ia_mtime); + err2 = obd_setattr(&sbi->ll_osc_conn, &oa, lsm, NULL); + if (err2) { + CERROR("obd_setattr fails: rc=%d\n", err); + if (!err) + err = err2; + } + } + RETURN(err); +} + +int ll_setattr(struct dentry *de, struct iattr *attr) +{ + int rc = inode_change_ok(de->d_inode, attr); + CDEBUG(D_VFSTRACE, "VFS Op:name=%s\n", de->d_name.name); + if (rc) + return rc; + + return ll_inode_setattr(de->d_inode, attr, 1); +} + + +void ll_update_inode(struct inode *inode, struct mds_body *body, + struct lov_stripe_md *lsm) +{ + struct ll_inode_info *lli = ll_i2info(inode); + + LASSERT ((lsm != NULL) == ((body->valid & OBD_MD_FLEASIZE) != 0)); + if (lsm != NULL) { + if (lli->lli_smd == NULL) + lli->lli_smd = lsm; + else + LASSERT(!memcmp(lli->lli_smd, lsm, sizeof(*lsm))); + } + + if (body->valid & OBD_MD_FLID) + inode->i_ino = body->ino; + if (body->valid & OBD_MD_FLATIME) + LTIME_S(inode->i_atime) = body->atime; + if (body->valid & OBD_MD_FLMTIME) + LTIME_S(inode->i_mtime) = body->mtime; + if (body->valid & OBD_MD_FLCTIME) + LTIME_S(inode->i_ctime) = body->ctime; + if (body->valid & OBD_MD_FLMODE) + inode->i_mode = (inode->i_mode & S_IFMT)|(body->mode & ~S_IFMT); + if (body->valid & OBD_MD_FLTYPE) + inode->i_mode = (inode->i_mode & ~S_IFMT)|(body->mode & S_IFMT); + if (body->valid & OBD_MD_FLUID) + inode->i_uid = body->uid; + if (body->valid & OBD_MD_FLGID) + inode->i_gid = body->gid; + if (body->valid & OBD_MD_FLFLAGS) + inode->i_flags = body->flags; + if (body->valid & OBD_MD_FLNLINK) + inode->i_nlink = body->nlink; + if (body->valid & OBD_MD_FLGENER) + inode->i_generation = body->generation; + if (body->valid & OBD_MD_FLRDEV) + inode->i_rdev = to_kdev_t(body->rdev); + if (body->valid & OBD_MD_FLSIZE) + inode->i_size = body->size; + if (body->valid & OBD_MD_FLBLOCKS) + inode->i_blocks = body->blocks; +} + +void ll_read_inode2(struct inode *inode, void *opaque) +{ + struct ll_read_inode2_cookie *lic = opaque; + struct mds_body *body = lic->lic_body; + struct ll_inode_info *lli = ll_i2info(inode); + ENTRY; + CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu\n", inode->i_ino); + + sema_init(&lli->lli_open_sem, 1); + spin_lock_init(&lli->lli_read_extent_lock); + INIT_LIST_HEAD(&lli->lli_read_extents); + ll_lldo_init(&lli->lli_dirty); + lli->lli_flags = 0; + + LASSERT(!lli->lli_smd); + + /* core attributes from the MDS first */ + ll_update_inode(inode, body, lic->lic_lsm); + + /* OIDEBUG(inode); */ + + if (S_ISREG(inode->i_mode)) { + inode->i_op = &ll_file_inode_operations; + inode->i_fop = &ll_file_operations; + inode->i_mapping->a_ops = &ll_aops; + EXIT; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &ll_dir_inode_operations; + inode->i_fop = &ll_dir_operations; + inode->i_mapping->a_ops = &ll_dir_aops; + EXIT; + } else if (S_ISLNK(inode->i_mode)) { + inode->i_op = &ll_fast_symlink_inode_operations; + EXIT; + } else { + inode->i_op = &ll_special_inode_operations; + init_special_inode(inode, inode->i_mode, + kdev_t_to_nr(inode->i_rdev)); + EXIT; + } +} -- 1.8.3.1