X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Flvfs%2Ffsfilt_ext3.c;h=271f19429504df3c1dc26fb6ca2394517470b956;hp=fa2e51008793109e3da78f60ff9303a2ff40b3b4;hb=1e9326917af52f3d01920411465476154b2807d0;hpb=ff359e141b6cfc1a9c2c3f3765fabc136e3f9040 diff --git a/lustre/lvfs/fsfilt_ext3.c b/lustre/lvfs/fsfilt_ext3.c index fa2e510..271f194 100644 --- a/lustre/lvfs/fsfilt_ext3.c +++ b/lustre/lvfs/fsfilt_ext3.c @@ -26,8 +26,11 @@ * GPL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * + * Copyright (c) 2011 Whamcloud, Inc. + * */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -46,6 +49,9 @@ #include #include #include +#ifdef HAVE_LINUX_EXPORTFS_H +#include +#endif #ifdef HAVE_EXT4_LDISKFS #include #include @@ -57,14 +63,23 @@ #include #include #include -#ifdef HAVE_QUOTAIO_V1_H -# include +#ifdef HAVE_QUOTAIO_H # include -#else -# include +#elif defined(HAVE_FS_QUOTA_QUOTAIO_H) +# include +# include +# define V2_DQTREEOFF QT_TREEOFF +#elif defined(HAVE_FS_QUOTAIO_V1_H) # include # include # define V2_DQTREEOFF QT_TREEOFF +# define V2_INITQVERSIONS_R1 V2_INITQVERSIONS +#endif + +#ifdef QFMT_VFS_V1 +#define QFMT_LUSTRE QFMT_VFS_V1 +#else +#define QFMT_LUSTRE QFMT_VFS_V0 #endif #if defined(HAVE_EXT3_XATTR_H) @@ -82,13 +97,11 @@ extern int ext3_xattr_set_handle(handle_t *, struct inode *, int, const char *, #include #include -#ifdef EXT3_MULTIBLOCK_ALLOCATOR #ifdef HAVE_EXT4_LDISKFS #include #else #include #endif -#endif #include "lustre_quota_fmt.h" @@ -107,6 +120,20 @@ extern int ext3_xattr_set_handle(handle_t *, struct inode *, int, const char *, #define FSFILT_SINGLEDATA_TRANS_BLOCKS(sb) EXT3_SINGLEDATA_TRANS_BLOCKS #endif +#ifdef EXT_INSERT_EXTENT_WITH_5ARGS +#define fsfilt_ext3_ext_insert_extent(handle, inode, path, newext, flag) \ + ext3_ext_insert_extent(handle, inode, path, newext, flag) +#else +#define fsfilt_ext3_ext_insert_extent(handle, inode, path, newext, flag) \ + ext3_ext_insert_extent(handle, inode, path, newext) +#endif + +#ifdef EXT3_DISCARD_PREALLOCATIONS +#define ext3_mb_discard_inode_preallocations(inode) \ + ext3_discard_preallocations(inode) +#endif + + static cfs_mem_cache_t *fcb_cache; struct fsfilt_cb_data { @@ -189,20 +216,12 @@ static char *fsfilt_ext3_uuid(struct super_block *sb) static __u64 get_i_version(struct inode *inode) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) && defined(HAVE_EXT4_LDISKFS) - return inode->i_version; -#else return EXT3_I(inode)->i_fs_version; -#endif } static void set_i_version(struct inode *inode, __u64 new_version) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) && defined(HAVE_EXT4_LDISKFS) - inode->i_version = new_version; -#else (EXT3_I(inode))->i_fs_version = new_version; -#endif } /* @@ -280,7 +299,7 @@ static void *fsfilt_ext3_start(struct inode *inode, int op, void *desc_private, cpu_to_le32(EXT3_EXTENTS_FL | EXT3_INDEX_FL))) { CWARN("extent-mapped directory found with " "ext3-based ldiskfs - contact " - "http://bugzilla.lustre.org/\n"); + "http://bugs.whamcloud.com/\n"); warned = 1; } } @@ -584,7 +603,7 @@ static int fsfilt_ext3_setattr(struct dentry *dentry, void *handle, if (iattr->ia_valid & ATTR_MODE) { inode->i_mode = iattr->ia_mode; - if (!in_group_p(inode->i_gid) && + if (!cfs_curproc_is_in_groups(inode->i_gid) && !cfs_capable(CFS_CAP_FSETID)) inode->i_mode &= ~S_ISGID; } @@ -622,9 +641,21 @@ static int fsfilt_ext3_iocontrol(struct inode *inode, struct file *file, ENTRY; /* FIXME: Can't do this because of nested transaction deadlock */ - if (cmd == EXT3_IOC_SETFLAGS && (*(int *)arg) & EXT3_JOURNAL_DATA_FL) { - CERROR("can't set data journal flag on file\n"); - RETURN(-EPERM); + if (cmd == EXT3_IOC_SETFLAGS) { + /* We can't enable data journaling on OST objects, because + * this forces the transaction to be closed in order to + * flush the journal, but the caller will already have a + * compound transaction open to update the last_rcvd file, + * and this thread would deadlock trying to set the flag. */ + if ((*(int *)arg) & EXT3_JOURNAL_DATA_FL) { + CERROR("can't set data journal flag on file\n"); + RETURN(-EPERM); + } + /* Because the MDS does not see the EXTENTS_FL set on the + * OST objects, mask this flag into all set flags. It is + * not legal to clear this flag in any case, so we are not + * changing the functionality by doing this. b=22911 */ + *(int *)arg |= EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL; } #ifdef HAVE_EXT4_LDISKFS @@ -777,13 +808,6 @@ static int fsfilt_ext3_add_journal_cb(struct obd_device *obd, __u64 last_rcvd, return 0; } -/* - * We need to hack the return value for the free inode counts because - * the current EA code requires one filesystem block per inode with EAs, - * so it is possible to run out of blocks before we run out of inodes. - * - * This can be removed when the ext3 EA code is fixed. - */ static int fsfilt_ext3_statfs(struct super_block *sb, struct obd_statfs *osfs) { struct kstatfs sfs; @@ -791,11 +815,6 @@ static int fsfilt_ext3_statfs(struct super_block *sb, struct obd_statfs *osfs) memset(&sfs, 0, sizeof(sfs)); rc = ll_do_statfs(sb, &sfs); - if (!rc && sfs.f_bfree < sfs.f_ffree) { - sfs.f_files = (sfs.f_files - sfs.f_ffree) + sfs.f_bfree; - sfs.f_ffree = sfs.f_bfree; - } - statfs_pack(osfs, &sfs); return rc; } @@ -805,26 +824,26 @@ static int fsfilt_ext3_sync(struct super_block *sb) return ext3_force_commit(sb); } -#if defined(EXT3_MULTIBLOCK_ALLOCATOR) && (!defined(EXT3_EXT_CACHE_NO) || defined(EXT_CACHE_MARK)) -#warning "kernel code has old extents/mballoc patch, disabling" -#undef EXT3_MULTIBLOCK_ALLOCATOR -#endif #ifndef EXT3_EXTENTS_FL #define EXT3_EXTENTS_FL 0x00080000 /* Inode uses extents */ #endif -#ifdef EXT3_MULTIBLOCK_ALLOCATOR #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)) -#define fsfilt_up_truncate_sem(inode) up(&EXT3_I(inode)->truncate_sem); -#define fsfilt_down_truncate_sem(inode) down(&EXT3_I(inode)->truncate_sem); +# define fsfilt_up_truncate_sem(inode) up(&LDISKFS_I(inode)->truncate_sem); +# define fsfilt_down_truncate_sem(inode) down(&LDISKFS_I(inode)->truncate_sem); #else -#ifdef HAVE_EXT4_LDISKFS -#define fsfilt_up_truncate_sem(inode) up_write((&EXT4_I(inode)->i_data_sem)); -#define fsfilt_down_truncate_sem(inode) down_write((&EXT4_I(inode)->i_data_sem)); -#else -#define fsfilt_up_truncate_sem(inode) mutex_unlock(&EXT3_I(inode)->truncate_mutex); -#define fsfilt_down_truncate_sem(inode) mutex_lock(&EXT3_I(inode)->truncate_mutex); -#endif +# ifdef HAVE_EXT4_LDISKFS +# ifdef WALK_SPACE_HAS_DATA_SEM /* We only use it in fsfilt_map_nblocks() for now */ +# define fsfilt_up_truncate_sem(inode) do{ }while(0) +# define fsfilt_down_truncate_sem(inode) do{ }while(0) +# else +# define fsfilt_up_truncate_sem(inode) up_write((&EXT4_I(inode)->i_data_sem)) +# define fsfilt_down_truncate_sem(inode) down_write((&EXT4_I(inode)->i_data_sem)) +# endif +# else +# define fsfilt_up_truncate_sem(inode) mutex_unlock(&EXT3_I(inode)->truncate_mutex) +# define fsfilt_down_truncate_sem(inode) mutex_lock(&EXT3_I(inode)->truncate_mutex) +# endif #endif #ifndef EXT_ASSERT @@ -850,6 +869,14 @@ static int fsfilt_ext3_sync(struct super_block *sb) ext3_ext_walk_space(tree, block, num, cb); #endif +#ifdef EXT_INSERT_EXTENT_WITH_5ARGS +#define fsfilt_ext3_ext_insert_extent(handle, inode, path, newext, flag) \ + ext3_ext_insert_extent(handle, inode, path, newext, flag) +#else +#define fsfilt_ext3_ext_insert_extent(handle, inode, path, newext, flag) \ + ext3_ext_insert_extent(handle, inode, path, newext) +#endif + #include struct bpointers { @@ -964,13 +991,17 @@ static int ext3_ext_new_extent_cb(struct ext3_ext_base *base, #endif struct inode *inode = ext3_ext_base2inode(base); struct ext3_extent nex; +#if defined(HAVE_EXT4_LDISKFS) && defined(WALK_SPACE_HAS_DATA_SEM) + struct ext4_ext_path *tmppath = NULL; + struct ext4_extent *tmpex; +#endif unsigned long pblock; unsigned long tgen; - int err, i; + int err, i, depth; unsigned long count; handle_t *handle; - i = EXT_DEPTH(base); + i = depth = EXT_DEPTH(base); EXT_ASSERT(i == path->p_depth); EXT_ASSERT(path[i].p_hdr); @@ -1015,6 +1046,29 @@ static int ext3_ext_new_extent_cb(struct ext3_ext_base *base, return EXT_REPEAT; } +#if defined(HAVE_EXT4_LDISKFS) && defined(WALK_SPACE_HAS_DATA_SEM) + /* In 2.6.32 kernel, ext4_ext_walk_space()'s callback func is not + * protected by i_data_sem, we need revalidate extent to be created */ + down_write((&EXT4_I(inode)->i_data_sem)); + + /* validate extent, make sure the extent tree does not changed */ + tmppath = ext4_ext_find_extent(inode, cex->ec_block, NULL); + if (IS_ERR(tmppath)) { + up_write(&EXT4_I(inode)->i_data_sem); + ext3_journal_stop(handle); + return PTR_ERR(tmppath); + } + tmpex = tmppath[depth].p_ext; + if (tmpex != ex) { + /* cex is invalid, try again */ + ext4_ext_drop_refs(tmppath); + kfree(tmppath); + up_write(&EXT4_I(inode)->i_data_sem); + ext3_journal_stop(handle); + return EXT_REPEAT; + } +#endif + count = cex->ec_len; pblock = new_blocks(handle, base, path, cex->ec_block, &count, &err); if (!pblock) @@ -1025,7 +1079,7 @@ static int ext3_ext_new_extent_cb(struct ext3_ext_base *base, nex.ee_block = cpu_to_le32(cex->ec_block); ext3_ext_store_pblock(&nex, pblock); nex.ee_len = cpu_to_le16(count); - err = ext3_ext_insert_extent(handle, base, path, &nex); + err = fsfilt_ext3_ext_insert_extent(handle, base, path, &nex, 0); if (err) { /* free data blocks we just allocated */ /* not a good idea to call discard here directly, @@ -1049,6 +1103,11 @@ static int ext3_ext_new_extent_cb(struct ext3_ext_base *base, BUG_ON(le32_to_cpu(nex.ee_block) != cex->ec_block); out: +#if defined(HAVE_EXT4_LDISKFS) && defined(WALK_SPACE_HAS_DATA_SEM) + ext4_ext_drop_refs(tmppath); + kfree(tmppath); + up_write((&EXT4_I(inode)->i_data_sem)); +#endif ext3_journal_stop(handle); map: if (err >= 0) { @@ -1172,7 +1231,6 @@ int fsfilt_ext3_map_ext_inode_pages(struct inode *inode, struct page **page, cleanup: return rc; } -#endif /* EXT3_MULTIBLOCK_ALLOCATOR */ extern int ext3_map_inode_page(struct inode *inode, struct page *page, unsigned long *blocks, int *created, int create); @@ -1201,22 +1259,21 @@ int fsfilt_ext3_map_bm_inode_pages(struct inode *inode, struct page **page, int fsfilt_ext3_map_inode_pages(struct inode *inode, struct page **page, int pages, unsigned long *blocks, int *created, int create, - struct semaphore *optional_sem) + cfs_semaphore_t *optional_sem) { int rc; -#ifdef EXT3_MULTIBLOCK_ALLOCATOR + if (EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL) { rc = fsfilt_ext3_map_ext_inode_pages(inode, page, pages, blocks, created, create); return rc; } -#endif if (optional_sem != NULL) - down(optional_sem); + cfs_down(optional_sem); rc = fsfilt_ext3_map_bm_inode_pages(inode, page, pages, blocks, created, create); if (optional_sem != NULL) - up(optional_sem); + cfs_up(optional_sem); return rc; } @@ -1228,10 +1285,10 @@ int fsfilt_ext3_read(struct inode *inode, void *buf, int size, loff_t *offs) int err, blocksize, csize, boffs, osize = size; /* prevent reading after eof */ - lock_kernel(); + cfs_lock_kernel(); if (i_size_read(inode) < *offs + size) { size = i_size_read(inode) - *offs; - unlock_kernel(); + cfs_unlock_kernel(); if (size < 0) { CDEBUG(D_EXT2, "size %llu is too short for read @%llu\n", i_size_read(inode), *offs); @@ -1240,7 +1297,7 @@ int fsfilt_ext3_read(struct inode *inode, void *buf, int size, loff_t *offs) return 0; } } else { - unlock_kernel(); + cfs_unlock_kernel(); } blocksize = 1 << inode->i_blkbits; @@ -1323,14 +1380,14 @@ int fsfilt_ext3_write_handle(struct inode *inode, void *buf, int bufsize, /* correct in-core and on-disk sizes */ if (new_size > i_size_read(inode)) { - lock_kernel(); + cfs_lock_kernel(); if (new_size > i_size_read(inode)) i_size_write(inode, new_size); if (i_size_read(inode) > EXT3_I(inode)->i_disksize) EXT3_I(inode)->i_disksize = i_size_read(inode); if (i_size_read(inode) > old_size) mark_inode_dirty(inode); - unlock_kernel(); + cfs_unlock_kernel(); } if (err == 0) @@ -1398,7 +1455,7 @@ static int fsfilt_ext3_setup(struct super_block *sb) sbi->s_qf_names[USRQUOTA] = NULL; return -ENOMEM; } - sbi->s_jquota_fmt = QFMT_VFS_V0; + sbi->s_jquota_fmt = QFMT_LUSTRE; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)) set_opt(sbi->s_mount_opt, QUOTA); #endif @@ -1463,7 +1520,7 @@ static int fsfilt_ext3_quotactl(struct super_block *sb, struct obd_quotactl *oqc) { int i, rc = 0, error = 0; - struct quotactl_ops *qcop; + const struct quotactl_ops *qcop; struct if_dqinfo *info; struct if_dqblk *dqblk; ENTRY; @@ -1494,7 +1551,7 @@ static int fsfilt_ext3_quotactl(struct super_block *sb, LASSERT(oqc->qc_id == LUSTRE_QUOTA_V2); - rc = ll_quota_on(sb, i, QFMT_VFS_V0, + rc = ll_quota_on(sb, i, QFMT_LUSTRE, name[i], 0); } else if (oqc->qc_cmd == Q_QUOTAOFF) { rc = ll_quota_off(sb, i, 0); @@ -1575,8 +1632,8 @@ out: } struct chk_dqblk{ - struct hlist_node dqb_hash; /** quotacheck hash */ - struct list_head dqb_list; /** in list also */ + cfs_hlist_node_t dqb_hash; /** quotacheck hash */ + cfs_list_t dqb_list; /** in list also */ qid_t dqb_id; /** uid/gid */ short dqb_type; /** USRQUOTA/GRPQUOTA */ qsize_t dqb_bhardlimit; /** block hard limit */ @@ -1585,8 +1642,8 @@ struct chk_dqblk{ qsize_t dqb_ihardlimit; /** inode hard limit */ qsize_t dqb_isoftlimit; /** inode soft limit */ qsize_t dqb_curinodes; /** current inodes */ - __u64 dqb_btime; /** block grace time */ - __u64 dqb_itime; /** inode grace time */ + obd_time dqb_btime; /** block grace time */ + obd_time dqb_itime; /** inode grace time */ __u32 dqb_valid; /** flag for above fields */ }; @@ -1599,13 +1656,13 @@ static inline unsigned int chkquot_hash(qid_t id, int type) } static inline struct chk_dqblk * -find_chkquot(struct hlist_head *head, qid_t id, int type) +find_chkquot(cfs_hlist_head_t *head, qid_t id, int type) { - struct hlist_node *node; + cfs_hlist_node_t *node; struct chk_dqblk *cdqb; - hlist_for_each(node, head) { - cdqb = hlist_entry(node, struct chk_dqblk, dqb_hash); + cfs_hlist_for_each(node, head) { + cdqb = cfs_hlist_entry(node, struct chk_dqblk, dqb_hash); if (cdqb->dqb_id == id && cdqb->dqb_type == type) return cdqb; } @@ -1619,8 +1676,8 @@ static struct chk_dqblk *alloc_chkquot(qid_t id, int type) OBD_ALLOC_PTR(cdqb); if (cdqb) { - INIT_HLIST_NODE(&cdqb->dqb_hash); - INIT_LIST_HEAD(&cdqb->dqb_list); + CFS_INIT_HLIST_NODE(&cdqb->dqb_hash); + CFS_INIT_LIST_HEAD(&cdqb->dqb_list); cdqb->dqb_id = id; cdqb->dqb_type = type; } @@ -1629,10 +1686,10 @@ static struct chk_dqblk *alloc_chkquot(qid_t id, int type) } static struct chk_dqblk * -cqget(struct super_block *sb, struct hlist_head *hash, struct list_head *list, - qid_t id, int type, int first_check) +cqget(struct super_block *sb, cfs_hlist_head_t *hash, + cfs_list_t *list, qid_t id, int type, int first_check) { - struct hlist_head *head = hash + chkquot_hash(id, type); + cfs_hlist_head_t *head = hash + chkquot_hash(id, type); struct if_dqblk dqb; struct chk_dqblk *cdqb; int rc; @@ -1657,8 +1714,8 @@ cqget(struct super_block *sb, struct hlist_head *hash, struct list_head *list, } } - hlist_add_head(&cdqb->dqb_hash, head); - list_add_tail(&cdqb->dqb_list, list); + cfs_hlist_add_head(&cdqb->dqb_hash, head); + cfs_list_add_tail(&cdqb->dqb_list, list); return cdqb; } @@ -1737,10 +1794,10 @@ static __u32 ext3_itable_unused_count(struct super_block *sb, #endif struct qchk_ctxt { - struct hlist_head qckt_hash[NR_DQHASH]; /* quotacheck hash */ - struct list_head qckt_list; /* quotacheck list */ + cfs_hlist_head_t qckt_hash[NR_DQHASH]; /* quotacheck hash */ + cfs_list_t qckt_list; /* quotacheck list */ int qckt_first_check[MAXQUOTAS]; /* 1 if no old quotafile */ - struct if_dqinfo qckt_dqinfo[MAXQUOTAS]; /* old dqinfo */ + struct if_dqinfo qckt_dqinfo[MAXQUOTAS]; /* old dqinfo */ }; static int add_inode_quota(struct inode *inode, struct qchk_ctxt *qctxt, @@ -1819,7 +1876,7 @@ static int v3_write_dqinfo(struct file *f, int type, struct if_dqinfo *info) static int v3_write_dqheader(struct file *f, int type) { static const __u32 quota_magics[] = V2_INITQMAGICS; - static const __u32 quota_versions[] = V2_INITQVERSIONS_R1; + static const __u32 quota_versions[] = LUSTRE_INITQVERSIONS_V2; struct v2_disk_dqheader dqhead; loff_t offset = 0; @@ -1863,7 +1920,7 @@ static int create_new_quota_files(struct qchk_ctxt *qctxt, GOTO(out, rc = -EINVAL); } - DQUOT_DROP(file->f_dentry->d_inode); + ll_vfs_dq_drop(file->f_dentry->d_inode); rc = v3_write_dqheader(file, i); if (rc) { @@ -1926,14 +1983,14 @@ static int prune_chkquots(struct super_block *sb, struct chk_dqblk *cdqb, *tmp; int rc; - list_for_each_entry_safe(cdqb, tmp, &qctxt->qckt_list, dqb_list) { + cfs_list_for_each_entry_safe(cdqb, tmp, &qctxt->qckt_list, dqb_list) { if (!error) { rc = commit_chkquot(sb, qctxt, cdqb); if (rc) error = rc; } - hlist_del_init(&cdqb->dqb_hash); - list_del(&cdqb->dqb_list); + cfs_hlist_del_init(&cdqb->dqb_hash); + cfs_list_del(&cdqb->dqb_list); OBD_FREE_PTR(cdqb); } @@ -1964,8 +2021,8 @@ static int fsfilt_ext3_quotacheck(struct super_block *sb, } for (i = 0; i < NR_DQHASH; i++) - INIT_HLIST_HEAD(&qctxt->qckt_hash[i]); - INIT_LIST_HEAD(&qctxt->qckt_list); + CFS_INIT_HLIST_HEAD(&qctxt->qckt_hash[i]); + CFS_INIT_LIST_HEAD(&qctxt->qckt_list); for (i = 0; i < MAXQUOTAS; i++) { if (!Q_TYPESET(oqc, i)) @@ -2004,14 +2061,27 @@ static int fsfilt_ext3_quotacheck(struct super_block *sb, /* we don't really need to take the group lock here, * but it may be useful if one day we support online * quotacheck */ +#ifdef HAVE_EXT4_LDISKFS + ext4_lock_group(sb, group); +#else spin_lock(sb_bgl_lock(sbi, group)); +#endif if (desc->bg_flags & cpu_to_le16(EXT3_BG_INODE_UNINIT)) { /* no inode in use in this group, just skip it */ +#ifdef HAVE_EXT4_LDISKFS + ext3_unlock_group(sb, group); +#else spin_unlock(sb_bgl_lock(sbi, group)); +#endif continue; } + used_count -= ext3_itable_unused_count(sb, desc); +#ifdef HAVE_EXT4_LDISKFS + ext3_unlock_group(sb, group); +#else spin_unlock(sb_bgl_lock(sbi, group)); +#endif } ino = group * sbi->s_inodes_per_group + 1; @@ -2053,7 +2123,7 @@ static int fsfilt_ext3_quotacheck(struct super_block *sb, * has limits but hasn't file) */ #ifdef HAVE_QUOTA_SUPPORT for (i = 0; i < MAXQUOTAS; i++) { - struct list_head id_list; + cfs_list_t id_list; struct dquot_id *dqid, *tmp; if (!Q_TYPESET(oqc, i)) @@ -2064,7 +2134,7 @@ static int fsfilt_ext3_quotacheck(struct super_block *sb, LASSERT(sb_dqopt(sb)->files[i] != NULL); - INIT_LIST_HEAD(&id_list); + CFS_INIT_LIST_HEAD(&id_list); #ifndef KERNEL_SUPPORTS_QUOTA_READ rc = lustre_get_qids(sb_dqopt(sb)->files[i], NULL, i, &id_list); #else @@ -2073,8 +2143,8 @@ static int fsfilt_ext3_quotacheck(struct super_block *sb, if (rc) CERROR("read old limits failed. (rc:%d)\n", rc); - list_for_each_entry_safe(dqid, tmp, &id_list, di_link) { - list_del_init(&dqid->di_link); + cfs_list_for_each_entry_safe(dqid, tmp, &id_list, di_link) { + cfs_list_del_init(&dqid->di_link); if (!rc) cqget(sb, qctxt->qckt_hash, &qctxt->qckt_list, @@ -2148,7 +2218,7 @@ static int fsfilt_ext3_quotainfo(struct lustre_quota_info *lqi, int type, } static int fsfilt_ext3_qids(struct file *file, struct inode *inode, int type, - struct list_head *list) + cfs_list_t *list) { return lustre_get_qids(file, inode, type, list); } @@ -2172,9 +2242,9 @@ static int fsfilt_ext3_dquot(struct lustre_dquot *dquot, int cmd) dquot->dq_dqb.dqb_isoftlimit || dquot->dq_dqb.dqb_bhardlimit || dquot->dq_dqb.dqb_bsoftlimit) - clear_bit(DQ_FAKE_B, &dquot->dq_flags); + cfs_clear_bit(DQ_FAKE_B, &dquot->dq_flags); else - set_bit(DQ_FAKE_B, &dquot->dq_flags); + cfs_set_bit(DQ_FAKE_B, &dquot->dq_flags); rc = lustre_commit_dquot(dquot); if (rc >= 0) @@ -2219,6 +2289,12 @@ ssize_t lustre_read_quota(struct file *f, struct inode *inode, int type, loff_t p = pos; int rc; + if (!f && !inode) { + CERROR("lustre_read_quota failed for no quota file!\n"); + libcfs_debug_dumpstack(NULL); + return -EINVAL; + } + /* Support for both adm and op quota files must be provided */ if (f) { rc = fsfilt_ext3_read_record(f, buf, count, &p); @@ -2273,6 +2349,69 @@ void lustre_quota_journal_stop(void *handle) ext3_journal_stop((handle_t *)handle); } +static int ll_decode_fh_accept(void *context, struct dentry *de) +{ + return 1; +} + +#ifdef HAVE_EXPORTFS_DECODE_FH +# define ll_exportfs_decode_fh(mnt, fid, len, type, acceptable, context) \ + exportfs_decode_fh(mnt, (struct fid*)(fid), len, type, \ + acceptable, context) +#else +# define ll_exportfs_decode_fh(mnt, fid, len, type, acceptable, context) \ + export_op_default.decode_fh((mnt)->mnt_sb, &(fid)->ino, len, \ + type, acceptable, context) +# define FILEID_INO32_GEN 1 +extern struct export_operations export_op_default; +#endif + +struct dentry *fsfilt_ext3_fid2dentry(struct vfsmount *mnt, + struct fsfilt_fid *fid, int ignore_gen) +{ + struct inode *inode; + struct dentry *result; + + result = ll_exportfs_decode_fh(mnt, fid, 2, FILEID_INO32_GEN, + ll_decode_fh_accept, NULL); + if (IS_ERR(result)) { + CDEBUG(D_DENTRY, "%s of %u/%u failed %ld\n", __func__, + fid->ino, fid->gen, PTR_ERR(result)); + return result; + } + + CDEBUG(D_DENTRY, "%s of %u/%u succeeded\n", __func__, + fid->ino, fid->gen); + inode = result->d_inode; + if (inode == NULL) + goto err_out; + + if (inode->i_nlink == 0 && + inode->i_mode == 0 && LTIME_S(inode->i_ctime) == 0) { + LCONSOLE_WARN("Found inode with zero nlink, mode and" + " ctime -- this may indicate disk " + "corruption (inode: %lu, link: %lu, " + "count: %d)\n", inode->i_ino, + (unsigned long)inode->i_nlink, + atomic_read(&inode->i_count)); + goto err_out; + } + if (fid->gen && inode->i_generation != fid->gen) { + /* we didn't find the right inode.. */ + CDEBUG(D_INODE, "found wrong generation: inode %lu, link: %lu, " + "count: %d, generation %u/%u\n", + inode->i_ino, (unsigned long)inode->i_nlink, + atomic_read(&inode->i_count), inode->i_generation, + fid->gen); + goto err_out; + } + + return result; +err_out: + l_dput(result); + return ERR_PTR(-ENOENT); +} + static struct fsfilt_operations fsfilt_ext3_ops = { .fs_type = "ext3", .fs_owner = THIS_MODULE, @@ -2312,6 +2451,7 @@ static struct fsfilt_operations fsfilt_ext3_ops = { .fs_get_mblk = fsfilt_ext3_get_mblk, #endif .fs_journal_sbdev = fsfilt_ext3_journal_sbdev, + .fs_fid2dentry = fsfilt_ext3_fid2dentry, }; static int __init fsfilt_ext3_init(void)