From a146e9a0c89363a8493bb978d4cbabb9cfd6524f Mon Sep 17 00:00:00 2001 From: braam Date: Mon, 17 Dec 2001 15:00:39 +0000 Subject: [PATCH] small changes and fixes to get the filter OBD working fully. It seems to work well under ext2, XFS and Reiser at the moment. --- lustre/demos/basesetup.sh | 4 +- lustre/demos/config.sh | 4 +- lustre/demos/obdfsclean.sh | 3 + lustre/demos/obdfssetup.sh | 8 +-- lustre/include/linux/obd_class.h | 23 ++++--- lustre/include/linux/obd_filter.h | 1 + lustre/obdfilter/filter.c | 140 +++++++++++++++++++++++++++----------- lustre/obdfs/dir.c | 26 ++++--- lustre/obdfs/namei.c | 10 +-- lustre/obdfs/rw.c | 2 +- lustre/obdfs/super.c | 7 +- 11 files changed, 155 insertions(+), 73 deletions(-) diff --git a/lustre/demos/basesetup.sh b/lustre/demos/basesetup.sh index 1e34702..a232871 100755 --- a/lustre/demos/basesetup.sh +++ b/lustre/demos/basesetup.sh @@ -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 diff --git a/lustre/demos/config.sh b/lustre/demos/config.sh index 4d19a29..3fdd5ba 100644 --- a/lustre/demos/config.sh +++ b/lustre/demos/config.sh @@ -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" diff --git a/lustre/demos/obdfsclean.sh b/lustre/demos/obdfsclean.sh index 58f5470..c0fa384 100755 --- a/lustre/demos/obdfsclean.sh +++ b/lustre/demos/obdfsclean.sh @@ -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 diff --git a/lustre/demos/obdfssetup.sh b/lustre/demos/obdfssetup.sh index 80acc66..de8ae27 100755 --- a/lustre/demos/obdfssetup.sh +++ b/lustre/demos/obdfssetup.sh @@ -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 diff --git a/lustre/include/linux/obd_class.h b/lustre/include/linux/obd_class.h index 70afae8..706996a 100644 --- a/lustre/include/linux/obd_class.h +++ b/lustre/include/linux/obd_class.h @@ -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; diff --git a/lustre/include/linux/obd_filter.h b/lustre/include/linux/obd_filter.h index bdccdfa..0530fc6 100644 --- a/lustre/include/linux/obd_filter.h +++ b/lustre/include/linux/obd_filter.h @@ -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; diff --git a/lustre/obdfilter/filter.c b/lustre/obdfilter/filter.c index e97ab5d..bd6d9a6 100644 --- a/lustre/obdfilter/filter.c +++ b/lustre/obdfilter/filter.c @@ -26,6 +26,28 @@ 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 diff --git a/lustre/obdfs/dir.c b/lustre/obdfs/dir.c index 4ac7bdf..05edd4c 100644 --- a/lustre/obdfs/dir.c +++ b/lustre/obdfs/dir.c @@ -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); diff --git a/lustre/obdfs/namei.c b/lustre/obdfs/namei.c index ff0f3e1..f0e55c6 100644 --- a/lustre/obdfs/namei.c +++ b/lustre/obdfs/namei.c @@ -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"); diff --git a/lustre/obdfs/rw.c b/lustre/obdfs/rw.c index 5fcd525..501a2df 100644 --- a/lustre/obdfs/rw.c +++ b/lustre/obdfs/rw.c @@ -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); diff --git a/lustre/obdfs/super.c b/lustre/obdfs/super.c index 9c9ae14..72926c0 100644 --- a/lustre/obdfs/super.c +++ b/lustre/obdfs/super.c @@ -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); -- 1.8.3.1