From: Eric Sandeen <sandeen@redhat.com> Date: Wed, 25 Mar 2009 15:54:52 -0500 Subject: [fs] xfs: backport to rhel5.4 kernel Message-id: 49CA9A1C.5010907@redhat.com O-Subject: [PATCH 7/10] backport xfs to rhel5.4 kernel Bugzilla: 470845 RH-Acked-by: Josef Bacik <josef@redhat.com> Majority of the backporting bits to make the previous patch build & run (modulo aops update patch, next). I can point reviewers to a much more finegrained quilt series that this patch came from, if need be. diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig index 3f53dd1..cbe1af0 100644 --- a/fs/xfs/Kconfig +++ b/fs/xfs/Kconfig @@ -1,6 +1,5 @@ config XFS_FS tristate "XFS filesystem support" - depends on BLOCK help XFS is a high performance journaling filesystem which originated on the SGI IRIX platform. It is completely multi-threaded, can diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c index 1cd3b55..9afb573 100644 --- a/fs/xfs/linux-2.6/kmem.c +++ b/fs/xfs/linux-2.6/kmem.c @@ -53,7 +53,7 @@ kmem_alloc(size_t size, unsigned int __nocast flags) printk(KERN_ERR "XFS: possible memory allocation " "deadlock in %s (mode:0x%x)\n", __func__, lflags); - congestion_wait(WRITE, HZ/50); + blk_congestion_wait(WRITE, HZ/50); } while (1); } @@ -95,7 +95,7 @@ kmem_free(const void *ptr) if (!is_vmalloc_addr(ptr)) { kfree(ptr); } else { - vfree(ptr); + vfree((void *)ptr); } } @@ -130,7 +130,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags) printk(KERN_ERR "XFS: possible memory allocation " "deadlock in %s (mode:0x%x)\n", __func__, lflags); - congestion_wait(WRITE, HZ/50); + blk_congestion_wait(WRITE, HZ/50); } while (1); } diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h index af6843c..3ccf8e3 100644 --- a/fs/xfs/linux-2.6/kmem.h +++ b/fs/xfs/linux-2.6/kmem.h @@ -74,14 +74,14 @@ extern void kmem_free(const void *); static inline kmem_zone_t * kmem_zone_init(int size, char *zone_name) { - return kmem_cache_create(zone_name, size, 0, 0, NULL); + return kmem_cache_create(zone_name, size, 0, 0, NULL, NULL); } static inline kmem_zone_t * kmem_zone_init_flags(int size, char *zone_name, unsigned long flags, - void (*construct)(void *)) + void (*construct)(void *, kmem_zone_t *, unsigned long)) { - return kmem_cache_create(zone_name, size, 0, flags, construct); + return kmem_cache_create(zone_name, size, 0, flags, construct, NULL); } static inline void diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index a44d68e..e79d83c 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -202,10 +202,9 @@ xfs_setfilesize( */ STATIC void xfs_end_bio_delalloc( - struct work_struct *work) + void *data) { - xfs_ioend_t *ioend = - container_of(work, xfs_ioend_t, io_work); + xfs_ioend_t *ioend = data; xfs_setfilesize(ioend); xfs_destroy_ioend(ioend); @@ -216,10 +215,9 @@ xfs_end_bio_delalloc( */ STATIC void xfs_end_bio_written( - struct work_struct *work) + void *data) { - xfs_ioend_t *ioend = - container_of(work, xfs_ioend_t, io_work); + xfs_ioend_t *ioend = data; xfs_setfilesize(ioend); xfs_destroy_ioend(ioend); @@ -233,10 +231,9 @@ xfs_end_bio_written( */ STATIC void xfs_end_bio_unwritten( - struct work_struct *work) + void *data) { - xfs_ioend_t *ioend = - container_of(work, xfs_ioend_t, io_work); + xfs_ioend_t *ioend = data; struct xfs_inode *ip = XFS_I(ioend->io_inode); xfs_off_t offset = ioend->io_offset; size_t size = ioend->io_size; @@ -258,10 +255,9 @@ xfs_end_bio_unwritten( */ STATIC void xfs_end_bio_read( - struct work_struct *work) + void *data) { - xfs_ioend_t *ioend = - container_of(work, xfs_ioend_t, io_work); + xfs_ioend_t *ioend = data; xfs_destroy_ioend(ioend); } @@ -298,13 +294,13 @@ xfs_alloc_ioend( ioend->io_size = 0; if (type == IOMAP_UNWRITTEN) - INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten); + INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten, ioend); else if (type == IOMAP_DELAY) - INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc); + INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc, ioend); else if (type == IOMAP_READ) - INIT_WORK(&ioend->io_work, xfs_end_bio_read); + INIT_WORK(&ioend->io_work, xfs_end_bio_read, ioend); else - INIT_WORK(&ioend->io_work, xfs_end_bio_written); + INIT_WORK(&ioend->io_work, xfs_end_bio_written, ioend); return ioend; } @@ -339,13 +335,17 @@ xfs_iomap_valid( /* * BIO completion handler for buffered IO. */ -STATIC void +STATIC int xfs_end_bio( struct bio *bio, + unsigned int bytes_done, int error) { xfs_ioend_t *ioend = bio->bi_private; + if (bio->bi_size) + return 1; + ASSERT(atomic_read(&bio->bi_cnt) >= 1); ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error; @@ -355,6 +355,7 @@ xfs_end_bio( bio_put(bio); xfs_finish_ioend(ioend, 0); + return 0; } STATIC void @@ -674,7 +675,7 @@ xfs_probe_cluster( } else pg_offset = PAGE_CACHE_SIZE; - if (page->index == tindex && trylock_page(page)) { + if (page->index == tindex && !TestSetPageLocked(page)) { pg_len = xfs_probe_page(page, pg_offset, mapped); unlock_page(page); } @@ -758,7 +759,7 @@ xfs_convert_page( if (page->index != tindex) goto fail; - if (!trylock_page(page)) + if (TestSetPageLocked(page)) goto fail; if (PageWriteback(page)) goto fail_unlock_page; @@ -1103,7 +1104,7 @@ xfs_page_state_convert( * that we are writing into for the first time. */ type = IOMAP_NEW; - if (trylock_buffer(bh)) { + if (!test_and_set_bit(BH_Lock, &bh->b_state)) { ASSERT(buffer_mapped(bh)); if (iomap_valid) all_bh = 1; @@ -1468,7 +1469,7 @@ xfs_end_io_direct( * didn't map an unwritten extent so switch it's completion * handler. */ - INIT_WORK(&ioend->io_work, xfs_end_bio_written); + INIT_WORK(&ioend->io_work, xfs_end_bio_written, ioend); xfs_finish_ioend(ioend, 0); } diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 8454dee..f0e7ab4 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -32,16 +32,12 @@ #include <linux/kthread.h> #include <linux/migrate.h> #include <linux/backing-dev.h> -#include <linux/freezer.h> static kmem_zone_t *xfs_buf_zone; STATIC int xfsbufd(void *); STATIC int xfsbufd_wakeup(int, gfp_t); STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int); -static struct shrinker xfs_buf_shake = { - .shrink = xfsbufd_wakeup, - .seeks = DEFAULT_SEEKS, -}; +static struct shrinker *xfs_buf_shake; static struct workqueue_struct *xfslogd_workqueue; struct workqueue_struct *xfsdatad_workqueue; @@ -58,7 +54,7 @@ xfs_buf_trace( bp, id, (void *)(unsigned long)bp->b_flags, (void *)(unsigned long)bp->b_hold.counter, - (void *)(unsigned long)bp->b_sema.count, + (void *)(unsigned long)bp->b_sema.count.counter, (void *)current, data, ra, (void *)(unsigned long)((bp->b_file_offset>>32) & 0xffffffff), @@ -405,7 +401,7 @@ _xfs_buf_lookup_pages( XFS_STATS_INC(xb_page_retries); xfsbufd_wakeup(0, gfp_mask); - congestion_wait(WRITE, HZ/50); + blk_congestion_wait(WRITE, HZ/50); goto retry; } @@ -891,7 +887,7 @@ int xfs_buf_lock_value( xfs_buf_t *bp) { - return bp->b_sema.count; + return atomic_read(&bp->b_sema.count); } #endif @@ -992,10 +988,9 @@ xfs_buf_wait_unpin( STATIC void xfs_buf_iodone_work( - struct work_struct *work) + void *data) { - xfs_buf_t *bp = - container_of(work, xfs_buf_t, b_iodone_work); + xfs_buf_t *bp = data; /* * We can get an EOPNOTSUPP to ordered writes. Here we clear the @@ -1028,10 +1023,10 @@ xfs_buf_ioend( if ((bp->b_iodone) || (bp->b_flags & XBF_ASYNC)) { if (schedule) { - INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work); + INIT_WORK(&bp->b_iodone_work, xfs_buf_iodone_work, bp); queue_work(xfslogd_workqueue, &bp->b_iodone_work); } else { - xfs_buf_iodone_work(&bp->b_iodone_work); + xfs_buf_iodone_work(bp); } } else { complete(&bp->b_iowait); @@ -1105,15 +1100,19 @@ _xfs_buf_ioend( } } -STATIC void +STATIC int xfs_buf_bio_end_io( struct bio *bio, + unsigned int bytes_done, int error) { xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; unsigned int blocksize = bp->b_target->bt_bsize; struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + if (bio->bi_size) + return 1; + xfs_buf_ioerror(bp, -error); do { @@ -1139,6 +1138,7 @@ xfs_buf_bio_end_io( _xfs_buf_ioend(bp, 1); bio_put(bio); + return 0; } STATIC void @@ -1705,8 +1705,6 @@ xfsbufd( current->flags |= PF_MEMALLOC; - set_freezable(); - do { if (unlikely(freezing(current))) { set_bit(XBT_FORCE_SLEEP, &target->bt_flags); @@ -1811,9 +1809,14 @@ xfs_buf_init(void) if (!xfsdatad_workqueue) goto out_destroy_xfslogd_workqueue; - register_shrinker(&xfs_buf_shake); + xfs_buf_shake = set_shrinker(DEFAULT_SEEKS, xfsbufd_wakeup); + if (!xfs_buf_shake) + goto out_destroy_xfsdatad_workqueue; + return 0; + out_destroy_xfsdatad_workqueue: + destroy_workqueue(xfsdatad_workqueue); out_destroy_xfslogd_workqueue: destroy_workqueue(xfslogd_workqueue); out_free_buf_zone: @@ -1828,7 +1831,7 @@ xfs_buf_init(void) void xfs_buf_terminate(void) { - unregister_shrinker(&xfs_buf_shake); + remove_shrinker(xfs_buf_shake); destroy_workqueue(xfsdatad_workqueue); destroy_workqueue(xfslogd_workqueue); kmem_zone_destroy(xfs_buf_zone); diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c index 7f7abec..c46e1df 100644 --- a/fs/xfs/linux-2.6/xfs_export.c +++ b/fs/xfs/linux-2.6/xfs_export.c @@ -22,7 +22,6 @@ #include "xfs_trans.h" #include "xfs_sb.h" #include "xfs_ag.h" -#include "xfs_dir2.h" #include "xfs_dmapi.h" #include "xfs_mount.h" #include "xfs_export.h" @@ -31,26 +30,65 @@ #include "xfs_inode.h" #include "xfs_vfsops.h" +static struct xfs_name xfs_name_dotdot = {"..", 2}; + /* - * Note that we only accept fileids which are long enough rather than allow - * the parent generation number to default to zero. XFS considers zero a - * valid generation number not an invalid/wildcard value. + * XFS encodes and decodes the fileid portion of NFS filehandles + * itself instead of letting the generic NFS code do it. This + * allows filesystems with 64 bit inode numbers to be exported. + * + * Note that a side effect is that xfs_vget() won't be passed a + * zero inode/generation pair under normal circumstances. As + * however a malicious client could send us such data, the check + * remains in that code. */ -static int xfs_fileid_length(int fileid_type) + +STATIC struct dentry * +xfs_fs_decode_fh( + struct super_block *sb, + __u32 *fh, + int fh_len, + int fileid_type, + int (*acceptable)( + void *context, + struct dentry *de), + void *context) { - switch (fileid_type) { - case FILEID_INO32_GEN: - return 2; - case FILEID_INO32_GEN_PARENT: - return 4; - case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG: - return 3; - case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG: - return 6; + xfs_fid_t ifid; + xfs_fid_t pfid; + void *parent = NULL; + int is64 = 0; + __u32 *p = fh; + +#if XFS_BIG_INUMS + is64 = (fileid_type & XFS_FILEID_TYPE_64FLAG); + fileid_type &= ~XFS_FILEID_TYPE_64FLAG; +#endif + + /* + * Note that we only accept fileids which are long enough + * rather than allow the parent generation number to default + * to zero. XFS considers zero a valid generation number not + * an invalid/wildcard value. There's little point printk'ing + * a warning here as we don't have the client information + * which would make such a warning useful. + */ + if (fileid_type > 2 || + fh_len < xfs_fileid_length((fileid_type == 2), is64)) + return NULL; + + p = xfs_fileid_decode_fid2(p, &ifid, is64); + + if (fileid_type == 2) { + p = xfs_fileid_decode_fid2(p, &pfid, is64); + parent = &pfid; } - return 255; /* invalid */ + + fh = (__u32 *)&ifid; + return sb->s_export_op->find_exported_dentry(sb, fh, parent, acceptable, context); } + STATIC int xfs_fs_encode_fh( struct dentry *dentry, @@ -58,21 +96,20 @@ xfs_fs_encode_fh( int *max_len, int connectable) { - struct fid *fid = (struct fid *)fh; - struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fh; struct inode *inode = dentry->d_inode; - int fileid_type; + int type = 1; + __u32 *p = fh; int len; - + int is64 = 0; +#if XFS_BIG_INUMS + if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS)) { + /* filesystem may contain 64bit inode numbers */ + is64 = XFS_FILEID_TYPE_64FLAG; + } +#endif /* Directories don't need their parent encoded, they have ".." */ - if (S_ISDIR(inode->i_mode) || !connectable) - fileid_type = FILEID_INO32_GEN; - else - fileid_type = FILEID_INO32_GEN_PARENT; - - /* filesystem may contain 64bit inode numbers */ - if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS)) - fileid_type |= XFS_FILEID_TYPE_64FLAG; + if (S_ISDIR(inode->i_mode)) + connectable = 0; /* * Only encode if there is enough space given. In practice @@ -80,110 +117,52 @@ xfs_fs_encode_fh( * over NFSv2 with the subtree_check export option; the other * seven combinations work. The real answer is "don't use v2". */ - len = xfs_fileid_length(fileid_type); + len = xfs_fileid_length(connectable, is64); if (*max_len < len) return 255; *max_len = len; - switch (fileid_type) { - case FILEID_INO32_GEN_PARENT: - spin_lock(&dentry->d_lock); - fid->i32.parent_ino = dentry->d_parent->d_inode->i_ino; - fid->i32.parent_gen = dentry->d_parent->d_inode->i_generation; - spin_unlock(&dentry->d_lock); - /*FALLTHRU*/ - case FILEID_INO32_GEN: - fid->i32.ino = inode->i_ino; - fid->i32.gen = inode->i_generation; - break; - case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG: + p = xfs_fileid_encode_inode(p, inode, is64); + if (connectable) { spin_lock(&dentry->d_lock); - fid64->parent_ino = dentry->d_parent->d_inode->i_ino; - fid64->parent_gen = dentry->d_parent->d_inode->i_generation; + p = xfs_fileid_encode_inode(p, dentry->d_parent->d_inode, is64); spin_unlock(&dentry->d_lock); - /*FALLTHRU*/ - case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG: - fid64->ino = inode->i_ino; - fid64->gen = inode->i_generation; - break; + type = 2; } - - return fileid_type; + BUG_ON((p - fh) != len); + return type | is64; } -STATIC struct inode * -xfs_nfs_get_inode( +STATIC struct dentry * +xfs_fs_get_dentry( struct super_block *sb, - u64 ino, - u32 generation) - { - xfs_mount_t *mp = XFS_M(sb); - xfs_inode_t *ip; + void *data) +{ + struct xfs_inode *ip; + struct inode *inode; + xfs_fid_t *xfid = (struct xfs_fid *)data; + xfs_mount_t *mp = XFS_M(sb); int error; /* * NFS can sometimes send requests for ino 0. Fail them gracefully. */ - if (ino == 0) + if (xfid->fid_ino == 0) return ERR_PTR(-ESTALE); - error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0); + error = xfs_iget(mp, NULL, xfid->fid_ino, 0, XFS_ILOCK_SHARED, &ip, 0); if (error) return ERR_PTR(-error); if (!ip) - return ERR_PTR(-EIO); + return ERR_PTR(-EIO) ; - if (ip->i_d.di_gen != generation) { + if (!ip->i_d.di_mode || ip->i_d.di_gen != xfid->fid_gen) { xfs_iput_new(ip, XFS_ILOCK_SHARED); return ERR_PTR(-ENOENT); } xfs_iunlock(ip, XFS_ILOCK_SHARED); - return VFS_I(ip); -} - -STATIC struct dentry * -xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid, - int fh_len, int fileid_type) -{ - struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid; - struct inode *inode = NULL; - - if (fh_len < xfs_fileid_length(fileid_type)) - return NULL; - - switch (fileid_type) { - case FILEID_INO32_GEN_PARENT: - case FILEID_INO32_GEN: - inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen); - break; - case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG: - case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG: - inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen); - break; - } - - return d_obtain_alias(inode); -} - -STATIC struct dentry * -xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid, - int fh_len, int fileid_type) -{ - struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid; - struct inode *inode = NULL; - - switch (fileid_type) { - case FILEID_INO32_GEN_PARENT: - inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino, - fid->i32.parent_gen); - break; - case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG: - inode = xfs_nfs_get_inode(sb, fid64->parent_ino, - fid64->parent_gen); - break; - } - + inode = VFS_I(ip); return d_obtain_alias(inode); } @@ -194,6 +173,7 @@ xfs_fs_get_parent( int error; struct xfs_inode *cip; + cip = NULL; error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip, NULL); if (unlikely(error)) return ERR_PTR(-error); @@ -201,9 +181,10 @@ xfs_fs_get_parent( return d_obtain_alias(VFS_I(cip)); } -const struct export_operations xfs_export_operations = { +struct export_operations xfs_export_operations = { + .decode_fh = xfs_fs_decode_fh, .encode_fh = xfs_fs_encode_fh, - .fh_to_dentry = xfs_fs_fh_to_dentry, - .fh_to_parent = xfs_fs_fh_to_parent, .get_parent = xfs_fs_get_parent, + .get_dentry = xfs_fs_get_dentry, }; + diff --git a/fs/xfs/linux-2.6/xfs_export.h b/fs/xfs/linux-2.6/xfs_export.h index 3272b6a..675bc63 100644 --- a/fs/xfs/linux-2.6/xfs_export.h +++ b/fs/xfs/linux-2.6/xfs_export.h @@ -59,14 +59,51 @@ * a subdirectory) or use the "fsid" export option. */ -struct xfs_fid64 { - u64 ino; - u32 gen; - u64 parent_ino; - u32 parent_gen; -} __attribute__((packed)); - /* This flag goes on the wire. Don't play with it. */ #define XFS_FILEID_TYPE_64FLAG 0x80 /* NFS fileid has 64bit inodes */ +/* Calculate the length in u32 units of the fileid data */ +static inline int +xfs_fileid_length(int hasparent, int is64) +{ + return hasparent ? (is64 ? 6 : 4) : (is64 ? 3 : 2); +} + +/* + * Decode encoded inode information (either for the inode itself + * or the parent) into an xfs_fid_t structure. Advances and + * returns the new data pointer + */ +static inline __u32 * +xfs_fileid_decode_fid2(__u32 *p, xfs_fid_t *fid, int is64) +{ + fid->fid_len = sizeof(xfs_fid_t) - sizeof(fid->fid_len); + fid->fid_pad = 0; + fid->fid_ino = *p++; +#if XFS_BIG_INUMS + if (is64) + fid->fid_ino |= (((__u64)(*p++)) << 32); +#endif + fid->fid_gen = *p++; + return p; +} + +/* + * Encode inode information (either for the inode itself or the + * parent) into a fileid buffer. Advances and returns the new + * data pointer. + */ +static inline __u32 * +xfs_fileid_encode_inode(__u32 *p, struct inode *inode, int is64) +{ + *p++ = (__u32)inode->i_ino; +#if XFS_BIG_INUMS + if (is64) + *p++ = (__u32)(inode->i_ino >> 32); +#endif + *p++ = inode->i_generation; + return p; +} + #endif /* __XFS_EXPORT_H__ */ + diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 3fee790..dc28fd4 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -47,75 +47,209 @@ static struct vm_operations_struct xfs_file_vm_ops; STATIC_INLINE ssize_t __xfs_file_read( struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, + char __user *buf, int ioflags, + size_t count, loff_t pos) { + struct iovec iov = {buf, count}; struct file *file = iocb->ki_filp; BUG_ON(iocb->ki_pos != pos); if (unlikely(file->f_flags & O_DIRECT)) ioflags |= IO_ISDIRECT; - return xfs_read(XFS_I(file->f_path.dentry->d_inode), iocb, iov, - nr_segs, &iocb->ki_pos, ioflags); + return xfs_read(XFS_I(file->f_dentry->d_inode), iocb, &iov, 1, &iocb->ki_pos, ioflags); } STATIC ssize_t xfs_file_aio_read( struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, + char __user *buf, + size_t count, loff_t pos) { - return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO, pos); + return __xfs_file_read(iocb, buf, IO_ISAIO, count, pos); } STATIC ssize_t xfs_file_aio_read_invis( struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, + char __user *buf, + size_t count, loff_t pos) { - return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos); + return __xfs_file_read(iocb, buf, IO_ISAIO|IO_INVIS, count, pos); } STATIC_INLINE ssize_t __xfs_file_write( struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, + const char __user *buf, int ioflags, + size_t count, loff_t pos) { + struct iovec iov = {(void __user *)buf, count}; struct file *file = iocb->ki_filp; BUG_ON(iocb->ki_pos != pos); if (unlikely(file->f_flags & O_DIRECT)) ioflags |= IO_ISDIRECT; - return xfs_write(XFS_I(file->f_mapping->host), iocb, iov, nr_segs, + return xfs_write(XFS_I(file->f_mapping->host), iocb, &iov, 1, &iocb->ki_pos, ioflags); } STATIC ssize_t xfs_file_aio_write( struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, + const char __user *buf, + size_t count, loff_t pos) { - return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO, pos); + return __xfs_file_write(iocb, buf, IO_ISAIO, count, pos); } STATIC ssize_t xfs_file_aio_write_invis( struct kiocb *iocb, + const char __user *buf, + size_t count, + loff_t pos) +{ + return __xfs_file_write(iocb, buf, IO_ISAIO|IO_INVIS, count, pos); +} + +STATIC_INLINE ssize_t +__xfs_file_readv( + struct file *file, const struct iovec *iov, + int ioflags, unsigned long nr_segs, - loff_t pos) + loff_t *ppos) +{ + struct kiocb kiocb; + ssize_t rval; + + init_sync_kiocb(&kiocb, file); + kiocb.ki_pos = *ppos; + + if (unlikely(file->f_flags & O_DIRECT)) + ioflags |= IO_ISDIRECT; + rval = xfs_read(XFS_I(file->f_dentry->d_inode), &kiocb, iov, + nr_segs, &kiocb.ki_pos, ioflags); + + *ppos = kiocb.ki_pos; + return rval; +} + +STATIC ssize_t +xfs_file_readv( + struct file *file, + const struct iovec *iov, + unsigned long nr_segs, + loff_t *ppos) +{ + return __xfs_file_readv(file, iov, 0, nr_segs, ppos); +} + +STATIC_INLINE ssize_t +__xfs_file_writev( + struct file *file, + const struct iovec *iov, + int ioflags, + unsigned long nr_segs, + loff_t *ppos) +{ + struct kiocb kiocb; + ssize_t rval; + + init_sync_kiocb(&kiocb, file); + kiocb.ki_pos = *ppos; + if (unlikely(file->f_flags & O_DIRECT)) + ioflags |= IO_ISDIRECT; + + rval = xfs_write(XFS_I(file->f_mapping->host), &kiocb, iov, nr_segs, + &kiocb.ki_pos, ioflags); + + *ppos = kiocb.ki_pos; + return rval; +} + +STATIC ssize_t +xfs_file_writev( + struct file *file, + const struct iovec *iov, + unsigned long nr_segs, + loff_t *ppos) { - return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos); + return __xfs_file_writev(file, iov, 0, nr_segs, ppos); +} + +ssize_t +xfs_sendfile( + struct xfs_inode *xip, + struct file *filp, + loff_t *offset, + int ioflags, + size_t count, + read_actor_t actor, + void *target, + cred_t *credp) +{ + xfs_mount_t *mp = xip->i_mount; + ssize_t ret; + + XFS_STATS_INC(xs_read_calls); + if (XFS_FORCED_SHUTDOWN(mp)) + return -EIO; + + xfs_ilock(xip, XFS_IOLOCK_SHARED); + + if (DM_EVENT_ENABLED(xip, DM_EVENT_READ) && + (!(ioflags & IO_INVIS))) { + int locktype = XFS_IOLOCK_SHARED; + int error; + + error = XFS_SEND_DATA(mp, DM_EVENT_READ, xip, + *offset, count, + FILP_DELAY_FLAG(filp), &locktype); + if (error) { + xfs_iunlock(xip, XFS_IOLOCK_SHARED); + return -error; + } + } + xfs_rw_enter_trace(XFS_SENDFILE_ENTER, xip, + (void *)(unsigned long)target, count, *offset, ioflags); + ret = generic_file_sendfile(filp, offset, count, actor, target); + if (ret > 0) + XFS_STATS_ADD(xs_read_bytes, ret); + + xfs_iunlock(xip, XFS_IOLOCK_SHARED); + return ret; +} + +STATIC ssize_t +xfs_file_sendfile( + struct file *filp, + loff_t *pos, + size_t count, + read_actor_t actor, + void *target) +{ + return xfs_sendfile(XFS_I(filp->f_dentry->d_inode), filp, pos, 0, + count, actor, target, NULL); +} + +STATIC ssize_t +xfs_file_sendfile_invis( + struct file *filp, + loff_t *pos, + size_t count, + read_actor_t actor, + void *target) +{ + return xfs_sendfile(XFS_I(filp->f_dentry->d_inode), filp, pos, IO_INVIS, + count, actor, target, NULL); } STATIC ssize_t @@ -126,7 +260,7 @@ xfs_file_splice_read( size_t len, unsigned int flags) { - return xfs_splice_read(XFS_I(infilp->f_path.dentry->d_inode), + return xfs_splice_read(XFS_I(infilp->f_dentry->d_inode), infilp, ppos, pipe, len, flags, 0); } @@ -138,7 +272,7 @@ xfs_file_splice_read_invis( size_t len, unsigned int flags) { - return xfs_splice_read(XFS_I(infilp->f_path.dentry->d_inode), + return xfs_splice_read(XFS_I(infilp->f_dentry->d_inode), infilp, ppos, pipe, len, flags, IO_INVIS); } @@ -150,7 +284,7 @@ xfs_file_splice_write( size_t len, unsigned int flags) { - return xfs_splice_write(XFS_I(outfilp->f_path.dentry->d_inode), + return xfs_splice_write(XFS_I(outfilp->f_dentry->d_inode), pipe, outfilp, ppos, len, flags, 0); } @@ -162,7 +296,7 @@ xfs_file_splice_write_invis( size_t len, unsigned int flags) { - return xfs_splice_write(XFS_I(outfilp->f_path.dentry->d_inode), + return xfs_splice_write(XFS_I(outfilp->f_dentry->d_inode), pipe, outfilp, ppos, len, flags, IO_INVIS); } @@ -204,13 +338,22 @@ xfs_file_fsync( return -xfs_fsync(XFS_I(dentry->d_inode)); } +/* + * Unfortunately we can't just use the clean and simple readdir implementation + * below, because nfs might call back into ->lookup from the filldir callback + * and that will deadlock the low-level btree code. + * + * Hopefully we'll find a better workaround that allows to use the optimal + * version at least for local readdirs for 2.6.25. + */ +#if 0 STATIC int xfs_file_readdir( struct file *filp, void *dirent, filldir_t filldir) { - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; xfs_inode_t *ip = XFS_I(inode); int error; size_t bufsize; @@ -235,6 +378,125 @@ xfs_file_readdir( return -error; return 0; } +#else + +struct hack_dirent { + u64 ino; + loff_t offset; + int namlen; + unsigned int d_type; + char name[]; +}; + +struct hack_callback { + char *dirent; + size_t len; + size_t used; +}; + +STATIC int +xfs_hack_filldir( + void *__buf, + const char *name, + int namlen, + loff_t offset, + u64 ino, + unsigned int d_type) +{ + struct hack_callback *buf = __buf; + struct hack_dirent *de = (struct hack_dirent *)(buf->dirent + buf->used); + unsigned int reclen; + + reclen = ALIGN(sizeof(struct hack_dirent) + namlen, sizeof(u64)); + if (buf->used + reclen > buf->len) + return -EINVAL; + + de->namlen = namlen; + de->offset = offset; + de->ino = ino; + de->d_type = d_type; + memcpy(de->name, name, namlen); + buf->used += reclen; + return 0; +} + +STATIC int +xfs_file_readdir( + struct file *filp, + void *dirent, + filldir_t filldir) +{ + struct inode *inode = filp->f_dentry->d_inode; + xfs_inode_t *ip = XFS_I(inode); + struct hack_callback buf; + struct hack_dirent *de; + int error; + loff_t size; + int eof = 0; + xfs_off_t start_offset, curr_offset, offset; + + /* + * Try fairly hard to get memory + */ + buf.len = PAGE_CACHE_SIZE; + do { + buf.dirent = kmalloc(buf.len, GFP_KERNEL); + if (buf.dirent) + break; + buf.len >>= 1; + } while (buf.len >= 1024); + + if (!buf.dirent) + return -ENOMEM; + + curr_offset = filp->f_pos; + if (curr_offset == 0x7fffffff) + offset = 0xffffffff; + else + offset = filp->f_pos; + + while (!eof) { + unsigned int reclen; + + start_offset = offset; + + buf.used = 0; + error = -xfs_readdir(ip, &buf, buf.len, &offset, + xfs_hack_filldir); + if (error || offset == start_offset) { + size = 0; + break; + } + + size = buf.used; + de = (struct hack_dirent *)buf.dirent; + while (size > 0) { + curr_offset = de->offset /* & 0x7fffffff */; + if (filldir(dirent, de->name, de->namlen, + curr_offset & 0x7fffffff, + de->ino, de->d_type)) { + goto done; + } + + reclen = ALIGN(sizeof(struct hack_dirent) + de->namlen, + sizeof(u64)); + size -= reclen; + de = (struct hack_dirent *)((char *)de + reclen); + } + } + + done: + if (!error) { + if (size == 0) + filp->f_pos = offset & 0x7fffffff; + else if (de) + filp->f_pos = curr_offset; + } + + kfree(buf.dirent); + return error; +} +#endif STATIC int xfs_file_mmap( @@ -242,7 +504,6 @@ xfs_file_mmap( struct vm_area_struct *vma) { vma->vm_ops = &xfs_file_vm_ops; - vma->vm_flags |= VM_CAN_NONLINEAR; file_accessed(filp); return 0; @@ -255,7 +516,7 @@ xfs_file_ioctl( unsigned long p) { int error; - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; error = xfs_ioctl(XFS_I(inode), filp, 0, cmd, (void __user *)p); xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED); @@ -276,7 +537,7 @@ xfs_file_ioctl_invis( unsigned long p) { int error; - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; error = xfs_ioctl(XFS_I(inode), filp, IO_INVIS, cmd, (void __user *)p); xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED); @@ -308,10 +569,13 @@ const struct file_operations xfs_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, + .readv = xfs_file_readv, + .writev = xfs_file_writev, .aio_read = xfs_file_aio_read, .aio_write = xfs_file_aio_write, .splice_read = xfs_file_splice_read, .splice_write = xfs_file_splice_write, + .sendfile = xfs_file_sendfile, .unlocked_ioctl = xfs_file_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = xfs_file_compat_ioctl, @@ -333,6 +597,7 @@ const struct file_operations xfs_invis_file_operations = { .aio_write = xfs_file_aio_write_invis, .splice_read = xfs_file_splice_read_invis, .splice_write = xfs_file_splice_write_invis, + .sendfile = xfs_file_sendfile_invis, .unlocked_ioctl = xfs_file_ioctl_invis, #ifdef CONFIG_COMPAT .compat_ioctl = xfs_file_compat_invis_ioctl, @@ -356,6 +621,7 @@ const struct file_operations xfs_dir_file_operations = { }; static struct vm_operations_struct xfs_file_vm_ops = { - .fault = filemap_fault, + .nopage = filemap_nopage, + .populate = filemap_populate, .page_mkwrite = xfs_vm_page_mkwrite, }; diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index d3438c7..7f433cf 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -86,15 +86,17 @@ xfs_find_handle( switch (cmd) { case XFS_IOC_PATH_TO_FSHANDLE: case XFS_IOC_PATH_TO_HANDLE: { - struct path path; - int error = user_lpath((const char __user *)hreq.path, &path); + struct nameidata nd; + int error; + + error = user_path_walk_link((const char __user *)hreq.path, &nd); if (error) return error; - ASSERT(path.dentry); - ASSERT(path.dentry->d_inode); - inode = igrab(path.dentry->d_inode); - path_put(&path); + ASSERT(nd.dentry); + ASSERT(nd.dentry->d_inode); + inode = igrab(nd.dentry->d_inode); + path_release(&nd); break; } @@ -105,9 +107,9 @@ xfs_find_handle( if (!file) return -EBADF; - ASSERT(file->f_path.dentry); - ASSERT(file->f_path.dentry->d_inode); - inode = igrab(file->f_path.dentry->d_inode); + ASSERT(file->f_dentry); + ASSERT(file->f_dentry->d_inode); + inode = igrab(file->f_dentry->d_inode); fput(file); break; } @@ -318,10 +320,10 @@ xfs_open_by_handle( } /* Ensure umount returns EBUSY on umounts while this file is open. */ - mntget(parfilp->f_path.mnt); + mntget(parfilp->f_vfsmnt); /* Create file pointer. */ - filp = dentry_open(dentry, parfilp->f_path.mnt, hreq.oflags); + filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags); if (IS_ERR(filp)) { put_unused_fd(new_fd); return -XFS_ERROR(-PTR_ERR(filp)); @@ -540,6 +542,8 @@ xfs_attrmulti_attr_set( char *kbuf; int error = EFAULT; + if (IS_RDONLY(inode)) + return -EROFS; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return EPERM; if (len > XATTR_SIZE_MAX) @@ -565,6 +569,8 @@ xfs_attrmulti_attr_remove( char *name, __uint32_t flags) { + if (IS_RDONLY(inode)) + return -EROFS; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return EPERM; return xfs_attr_remove(XFS_I(inode), name, flags); @@ -574,7 +580,6 @@ STATIC int xfs_attrmulti_by_handle( xfs_mount_t *mp, void __user *arg, - struct file *parfilp, struct inode *parinode) { int error; @@ -628,21 +633,13 @@ xfs_attrmulti_by_handle( &ops[i].am_length, ops[i].am_flags); break; case ATTR_OP_SET: - ops[i].am_error = mnt_want_write(parfilp->f_path.mnt); - if (ops[i].am_error) - break; ops[i].am_error = xfs_attrmulti_attr_set(inode, attr_name, ops[i].am_attrvalue, ops[i].am_length, ops[i].am_flags); - mnt_drop_write(parfilp->f_path.mnt); break; case ATTR_OP_REMOVE: - ops[i].am_error = mnt_want_write(parfilp->f_path.mnt); - if (ops[i].am_error) - break; ops[i].am_error = xfs_attrmulti_attr_remove(inode, attr_name, ops[i].am_flags); - mnt_drop_write(parfilp->f_path.mnt); break; default: ops[i].am_error = EINVAL; @@ -1333,7 +1330,7 @@ xfs_ioctl( unsigned int cmd, void __user *arg) { - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; xfs_mount_t *mp = ip->i_mount; int error; @@ -1433,7 +1430,7 @@ xfs_ioctl( return xfs_attrlist_by_handle(mp, arg, inode); case XFS_IOC_ATTRMULTI_BY_HANDLE: - return xfs_attrmulti_by_handle(mp, arg, filp, inode); + return xfs_attrmulti_by_handle(mp, arg, inode); case XFS_IOC_SWAPEXT: { error = xfs_swapext((struct xfs_swapext __user *)arg); diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index a4b254e..d5b5023 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -374,7 +374,7 @@ xfs_compat_ioctl( unsigned cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; + struct inode *inode = file->f_dentry->d_inode; int error; switch (cmd) { diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 095d271..c2233ec 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -101,6 +101,13 @@ xfs_ichgtime( tv = current_fs_time(inode->i_sb); + /* + * We're not supposed to change timestamps in readonly-mounted + * filesystems. Throw it away if anyone asks us. + */ + if (unlikely(IS_RDONLY(inode))) + return; + if ((flags & XFS_ICHGTIME_MOD) && !timespec_equal(&inode->i_mtime, &tv)) { inode->i_mtime = tv; @@ -529,7 +536,8 @@ xfs_check_acl( STATIC int xfs_vn_permission( struct inode *inode, - int mask) + int mask, + struct nameidata *nd) { return generic_permission(inode, mask, xfs_check_acl); } @@ -661,7 +669,7 @@ out_error: return error; } -static const struct inode_operations xfs_inode_operations = { +static struct inode_operations xfs_inode_operations = { .permission = xfs_vn_permission, .truncate = xfs_vn_truncate, .getattr = xfs_vn_getattr, @@ -673,7 +681,7 @@ static const struct inode_operations xfs_inode_operations = { .fallocate = xfs_vn_fallocate, }; -static const struct inode_operations xfs_dir_inode_operations = { +static struct inode_operations xfs_dir_inode_operations = { .create = xfs_vn_create, .lookup = xfs_vn_lookup, .link = xfs_vn_link, @@ -698,7 +706,7 @@ static const struct inode_operations xfs_dir_inode_operations = { .listxattr = xfs_vn_listxattr, }; -static const struct inode_operations xfs_dir_ci_inode_operations = { +static struct inode_operations xfs_dir_ci_inode_operations = { .create = xfs_vn_create, .lookup = xfs_vn_ci_lookup, .link = xfs_vn_link, @@ -723,7 +731,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { .listxattr = xfs_vn_listxattr, }; -static const struct inode_operations xfs_symlink_inode_operations = { +static struct inode_operations xfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = xfs_vn_follow_link, .put_link = xfs_vn_put_link, diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index cc0f7b3..bbb83d7 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h @@ -51,7 +51,6 @@ #include <support/debug.h> #include <support/uuid.h> -#include <linux/semaphore.h> #include <linux/mm.h> #include <linux/kernel.h> #include <linux/blkdev.h> @@ -180,6 +179,8 @@ #define xfs_itruncate_data(ip, off) \ (-vmtruncate(VFS_I(ip), (off))) +#include <linux/net.h> +#define random32() net_random() /* Move the kernel do_div definition off to one side */ diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 1957e53..617788f 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c @@ -256,7 +256,7 @@ xfs_read( (void *)iovp, segs, *offset, ioflags); iocb->ki_pos = *offset; - ret = generic_file_aio_read(iocb, iovp, segs, *offset); + ret = __generic_file_aio_read(iocb, iovp, segs, offset); if (ret == -EIOCBQUEUED && !(ioflags & IO_ISAIO)) ret = wait_on_sync_kiocb(iocb); if (ret > 0) @@ -668,14 +668,8 @@ start: if (new_size > xip->i_size) xip->i_new_size = new_size; - /* - * We're not supposed to change timestamps in readonly-mounted - * filesystems. Throw it away if anyone asks us. - */ - if (likely(!(ioflags & IO_INVIS) && - !mnt_want_write(file->f_path.mnt))) { + if (likely(!(ioflags & IO_INVIS))) { xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - mnt_drop_write(file->f_path.mnt); } /* @@ -709,7 +703,7 @@ start: !capable(CAP_FSETID)) { error = xfs_write_clear_setuid(xip); if (likely(!error)) - error = -file_remove_suid(file); + error = -remove_suid(file->f_dentry); if (unlikely(error)) { goto out_unlock_internal; } diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index e6be37d..4ae0a55 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h @@ -50,6 +50,7 @@ struct xfs_iomap; #define XFS_INVAL_CACHED 18 #define XFS_DIORD_ENTER 19 #define XFS_DIOWR_ENTER 20 +#define XFS_SENDFILE_ENTER 21 #define XFS_WRITEPAGE_ENTER 22 #define XFS_RELEASEPAGE_ENTER 23 #define XFS_INVALIDPAGE_ENTER 24 diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 37ebe36..ab10491 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -65,7 +65,6 @@ #include <linux/mempool.h> #include <linux/writeback.h> #include <linux/kthread.h> -#include <linux/freezer.h> #include <linux/parser.h> static struct quotactl_ops xfs_quotactl_operations; @@ -158,7 +157,7 @@ enum { Opt_barrier, Opt_nobarrier, Opt_err }; -static const match_table_t tokens = { +static match_table_t tokens = { {Opt_barrier, "barrier"}, {Opt_nobarrier, "nobarrier"}, {Opt_err, NULL} @@ -589,7 +588,7 @@ xfs_blkdev_get( { int error = 0; - *bdevp = open_bdev_exclusive(name, FMODE_READ|FMODE_WRITE, mp); + *bdevp = open_bdev_excl(name, 0, mp); if (IS_ERR(*bdevp)) { error = PTR_ERR(*bdevp); printk("XFS: Invalid device [%s], error=%d\n", name, error); @@ -603,7 +602,7 @@ xfs_blkdev_put( struct block_device *bdev) { if (bdev) - close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE); + close_bdev_excl(bdev); } /* @@ -882,9 +881,13 @@ xfs_fs_destroy_inode( STATIC void xfs_fs_inode_init_once( - void *vnode) + void *vnode, + kmem_zone_t *zonep, + unsigned long flags) { - inode_init_once((struct inode *)vnode); + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) + inode_init_once((struct inode *)vnode); } /* @@ -1044,7 +1047,6 @@ xfssyncd( bhv_vfs_sync_work_t *work, *n; LIST_HEAD (tmp); - set_freezable(); timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); for (;;) { timeleft = schedule_timeout_interruptible(timeleft); @@ -1866,7 +1868,7 @@ static struct file_system_type xfs_fs_type = { .name = "xfs", .get_sb = xfs_fs_get_sb, .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, + .fs_flags = FS_REQUIRES_DEV|FS_HAS_FALLOCATE, }; STATIC int __init diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/linux-2.6/xfs_super.h index fe2ef4e..2de6c31 100644 --- a/fs/xfs/linux-2.6/xfs_super.h +++ b/fs/xfs/linux-2.6/xfs_super.h @@ -18,8 +18,6 @@ #ifndef __XFS_SUPER_H__ #define __XFS_SUPER_H__ -#include <linux/exportfs.h> - #ifdef CONFIG_XFS_DMAPI # define vfs_insertdmapi(vfs) vfs_insertops(vfsp, &xfs_dmops) # define vfs_initdmapi() dmapi_init() @@ -106,7 +104,7 @@ extern void xfs_flush_device(struct xfs_inode *); extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); -extern const struct export_operations xfs_export_operations; +extern struct export_operations xfs_export_operations; extern struct xattr_handler *xfs_xattr_handlers[]; #define XFS_M(sb) ((struct xfs_mount *)((sb)->s_fs_info)) diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c index 7dacb5b..6e76594 100644 --- a/fs/xfs/linux-2.6/xfs_sysctl.c +++ b/fs/xfs/linux-2.6/xfs_sysctl.c @@ -262,7 +262,7 @@ static ctl_table xfs_root_table[] = { int xfs_sysctl_register(void) { - xfs_table_header = register_sysctl_table(xfs_root_table); + xfs_table_header = register_sysctl_table(xfs_root_table, 1); if (!xfs_table_header) return -ENOMEM; return 0; diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index df0ffef..e9b1f6a 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -62,6 +62,7 @@ uint ndquot; kmem_zone_t *qm_dqzone; kmem_zone_t *qm_dqtrxzone; +static struct shrinker *xfs_qm_shaker; static cred_t xfs_zerocr; @@ -77,11 +78,6 @@ STATIC int xfs_qm_init_quotainos(xfs_mount_t *); STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); STATIC int xfs_qm_shake(int, gfp_t); -static struct shrinker xfs_qm_shaker = { - .shrink = xfs_qm_shake, - .seeks = DEFAULT_SEEKS, -}; - #ifdef DEBUG extern mutex_t qcheck_lock; #endif @@ -154,7 +150,7 @@ xfs_Gqm_init(void) } else xqm->qm_dqzone = qm_dqzone; - register_shrinker(&xfs_qm_shaker); + xfs_qm_shaker = set_shrinker(DEFAULT_SEEKS, xfs_qm_shake); /* * The t_dqinfo portion of transactions. @@ -186,7 +182,7 @@ xfs_qm_destroy( ASSERT(xqm != NULL); ASSERT(xqm->qm_nrefs == 0); - unregister_shrinker(&xfs_qm_shaker); + remove_shrinker(xfs_qm_shaker); hsize = xqm->qm_dqhashmask + 1; for (i = 0; i < hsize; i++) { xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 75b0cd4..9b26919 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c @@ -91,8 +91,8 @@ xfs_swapext( goto out_put_target_file; } - ip = XFS_I(file->f_path.dentry->d_inode); - tip = XFS_I(target_file->f_path.dentry->d_inode); + ip = XFS_I(file->f_dentry->d_inode); + tip = XFS_I(target_file->f_dentry->d_inode); if (ip->i_mount != tip->i_mount) { error = XFS_ERROR(EINVAL); diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index a391b95..2c1f102 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -580,8 +580,8 @@ xfs_iformat_extents( xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip)); for (i = 0; i < nex; i++, dp++) { xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); - ep->l0 = get_unaligned_be64(&dp->l0); - ep->l1 = get_unaligned_be64(&dp->l1); + ep->l0 = be64_to_cpu(get_unaligned(&dp->l0)); + ep->l1 = be64_to_cpu(get_unaligned(&dp->l1)); } XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork); if (whichfork != XFS_DATA_FORK || @@ -1081,8 +1081,8 @@ xfs_ialloc( ip->i_d.di_onlink = 0; ip->i_d.di_nlink = nlink; ASSERT(ip->i_d.di_nlink == nlink); - ip->i_d.di_uid = current_fsuid(); - ip->i_d.di_gid = current_fsgid(); + ip->i_d.di_uid = current->fsuid; + ip->i_d.di_gid = current->fsgid; ip->i_d.di_projid = prid; memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 15f5dd2..0c1a768 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1948,6 +1948,9 @@ xfs_icsb_cpu_notify( mp = (xfs_mount_t *)container_of(nfb, xfs_mount_t, m_icsb_notifier); cntp = (xfs_icsb_cnts_t *) per_cpu_ptr(mp->m_sb_cnts, (unsigned long)hcpu); +#ifndef CPU_UP_PREPARE_FROZEN +#define CPU_UP_PREPARE_FROZEN (CPU_UP_PREPARE | CPU_TASKS_FROZEN) +#endif switch (action) { case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c index afee7eb..f9de4e4 100644 --- a/fs/xfs/xfs_mru_cache.c +++ b/fs/xfs/xfs_mru_cache.c @@ -274,10 +274,9 @@ _xfs_mru_cache_clear_reap_list( * at each interval whether there is anything we need to do. */ STATIC void -_xfs_mru_cache_reap( - struct work_struct *work) +_xfs_mru_cache_reap(void *data) { - xfs_mru_cache_t *mru = container_of(work, xfs_mru_cache_t, work.work); + xfs_mru_cache_t *mru = data; unsigned long now, next; ASSERT(mru && mru->lists); @@ -376,7 +375,7 @@ xfs_mru_cache_create( INIT_RADIX_TREE(&mru->store, GFP_ATOMIC); INIT_LIST_HEAD(&mru->reap_list); spin_lock_init(&mru->lock); - INIT_DELAYED_WORK(&mru->work, _xfs_mru_cache_reap); + INIT_WORK(&mru->work, _xfs_mru_cache_reap, mru); mru->grp_time = grp_time; mru->free_func = free_func; @@ -408,7 +407,10 @@ xfs_mru_cache_flush( spin_lock(&mru->lock); if (mru->queued) { spin_unlock(&mru->lock); - cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work); + /* HACK: cancel_rearming_delayed_work live-locks + if no work pending */ + if (delayed_work_pending(&mru->work)) + cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work); spin_lock(&mru->lock); } diff --git a/fs/xfs/xfs_mru_cache.h b/fs/xfs/xfs_mru_cache.h index dd58ea1..2d195eb 100644 --- a/fs/xfs/xfs_mru_cache.h +++ b/fs/xfs/xfs_mru_cache.h @@ -33,7 +33,7 @@ typedef struct xfs_mru_cache unsigned int lru_grp; /* Group containing time zero. */ unsigned long time_zero; /* Time first element was added. */ xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */ - struct delayed_work work; /* Workqueue data for reaping. */ + struct work_struct work; /* Workqueue data for reaping. */ unsigned int queued; /* work has been queued */ } xfs_mru_cache_t; diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 8b6812f..3bc89c8 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -182,7 +182,7 @@ xfs_setattr( xfs_ilock(ip, lock_flags); /* boolean: are we the file owner? */ - file_owner = (current_fsuid() == ip->i_d.di_uid); + file_owner = (current->fsuid == ip->i_d.di_uid); /* * Change various properties of a file. @@ -1533,7 +1533,7 @@ xfs_create( * Make sure that we have allocated dquot(s) on disk. */ error = XFS_QM_DQVOPALLOC(mp, dp, - current_fsuid(), current_fsgid(), prid, + current->fsuid, current->fsgid, prid, XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp); if (error) goto std_return; @@ -2277,7 +2277,7 @@ xfs_mkdir( * Make sure that we have allocated dquot(s) on disk. */ error = XFS_QM_DQVOPALLOC(mp, dp, - current_fsuid(), current_fsgid(), prid, + current->fsuid, current->fsgid, prid, XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); if (error) goto std_return; @@ -2503,7 +2503,7 @@ xfs_symlink( * Make sure that we have allocated dquot(s) on disk. */ error = XFS_QM_DQVOPALLOC(mp, dp, - current_fsuid(), current_fsgid(), prid, + current->fsuid, current->fsgid, prid, XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); if (error) goto std_return;