Whamcloud - gitweb
small changes and fixes to get the filter OBD working fully.
authorbraam <braam>
Mon, 17 Dec 2001 15:00:39 +0000 (15:00 +0000)
committerbraam <braam>
Mon, 17 Dec 2001 15:00:39 +0000 (15:00 +0000)
It seems to work well under ext2, XFS and Reiser at the moment.

lustre/demos/basesetup.sh
lustre/demos/config.sh
lustre/demos/obdfsclean.sh
lustre/demos/obdfssetup.sh
lustre/include/linux/obd_class.h
lustre/include/linux/obd_filter.h
lustre/obdfilter/filter.c
lustre/obdfs/dir.c
lustre/obdfs/namei.c
lustre/obdfs/rw.c
lustre/obdfs/super.c

index 1e34702..a232871 100755 (executable)
@@ -58,8 +58,8 @@ fi
 
 
 if [ "$BASEDEV" ]; then
-#     echo "No mke2fs!!"
-    mke2fs -r 0 -b 4096 $BASEDEV
+     echo "No mke2fs!!"
+    mke2fs -r 0 -b 4096 $BASEDEV
 else
     echo "\$BASEDEV not defined in demos/config.sh.  Please fix!"
     [ "$LOOPDEV" ] && losetup -d $LOOPDEV 
index 4d19a29..3fdd5ba 100644 (file)
@@ -25,8 +25,8 @@ OBDMAJ=186
 
 # If LOOPDEV is empty, then it is assumed that BASEDEV is a real block device
 # that doesn't mind being overwritten - don't use a partition with data on it!!
-LOOPDEV="/dev/loop0"
-BASEDEV="/dev/loop0"
+LOOPDEV=""
+BASEDEV="/dev/hda6"
 
 # The following are mount points for the filesystems during the test.
 MNTOBD="/mnt/obd"
index 58f5470..c0fa384 100755 (executable)
@@ -21,6 +21,9 @@ detach
 quit
 EOF
 
+plog rmmod xfs
+plog rmmod xfs_support
+plog rmmod pagebuf
 plog rmmod obdfilter
 plog rmmod obdext2
 plog rmmod obdclass
index 80acc66..de8ae27 100755 (executable)
@@ -23,10 +23,10 @@ fi
 plog log "ATTACHING device 0 SETUP $BASEDEV"
 $OBDDIR/utils/obdctl << EOF
 device 0
-attach obdfilter
-setup $BASEDEV reiserfs
-attach obdext2
-setup $BASEDEV
+attach obdfilter
+setup $BASEDEV reiserfs
+attach obdext2
+setup $BASEDEV
 quit
 EOF
 
index 70afae8..706996a 100644 (file)
@@ -184,14 +184,15 @@ struct obd_ioctl_data {
 #define OBD_MD_FLBLOCKS (0x00000020UL)
 #define OBD_MD_FLBLKSZ  (0x00000040UL)
 #define OBD_MD_FLMODE   (0x00000080UL)
-#define OBD_MD_FLUID    (0x00000100UL)
-#define OBD_MD_FLGID    (0x00000200UL)
-#define OBD_MD_FLFLAGS  (0x00000400UL)
-#define OBD_MD_FLOBDFLG (0x00000800UL)
-#define OBD_MD_FLNLINK  (0x00001000UL)
-#define OBD_MD_FLGENER  (0x00002000UL)
-#define OBD_MD_FLINLINE (0x00004000UL)
-#define OBD_MD_FLOBDMD  (0x00008000UL)
+#define OBD_MD_FLTYPE   (0x00000100UL)
+#define OBD_MD_FLUID    (0x00000200UL)
+#define OBD_MD_FLGID    (0x00000400UL)
+#define OBD_MD_FLFLAGS  (0x00000800UL)
+#define OBD_MD_FLOBDFLG (0x00001000UL)
+#define OBD_MD_FLNLINK  (0x00002000UL)
+#define OBD_MD_FLGENER  (0x00004000UL)
+#define OBD_MD_FLINLINE (0x00008000UL)
+#define OBD_MD_FLOBDMD  (0x00010000UL)
 #define OBD_MD_FLNOTOBD (~(OBD_MD_FLOBDMD | OBD_MD_FLOBDFLG | OBD_MD_FLBLOCKS))
 
 /*
@@ -352,7 +353,7 @@ static __inline__ void obdo_free(struct obdo *oa)
 
 
 static __inline__ struct obdo *obdo_fromid(struct obd_conn *conn, obd_id id,
-                                           obd_flag valid)
+                                          obd_mode mode, obd_flag valid)
 {
         struct obdo *oa;
         int err;
@@ -365,6 +366,7 @@ static __inline__ struct obdo *obdo_fromid(struct obd_conn *conn, obd_id id,
         }
 
         oa->o_id = id;
+       oa->o_mode = mode;
         oa->o_valid = valid;
         if ((err = OBP(conn->oc_dev, getattr)(conn, oa))) {
                 obdo_free(oa);
@@ -416,7 +418,8 @@ static inline void obdo_from_iattr(struct obdo *oa, struct iattr *attr)
 static inline void iattr_from_obdo(struct iattr *attr, struct obdo *oa)
 {
         unsigned int ia_valid = oa->o_valid;
-
+       
+       memset(attr, 0, sizeof(*attr));
         if (ia_valid & OBD_MD_FLATIME) {
                 attr->ia_atime = oa->o_atime;
                 attr->ia_valid |= ATTR_ATIME;
index bdccdfa..0530fc6 100644 (file)
@@ -23,6 +23,7 @@ struct filter_obd {
         struct super_block * fo_sb;
        struct vfsmount *fo_vfsmnt;
        struct run_ctxt  fo_ctxt;
+       spinlock_t fo_lock;
        __u64 fo_lastino;
        struct file_operations *fo_fop; 
        struct inode_operations *fo_iop;
index e97ab5d..bd6d9a6 100644 (file)
 extern struct obd_device obd_dev[MAX_OBD_DEVICES];
 long filter_memory;
 
+#define FILTER_ROOTINO 2
+
+#define S_SHIFT 12
+
+static char * obd_type_by_mode[S_IFMT >> S_SHIFT] = {
+       [0]                     "",
+       [S_IFREG >> S_SHIFT]    "R", 
+       [S_IFDIR >> S_SHIFT]    "D",
+       [S_IFCHR >> S_SHIFT]    "C",
+       [S_IFBLK >> S_SHIFT]    "B", 
+       [S_IFIFO >> S_SHIFT]    "F", 
+       [S_IFSOCK >> S_SHIFT]   "S",
+       [S_IFLNK >> S_SHIFT]    "L"
+};
+
+static void filter_id(char *buf, obd_id id, obd_mode mode)
+{
+       sprintf(buf, "O/%s/%Ld", 
+               obd_type_by_mode[(mode & S_IFMT) >> S_SHIFT],
+               id);
+}
+
 void push_ctxt(struct run_ctxt *save, struct run_ctxt *new)
 { 
        save->fs = get_fs();
@@ -52,6 +74,7 @@ static void filter_prep(struct obd_device *obddev)
        struct inode *inode;
        long rc;
        int fd;
+       char rootid[128];
        struct stat64 buf;
        __u64 lastino = 2;
 
@@ -59,7 +82,22 @@ static void filter_prep(struct obd_device *obddev)
        rc = sys_mkdir("O", 0700);
        rc = sys_mkdir("P", 0700);
        rc = sys_mkdir("D", 0700);
-       rc = sys_mkdir("O/2", 0755);
+       rc = sys_mkdir("O/R", 0700);  /* regular */
+       rc = sys_mkdir("O/D", 0700);  /* directory */
+       rc = sys_mkdir("O/L", 0700);  /* symbolic links */
+       rc = sys_mkdir("O/C", 0700);  /* character devices */
+       rc = sys_mkdir("O/B", 0700);  /* block devices */
+       rc = sys_mkdir("O/F", 0700);  /* fifo's */
+       rc = sys_mkdir("O/S", 0700);  /* sockets */
+       
+       filter_id(rootid, FILTER_ROOTINO, S_IFDIR);
+       file = filp_open(rootid, O_RDWR | O_CREAT, 00755);
+       if (IS_ERR(file)) {
+               printk("OBD filter: cannot make root directory"); 
+               goto out;
+       }
+       filp_close(file, 0);
+       rc = sys_mkdir(rootid, 0755);
        if ( (fd = sys_open("D/status", O_RDWR | O_CREAT, 0700)) == -1 ) {
                printk("OBD filter: cannot create status file\n");
                goto out;
@@ -84,7 +122,7 @@ static void filter_prep(struct obd_device *obddev)
        obddev->u.filter.fo_lastino = lastino;
 
        /* this is also the moment to steal operations */
-       file = filp_open("D/status", O_RDONLY, 0);
+       file = filp_open("D/status", O_RDONLY | O_LARGEFILE, 0);
        if (!file || IS_ERR(file)) { 
                EXIT;
                goto out_close;
@@ -170,12 +208,23 @@ static int filter_setup(struct obd_device *obddev, obd_count len,
        obddev->u.filter.fo_ctxt.fs = KERNEL_DS;
 
        filter_prep(obddev);
-       
+       spin_lock_init(&obddev->u.filter.fo_lock);
+
         MOD_INC_USE_COUNT;
         EXIT; 
         return 0;
 } 
 
+static __u64 filter_next_id(struct obd_device *obddev) 
+{
+       __u64 id;
+       spin_lock(&obddev->u.filter.fo_lock);
+       obddev->u.filter.fo_lastino++;
+       id =    obddev->u.filter.fo_lastino;
+       spin_unlock(&obddev->u.filter.fo_lock);
+       return id;
+}
+
 static int filter_cleanup(struct obd_device * obddev)
 {
         struct super_block *sb;
@@ -218,7 +267,7 @@ static struct file *filter_obj_open(struct obd_device *obddev,
 {
        struct file *file;
        int error = 0;
-       char id[16];
+       char id[24];
        struct run_ctxt saved;
        struct super_block *sb;
 
@@ -235,9 +284,13 @@ static struct file *filter_obj_open(struct obd_device *obddev,
                 return NULL;
         }
 
-       sprintf(id, "O/%Ld", oa->o_id);
+       if ( ! (oa->o_mode & S_IFMT) ) { 
+               printk("OBD filter_obj_open, no type (%Ld), mode %o!\n", 
+                      oa->o_id, oa->o_mode);
+       }
+       filter_id(id, oa->o_id, oa->o_mode); 
        push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
-       file = filp_open(id , O_RDONLY, 0);
+       file = filp_open(id , O_RDONLY | O_LARGEFILE, 0);
        pop_ctxt(&saved);
 
        if (IS_ERR(file)) { 
@@ -245,18 +298,11 @@ static struct file *filter_obj_open(struct obd_device *obddev,
                file = NULL;
        }
        CDEBUG(D_INODE, "opening obdo %s\n", id);
-               
-       if ( file ) {
-               file->f_op = obddev->u.filter.fo_fop;
-               file->f_dentry->d_inode->i_op = obddev->u.filter.fo_iop;
-               file->f_dentry->d_inode->i_mapping->a_ops = obddev->u.filter.fo_aops;
-       } else { 
-               printk("Error opening object %s,  error %d\n", id, error);
-       }
+
        return file;
 }
 
-static struct inode *inode_from_obdo(struct obd_device *obddev, 
+static struct inode *filter_inode_from_obdo(struct obd_device *obddev, 
                                     struct obdo *oa)
 {
        struct file *file;
@@ -264,7 +310,7 @@ static struct inode *inode_from_obdo(struct obd_device *obddev,
 
        file = filter_obj_open(obddev, oa);
        if ( !file ) { 
-               printk("inode_from_obdo failed\n"); 
+               printk("filter_inode_from_obdo failed\n"); 
                return NULL;
        }
 
@@ -275,11 +321,14 @@ static struct inode *inode_from_obdo(struct obd_device *obddev,
 
 static inline void filter_from_inode(struct obdo *oa, struct inode *inode)
 {
+       int type = oa->o_mode & S_IFMT;
         ENTRY;
 
         CDEBUG(D_INFO, "src inode %ld, dst obdo %ld valid 0x%08x\n",
                inode->i_ino, (long)oa->o_id, oa->o_valid);
         obdo_from_inode(oa, inode);
+       oa->o_mode &= ~S_IFMT;
+       oa->o_mode |= type;
 
         if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
                obd_rdev rdev = kdev_t_to_nr(inode->i_rdev);
@@ -322,7 +371,7 @@ static int filter_getattr(struct obd_conn *conn, struct obdo *oa)
                 return -EINVAL;
         }
 
-       if ( !(inode = inode_from_obdo(conn->oc_dev, oa)) ) { 
+       if ( !(inode = filter_inode_from_obdo(conn->oc_dev, oa)) ) { 
                EXIT;
                return -ENOENT;
        }
@@ -347,13 +396,15 @@ static int filter_setattr(struct obd_conn *conn, struct obdo *oa)
                 return -EINVAL;
         }
 
-       inode = inode_from_obdo(conn->oc_dev, oa); 
+       inode = filter_inode_from_obdo(conn->oc_dev, oa); 
        if ( !inode ) { 
                EXIT;
                return -ENOENT;
        }
 
        iattr_from_obdo(&iattr, oa);
+       iattr.ia_mode &= ~S_IFMT;
+       iattr.ia_mode |= S_IFREG;
        de.d_inode = inode;
        if ( inode->i_op->setattr ) {
                rc = inode->i_op->setattr(&de, &iattr);
@@ -370,9 +421,10 @@ static int filter_create (struct obd_conn* conn, struct obdo *oa)
 {
        char name[64];
        struct run_ctxt saved;
+       struct file *file;
+       int mode;
        struct obd_device *obddev = conn->oc_dev;
        struct iattr;
-       int rc;
        ENTRY;
 
         if (!gen_client(conn)) {
@@ -381,23 +433,24 @@ static int filter_create (struct obd_conn* conn, struct obdo *oa)
         }
        CDEBUG(D_IOCTL, "\n");
 
-       conn->oc_dev->u.filter.fo_lastino++;
-       oa->o_id = conn->oc_dev->u.filter.fo_lastino;
-       sprintf(name, "O/%Ld", oa->o_id);
-       push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
-       CDEBUG(D_IOCTL, "\n");
-       if (sys_mknod(name, 0100644, 0)) { 
-               printk("Error mknod obj %s\n", name);
+       oa->o_id = filter_next_id(conn->oc_dev);
+       if ( !(oa->o_mode && S_IFMT) ) { 
+               printk("filter obd: no type!\n");
                return -ENOENT;
        }
-       pop_ctxt(&saved);
 
-       CDEBUG(D_IOCTL, "\n");
-       rc = filter_setattr(conn, oa); 
-       if ( rc ) { 
-               EXIT;
-               return -EINVAL;
+       filter_id(name, oa->o_id, oa->o_mode);
+       push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
+       mode = oa->o_mode;
+       mode &= ~S_IFMT;
+       mode |= S_IFREG; 
+       file = filp_open(name, O_RDONLY | O_CREAT, mode);
+       pop_ctxt(&saved);
+       if (IS_ERR(file)) { 
+               printk("Error mknod obj %s, err %ld\n", name, PTR_ERR(file));
+               return -ENOENT;
        }
+       filp_close(file, 0);
        CDEBUG(D_IOCTL, "\n");
        
         /* Set flags for fields we have set in ext2_new_inode */
@@ -422,7 +475,7 @@ static int filter_destroy(struct obd_conn *conn, struct obdo *oa)
         }
 
         obddev = conn->oc_dev;
-       inode = inode_from_obdo(obddev, oa);
+       inode = filter_inode_from_obdo(obddev, oa);
 
        if (!inode) { 
                EXIT;
@@ -433,10 +486,11 @@ static int filter_destroy(struct obd_conn *conn, struct obdo *oa)
        inode->i_mode = 010000;
        iput(inode);
 
-       sprintf(id, "O/%Ld", oa->o_id);
+       filter_id(id, oa->o_id, oa->o_mode);
        push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
        if (sys_unlink(id)) { 
                EXIT;
+               pop_ctxt(&saved);
                return -EPERM;
        }
        pop_ctxt(&saved);
@@ -445,6 +499,18 @@ static int filter_destroy(struct obd_conn *conn, struct obdo *oa)
         return 0;
 }
 
+static int filter_truncate(struct obd_conn *conn, struct obdo *oa, obd_size count,
+                         obd_off offset)
+{
+       int error;
+
+       error = filter_setattr(conn, oa);
+        oa->o_valid = OBD_MD_FLBLOCKS | OBD_MD_FLCTIME | OBD_MD_FLMTIME;
+
+        EXIT;
+        return error;
+}
+
 /* buffer must lie in user memory here */
 static int filter_read(struct obd_conn *conn, struct obdo *oa, char *buf,
                         obd_size *count, obd_off offset)
@@ -661,8 +727,7 @@ static int  filter_get_info(struct obd_conn *conn, obd_count keylen,
         if ( keylen == strlen("root_ino") &&
              memcmp(key, "root_ino", keylen) == 0 ){
                 *vallen = sizeof(int);
-                *val = (void *)(int)
-                       obddev->u.filter.fo_sb->s_root->d_inode->i_ino;
+                *val = (void *)(int) FILTER_ROOTINO;
                EXIT;
                 return 0;
         }
@@ -687,10 +752,9 @@ struct obd_ops filter_obd_ops = {
         o_read:        filter_read,
         o_write:       filter_write,
        o_brw:         filter_pgcache_brw,
+        o_punch:       filter_truncate,
 #if 0
         o_preallocate: ext2obd_preallocate_inodes,
-        o_setattr:     ext2obd_setattr,
-        o_punch:       ext2obd_punch,
         o_migrate:     ext2obd_migrate,
         o_copy:        gen_copy_data,
         o_iterate:     ext2obd_iterate
index 4ac7bdf..05edd4c 100644 (file)
@@ -229,6 +229,17 @@ static unsigned char ext2_filetype_table[EXT2_FT_MAX] = {
        [EXT2_FT_SYMLINK]       DT_LNK,
 };
 
+static unsigned int obdfs_dt2fmt[DT_WHT + 1] = {
+       [EXT2_FT_UNKNOWN]       0, 
+       [EXT2_FT_REG_FILE]      S_IFREG,
+       [EXT2_FT_DIR]           S_IFDIR,
+       [EXT2_FT_CHRDEV]        S_IFCHR,
+       [EXT2_FT_BLKDEV]        S_IFBLK, 
+       [EXT2_FT_FIFO]          S_IFIFO,
+       [EXT2_FT_SOCK]          S_IFSOCK,
+       [EXT2_FT_SYMLINK]       S_IFLNK
+};
+       
 #define S_SHIFT 12
 static unsigned char ext2_type_by_mode[S_IFMT >> S_SHIFT] = {
        [S_IFREG >> S_SHIFT]    EXT2_FT_REG_FILE,
@@ -242,14 +253,8 @@ static unsigned char ext2_type_by_mode[S_IFMT >> S_SHIFT] = {
 
 static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode)
 {
-       /* XXX
        mode_t mode = inode->i_mode;
-       if (EXT2_HAS_INCOMPAT_FEATURE(inode->i_sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
-               de->file_type = ext2_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
-       else
-               de->file_type = 0;
-       */
-       de->file_type = 0;
+       de->file_type = ext2_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
 }
 
 int
@@ -268,8 +273,7 @@ new_obdfs_readdir (struct file * filp, void * dirent, filldir_t filldir)
        if (pos > inode->i_size - EXT2_DIR_REC_LEN(1))
                goto done;
 
-       //if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
-       //types = ext2_filetype_table;
+       types = ext2_filetype_table;
 
        for ( ; n < npages; n++, offset = 0) {
                char *kaddr, *limit;
@@ -376,7 +380,7 @@ struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p)
        return de;
 }
 
-ino_t ext2_inode_by_name(struct inode * dir, struct dentry *dentry)
+ino_t obdfs_inode_by_name(struct inode * dir, struct dentry *dentry, int *type)
 {
        ino_t res = 0;
        struct ext2_dir_entry_2 * de;
@@ -385,6 +389,7 @@ ino_t ext2_inode_by_name(struct inode * dir, struct dentry *dentry)
        de = ext2_find_entry (dir, dentry, &page);
        if (de) {
                res = le32_to_cpu(de->inode);
+               *type = obdfs_dt2fmt[de->file_type];
                kunmap(page);
                page_cache_release(page);
        }
@@ -476,6 +481,7 @@ got_it:
        memcpy (de->name, name, namelen);
        de->inode = cpu_to_le32(inode->i_ino);
        ext2_set_de_type (de, inode);
+       CDEBUG(D_INODE, "type set to %o\n", de->file_type);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
        err = ext2_commit_chunk(page, from, to);
 
index ff0f3e1..f0e55c6 100644 (file)
@@ -40,7 +40,7 @@ extern int obdfs_setattr(struct dentry *de, struct iattr *attr);
 
 /* from dir.c */
 extern int ext2_add_link (struct dentry *dentry, struct inode *inode);
-extern ino_t ext2_inode_by_name(struct inode * dir, struct dentry *dentry);
+ino_t obdfs_inode_by_name(struct inode * dir, struct dentry *dentry, int *typ);
 int ext2_make_empty(struct inode *inode, struct inode *parent);
 struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
                   struct dentry *dentry, struct page ** res_page);
@@ -85,17 +85,19 @@ static struct dentry *obdfs_lookup(struct inode * dir, struct dentry *dentry)
 {
         struct obdo *oa;
        struct inode * inode = NULL;
+       int type;
        ino_t ino;
        
         ENTRY;
        if (dentry->d_name.len > EXT2_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
 
-       ino = ext2_inode_by_name(dir, dentry);
+       ino = obdfs_inode_by_name(dir, dentry, &type);
        if (!ino)
                goto negative;
 
-        oa = obdo_fromid(IID(dir), ino, OBD_MD_FLNOTOBD | OBD_MD_FLBLOCKS);
+        oa = obdo_fromid(IID(dir), ino, type, 
+                        OBD_MD_FLNOTOBD | OBD_MD_FLBLOCKS);
         if ( IS_ERR(oa) ) {
                 printk(__FUNCTION__ ": obdo_fromid failed\n");
                 EXIT;
@@ -161,7 +163,7 @@ static struct inode *obdfs_new_inode(struct inode *dir, int mode)
                 EXIT;
                 return ERR_PTR(err);
         }
-       CDEBUG(D_INODE, "\n");
+       CDEBUG(D_INODE, "obdo mode %o\n", oa->o_mode);
 
         inode = iget4(dir->i_sb, (ino_t)oa->o_id, NULL, oa);
        CDEBUG(D_INODE, "\n");
index 5fcd525..501a2df 100644 (file)
@@ -692,7 +692,7 @@ void obdfs_truncate(struct inode *inode)
                 obdo.o_valid = OBD_MD_FLNOTOBD;
                 obdfs_from_inode(&obdo, inode);
 
-                err = IOPS(inode, punch)(IID(inode), &obdo, obdo.o_size, 0);
+                err = IOPS(inode, punch)(IID(inode), &obdo, 0, obdo.o_size);
         } else {
                 oa->o_valid = OBD_MD_FLNOTOBD;
                 obdfs_from_inode(oa, inode);
index 9c9ae14..72926c0 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * OBDFS Super operations
  *
@@ -238,9 +239,9 @@ static struct super_block * obdfs_read_super(struct super_block *sb,
 
         /* make root inode */
         CDEBUG(D_INFO, "\n"); 
-        oa = obdo_fromid(&sbi->osi_conn, root_ino,
+        oa = obdo_fromid(&sbi->osi_conn, root_ino, S_IFDIR,
                          OBD_MD_FLNOTOBD | OBD_MD_FLBLOCKS);
-        CDEBUG(D_INFO, "\n"); 
+        CDEBUG(D_INFO, "mode %o\n", oa->o_mode); 
         if ( IS_ERR(oa) ) {
                 printk(__FUNCTION__ ": obdo_fromid failed\n");
                iput(root); 
@@ -331,6 +332,7 @@ void obdfs_do_change_inode(struct inode *inode, int valid)
 
         oa->o_valid = OBD_MD_FLNOTOBD & (valid | OBD_MD_FLID);
         obdfs_from_inode(oa, inode);
+       oa->o_mode = inode->i_mode;
         err = IOPS(inode, setattr)(IID(inode), oa);
 
         if ( err )
@@ -459,6 +461,7 @@ int obdfs_setattr(struct dentry *de, struct iattr *attr)
 
        obdfs_attr2inode(inode, attr);
         oa->o_id = inode->i_ino;
+       oa->o_mode = inode->i_mode;
         obdo_from_iattr(oa, attr);
         err = IOPS(inode, setattr)(IID(inode), oa);