diff options
| author | Linus Torvalds <torvalds@home.transmeta.com> | 2002-12-14 20:29:45 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-12-14 20:29:45 -0800 |
| commit | d1e652c708a4b42fba7fdae96d673d80c383dfa8 (patch) | |
| tree | 244db5a3876624d1f9c7ac44683d308d3c83bd02 | |
| parent | bda0e9568615f5af3bd927420f6deb2d1d7773ac (diff) | |
| parent | 8c88cd21b9eccf0b65591056531eba0998212a56 (diff) | |
Merge master.kernel.org:/home/hch/BK/xfs/linux-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
| -rw-r--r-- | fs/block_dev.c | 80 | ||||
| -rw-r--r-- | fs/super.c | 59 | ||||
| -rw-r--r-- | fs/xfs/linux/xfs_linux.h | 1 | ||||
| -rw-r--r-- | fs/xfs/linux/xfs_lrw.c | 26 | ||||
| -rw-r--r-- | fs/xfs/linux/xfs_lrw.h | 3 | ||||
| -rw-r--r-- | fs/xfs/linux/xfs_super.c | 33 | ||||
| -rw-r--r-- | fs/xfs/linux/xfs_super.h | 4 | ||||
| -rw-r--r-- | fs/xfs/pagebuf/page_buf.c | 203 | ||||
| -rw-r--r-- | fs/xfs/pagebuf/page_buf.h | 18 | ||||
| -rw-r--r-- | fs/xfs/pagebuf/page_buf_internal.h | 26 | ||||
| -rw-r--r-- | fs/xfs/pagebuf/page_buf_locking.c | 8 | ||||
| -rw-r--r-- | fs/xfs/xfs_mount.h | 5 | ||||
| -rw-r--r-- | fs/xfs/xfs_vfsops.c | 30 | ||||
| -rw-r--r-- | fs/xfs/xfs_vnodeops.c | 1 | ||||
| -rw-r--r-- | fs/xfs/xfsidbg.c | 44 | ||||
| -rw-r--r-- | include/linux/fs.h | 7 | ||||
| -rw-r--r-- | kernel/ksyms.c | 2 |
17 files changed, 241 insertions, 309 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 8715fead5101..e6fc5b1984e3 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -22,6 +22,7 @@ #include <linux/mpage.h> #include <linux/mount.h> #include <linux/uio.h> +#include <linux/namei.h> #include <asm/uaccess.h> @@ -796,3 +797,82 @@ const char *__bdevname(dev_t dev) sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev)); return buffer; } + +/** + * open_bdev_excl - open a block device by name and set it up for use + * + * @path: special file representing the block device + * @flags: %MS_RDONLY for opening read-only + * @kind: usage (same as the 4th paramter to blkdev_get) + * @holder: owner for exclusion + * + * Open the blockdevice described by the special file at @path, claim it + * for the @holder and properly set it up for @kind usage. + */ +struct block_device *open_bdev_excl(const char *path, int flags, + int kind, void *holder) +{ + struct inode *inode; + struct block_device *bdev; + struct nameidata nd; + mode_t mode = FMODE_READ; + int error = 0; + + if (!path || !*path) + return ERR_PTR(-EINVAL); + + error = path_lookup(path, LOOKUP_FOLLOW, &nd); + if (error) + return ERR_PTR(error); + + inode = nd.dentry->d_inode; + error = -ENOTBLK; + if (!S_ISBLK(inode->i_mode)) + goto path_release; + error = -EACCES; + if (nd.mnt->mnt_flags & MNT_NODEV) + goto path_release; + error = bd_acquire(inode); + if (error) + goto path_release; + bdev = inode->i_bdev; + + /* Done with lookups */ + path_release(&nd); + + if (!(flags & MS_RDONLY)) + mode |= FMODE_WRITE; + error = blkdev_get(bdev, mode, 0, kind); + if (error) + return ERR_PTR(error); + error = -EACCES; + if (!(flags & MS_RDONLY) && bdev_read_only(bdev)) + goto blkdev_put; + error = bd_claim(bdev, holder); + if (error) + goto blkdev_put; + + return bdev; + +blkdev_put: + blkdev_put(bdev, BDEV_FS); + return ERR_PTR(error); + +path_release: + path_release(&nd); + return ERR_PTR(error); +} + +/** + * close_bdev_excl - release a blockdevice openen by open_bdev_excl() + * + * @bdev: blockdevice to close + * @kind: usage (same as the 4th paramter to blkdev_get) + * + * This is the counterpart to open_bdev_excl(). + */ +void close_bdev_excl(struct block_device *bdev, int kind) +{ + bd_release(bdev); + blkdev_put(bdev, kind); +} diff --git a/fs/super.c b/fs/super.c index 8d21baaec70e..0840ecf9590f 100644 --- a/fs/super.c +++ b/fs/super.c @@ -505,55 +505,25 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type, int flags, char *dev_name, void * data, int (*fill_super)(struct super_block *, void *, int)) { - struct inode *inode; struct block_device *bdev; - struct super_block * s; - struct nameidata nd; + struct super_block *s; int error = 0; - mode_t mode = FMODE_READ; /* we always need it ;-) */ - /* What device it is? */ - if (!dev_name || !*dev_name) - return ERR_PTR(-EINVAL); - error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); - if (error) - return ERR_PTR(error); - inode = nd.dentry->d_inode; - error = -ENOTBLK; - if (!S_ISBLK(inode->i_mode)) - goto out; - error = -EACCES; - if (nd.mnt->mnt_flags & MNT_NODEV) - goto out; - error = bd_acquire(inode); - if (error) - goto out; - bdev = inode->i_bdev; - /* Done with lookups, semaphore down */ - if (!(flags & MS_RDONLY)) - mode |= FMODE_WRITE; - error = blkdev_get(bdev, mode, 0, BDEV_FS); - if (error) - goto out; - error = -EACCES; - if (!(flags & MS_RDONLY) && bdev_read_only(bdev)) - goto out1; - error = bd_claim(bdev, fs_type); - if (error) - goto out1; + bdev = open_bdev_excl(dev_name, flags, BDEV_FS, fs_type); + if (IS_ERR(bdev)) + return (struct super_block *)bdev; s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); - if (IS_ERR(s)) { - bd_release(bdev); - blkdev_put(bdev, BDEV_FS); - } else if (s->s_root) { + if (IS_ERR(s)) + goto out; + + if (s->s_root) { if ((flags ^ s->s_flags) & MS_RDONLY) { up_write(&s->s_umount); deactivate_super(s); s = ERR_PTR(-EBUSY); } - bd_release(bdev); - blkdev_put(bdev, BDEV_FS); + goto out; } else { s->s_flags = flags; strncpy(s->s_id, bdevname(bdev), sizeof(s->s_id)); @@ -567,14 +537,12 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type, } else s->s_flags |= MS_ACTIVE; } - path_release(&nd); + return s; -out1: - blkdev_put(bdev, BDEV_FS); out: - path_release(&nd); - return ERR_PTR(error); + close_bdev_excl(bdev, BDEV_FS); + return s; } void kill_block_super(struct super_block *sb) @@ -582,8 +550,7 @@ void kill_block_super(struct super_block *sb) struct block_device *bdev = sb->s_bdev; generic_shutdown_super(sb); set_blocksize(bdev, sb->s_old_blocksize); - bd_release(bdev); - blkdev_put(bdev, BDEV_FS); + close_bdev_excl(bdev, BDEV_FS); } struct super_block *get_sb_nodev(struct file_system_type *fs_type, diff --git a/fs/xfs/linux/xfs_linux.h b/fs/xfs/linux/xfs_linux.h index 0a69bc4dc075..3920a9cf575f 100644 --- a/fs/xfs/linux/xfs_linux.h +++ b/fs/xfs/linux/xfs_linux.h @@ -42,7 +42,6 @@ #include <linux/sched.h> #include <linux/bitops.h> #include <linux/major.h> -#include <linux/root_dev.h> #include <asm/page.h> #include <asm/div64.h> diff --git a/fs/xfs/linux/xfs_lrw.c b/fs/xfs/linux/xfs_lrw.c index 26971490f340..8eca91aff8cb 100644 --- a/fs/xfs/linux/xfs_lrw.c +++ b/fs/xfs/linux/xfs_lrw.c @@ -215,54 +215,46 @@ xfs_sendfile( void *target, cred_t *credp) { - size_t size = 0; ssize_t ret; xfs_fsize_t n; xfs_inode_t *ip; - xfs_mount_t *mp; vnode_t *vp; + int invisible = (filp->f_mode & FINVIS); ip = XFS_BHVTOI(bdp); vp = BHV_TO_VNODE(bdp); - mp = ip->i_mount; vn_trace_entry(vp, "xfs_sendfile", (inst_t *)__return_address); XFS_STATS_INC(xfsstats.xs_read_calls); n = XFS_MAX_FILE_OFFSET - *offp; - if ((n <= 0) || (size == 0)) + if ((n <= 0) || (count == 0)) return 0; - if (n < size) - size = n; + if (n < count) + count = n; - if (XFS_FORCED_SHUTDOWN(mp)) { + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return -EIO; - } xfs_ilock(ip, XFS_IOLOCK_SHARED); - - if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && - !(filp->f_mode & FINVIS)) { - int error; + if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && !invisible) { vrwlock_t locktype = VRWLOCK_READ; + int error; error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, *offp, - size, FILP_DELAY_FLAG(filp), &locktype); + count, FILP_DELAY_FLAG(filp), &locktype); if (error) { xfs_iunlock(ip, XFS_IOLOCK_SHARED); return -error; } } - ret = generic_file_sendfile(filp, offp, count, actor, target); xfs_iunlock(ip, XFS_IOLOCK_SHARED); XFS_STATS_ADD(xfsstats.xs_read_bytes, ret); - - if (!(filp->f_mode & FINVIS)) + if (!invisible) xfs_ichgtime(ip, XFS_ICHGTIME_ACC); - return ret; } diff --git a/fs/xfs/linux/xfs_lrw.h b/fs/xfs/linux/xfs_lrw.h index 41a5dfd2f15e..1cd362bb5e4c 100644 --- a/fs/xfs/linux/xfs_lrw.h +++ b/fs/xfs/linux/xfs_lrw.h @@ -58,6 +58,9 @@ extern ssize_t xfs_read (struct bhv_desc *, struct file *, extern ssize_t xfs_write (struct bhv_desc *, struct file *, const struct iovec *, unsigned long, loff_t *, struct cred *); +extern ssize_t xfs_sendfile (struct bhv_desc *, struct file *, + loff_t *, size_t, read_actor_t, + void *, struct cred *); extern int xfs_dev_is_read_only (struct xfs_mount *, char *); diff --git a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c index 7db1cfd5b6ee..f542425c7555 100644 --- a/fs/xfs/linux/xfs_super.c +++ b/fs/xfs/linux/xfs_super.c @@ -468,27 +468,18 @@ xfs_initialize_vnode( int xfs_blkdev_get( + xfs_mount_t *mp, const char *name, struct block_device **bdevp) { - struct nameidata nd; - int error; + int error = 0; - error = path_lookup(name, LOOKUP_FOLLOW, &nd); - if (error) { + *bdevp = open_bdev_excl(name, 0, BDEV_FS, mp); + if (IS_ERR(*bdevp)) { + error = PTR_ERR(*bdevp); printk("XFS: Invalid device [%s], error=%d\n", name, error); - return -error; - } - - /* I think we actually want bd_acquire here.. --hch */ - *bdevp = bdget(kdev_t_to_nr(nd.dentry->d_inode->i_rdev)); - if (*bdevp) { - error = blkdev_get(*bdevp, FMODE_READ|FMODE_WRITE, 0, BDEV_FS); - } else { - error = -ENOMEM; } - path_release(&nd); return -error; } @@ -497,7 +488,7 @@ xfs_blkdev_put( struct block_device *bdev) { if (bdev) - blkdev_put(bdev, BDEV_FS); + close_bdev_excl(bdev, BDEV_FS); } void @@ -762,17 +753,6 @@ linvfs_clear_inode( } STATIC void -linvfs_put_inode( - struct inode *ip) -{ - vnode_t *vp = LINVFS_GET_VP(ip); - int error; - - if (vp && vp->v_fbhv && (atomic_read(&ip->i_count) == 1)) - VOP_RELEASE(vp, error); -} - -STATIC void linvfs_put_super( struct super_block *sb) { @@ -989,7 +969,6 @@ STATIC struct super_operations linvfs_sops = { .alloc_inode = linvfs_alloc_inode, .destroy_inode = linvfs_destroy_inode, .write_inode = linvfs_write_inode, - .put_inode = linvfs_put_inode, .clear_inode = linvfs_clear_inode, .put_super = linvfs_put_super, .write_super = linvfs_write_super, diff --git a/fs/xfs/linux/xfs_super.h b/fs/xfs/linux/xfs_super.h index 6df2a9b07b7e..ec38e001e909 100644 --- a/fs/xfs/linux/xfs_super.h +++ b/fs/xfs/linux/xfs_super.h @@ -78,12 +78,14 @@ #define LINVFS_SET_VFS(s, vfsp) \ ((s)->s_fs_info = vfsp) +struct xfs_mount; struct pb_target; struct block_device; extern void xfs_initialize_vnode (bhv_desc_t *, vnode_t *, bhv_desc_t *, int); -extern int xfs_blkdev_get (const char *, struct block_device **); +extern int xfs_blkdev_get (struct xfs_mount *, const char *, + struct block_device **); extern void xfs_blkdev_put (struct block_device *); extern struct pb_target *xfs_alloc_buftarg (struct block_device *); diff --git a/fs/xfs/pagebuf/page_buf.c b/fs/xfs/pagebuf/page_buf.c index 4c6a7dad951d..6c1b1b2760e0 100644 --- a/fs/xfs/pagebuf/page_buf.c +++ b/fs/xfs/pagebuf/page_buf.c @@ -104,7 +104,7 @@ pb_trace_func( pb_trace.buf[j].event = event; pb_trace.buf[j].flags = pb->pb_flags; pb_trace.buf[j].hold = pb->pb_hold.counter; - pb_trace.buf[j].lock_value = PBP(pb)->pb_sema.count.counter; + pb_trace.buf[j].lock_value = pb->pb_sema.count.counter; pb_trace.buf[j].task = (void *)current; pb_trace.buf[j].misc = misc; pb_trace.buf[j].ra = ra; @@ -118,7 +118,6 @@ pb_trace_func( */ STATIC kmem_cache_t *pagebuf_cache; -STATIC pagebuf_daemon_t *pb_daemon; STATIC void pagebuf_daemon_wakeup(int); STATIC struct workqueue_struct *pagebuf_workqueue; @@ -272,12 +271,12 @@ _pagebuf_initialize( */ flags &= ~(PBF_LOCK|PBF_MAPPED|PBF_DONT_BLOCK|PBF_READ_AHEAD); - memset(pb, 0, sizeof(page_buf_private_t)); + memset(pb, 0, sizeof(page_buf_t)); atomic_set(&pb->pb_hold, 1); init_MUTEX_LOCKED(&pb->pb_iodonesema); INIT_LIST_HEAD(&pb->pb_list); INIT_LIST_HEAD(&pb->pb_hash_list); - init_MUTEX_LOCKED(&PBP(pb)->pb_sema); /* held, no waiters */ + init_MUTEX_LOCKED(&pb->pb_sema); /* held, no waiters */ PB_SET_OWNER(pb); pb->pb_target = target; pb->pb_file_offset = range_base; @@ -289,8 +288,8 @@ _pagebuf_initialize( pb->pb_buffer_length = pb->pb_count_desired = range_length; pb->pb_flags = flags | PBF_NONE; pb->pb_bn = PAGE_BUF_DADDR_NULL; - atomic_set(&PBP(pb)->pb_pin_count, 0); - init_waitqueue_head(&PBP(pb)->pb_waiters); + atomic_set(&pb->pb_pin_count, 0); + init_waitqueue_head(&pb->pb_waiters); PB_STATS_INC(pbstats.pb_create); PB_TRACE(pb, PB_TRACE_REC(get), target); @@ -657,7 +656,7 @@ found: * if this does not work then we need to drop the * spinlock and do a hard attempt on the semaphore. */ - not_locked = down_trylock(&PBP(pb)->pb_sema); + not_locked = down_trylock(&pb->pb_sema); if (not_locked) { if (!(flags & PBF_TRYLOCK)) { /* wait for buffer ownership */ @@ -788,28 +787,6 @@ pagebuf_get( /* allocate a buffer */ } /* - * Create a pagebuf and populate it with pages from the address - * space of the passed in inode. - */ -page_buf_t * -pagebuf_lookup( - struct pb_target *target, - struct inode *inode, - loff_t ioff, - size_t isize, - page_buf_flags_t flags) -{ - page_buf_t *pb = NULL; - - flags |= _PBF_PRIVATE_BH; - pb = pagebuf_allocate(flags); - if (pb) { - _pagebuf_initialize(pb, target, ioff, isize, flags); - } - return pb; -} - -/* * If we are not low on memory then do the readahead in a deadlock * safe manner. */ @@ -906,7 +883,7 @@ pagebuf_associate_memory( pb->pb_locked = 0; pb->pb_count_desired = pb->pb_buffer_length = len; - pb->pb_flags |= PBF_MAPPED | _PBF_PRIVATE_BH; + pb->pb_flags |= PBF_MAPPED; return 0; } @@ -952,7 +929,7 @@ pagebuf_get_no_daddr( /* otherwise pagebuf_free just ignores it */ pb->pb_flags |= _PBF_MEM_ALLOCATED; PB_CLEAR_OWNER(pb); - up(&PBP(pb)->pb_sema); /* Return unlocked pagebuf */ + up(&pb->pb_sema); /* Return unlocked pagebuf */ PB_TRACE(pb, PB_TRACE_REC(no_daddr), rmem); @@ -1070,8 +1047,8 @@ void pagebuf_pin( page_buf_t *pb) { - atomic_inc(&PBP(pb)->pb_pin_count); - PB_TRACE(pb, PB_TRACE_REC(pin), PBP(pb)->pb_pin_count.counter); + atomic_inc(&pb->pb_pin_count); + PB_TRACE(pb, PB_TRACE_REC(pin), pb->pb_pin_count.counter); } /* @@ -1085,17 +1062,17 @@ void pagebuf_unpin( page_buf_t *pb) { - if (atomic_dec_and_test(&PBP(pb)->pb_pin_count)) { - wake_up_all(&PBP(pb)->pb_waiters); + if (atomic_dec_and_test(&pb->pb_pin_count)) { + wake_up_all(&pb->pb_waiters); } - PB_TRACE(pb, PB_TRACE_REC(unpin), PBP(pb)->pb_pin_count.counter); + PB_TRACE(pb, PB_TRACE_REC(unpin), pb->pb_pin_count.counter); } int pagebuf_ispin( page_buf_t *pb) { - return atomic_read(&PBP(pb)->pb_pin_count); + return atomic_read(&pb->pb_pin_count); } /* @@ -1111,19 +1088,19 @@ _pagebuf_wait_unpin( { DECLARE_WAITQUEUE (wait, current); - if (atomic_read(&PBP(pb)->pb_pin_count) == 0) + if (atomic_read(&pb->pb_pin_count) == 0) return; - add_wait_queue(&PBP(pb)->pb_waiters, &wait); + add_wait_queue(&pb->pb_waiters, &wait); for (;;) { current->state = TASK_UNINTERRUPTIBLE; - if (atomic_read(&PBP(pb)->pb_pin_count) == 0) { + if (atomic_read(&pb->pb_pin_count) == 0) { break; } pagebuf_run_queues(pb); schedule(); } - remove_wait_queue(&PBP(pb)->pb_waiters, &wait); + remove_wait_queue(&pb->pb_waiters, &wait); current->state = TASK_RUNNING; } @@ -1503,44 +1480,6 @@ pagebuf_offset( } /* - * pagebuf_segment - * - * pagebuf_segment is used to retrieve the various contiguous - * segments of a buffer. The variable addressed by the - * loff_t * should be initialized to 0, and successive - * calls will update to point to the segment following the one - * returned. - */ -STATIC void -pagebuf_segment( - page_buf_t *pb, /* buffer to examine */ - loff_t *boff_p,/* offset in buffer of next */ - /* next segment (updated) */ - struct page **spage_p, /* page (updated) */ - /* (NULL if not in page array) */ - size_t *soff_p,/* offset in page (updated) */ - size_t *ssize_p) /* segment length (updated) */ -{ - loff_t kpboff; /* offset in pagebuf */ - int kpi; /* page index in pagebuf */ - size_t slen; /* segment length */ - - kpboff = *boff_p; - - kpi = page_buf_btoct(kpboff + pb->pb_offset); - - *spage_p = pb->pb_pages[kpi]; - - *soff_p = page_buf_poff(kpboff + pb->pb_offset); - slen = PAGE_CACHE_SIZE - *soff_p; - if (slen > (pb->pb_count_desired - kpboff)) - slen = (pb->pb_count_desired - kpboff); - *ssize_p = slen; - - *boff_p = *boff_p + slen; -} - -/* * pagebuf_iomove * * Move data into or out of a buffer. @@ -1548,21 +1487,21 @@ pagebuf_segment( void pagebuf_iomove( page_buf_t *pb, /* buffer to process */ - off_t boff, /* starting buffer offset */ + size_t boff, /* starting buffer offset */ size_t bsize, /* length to copy */ caddr_t data, /* data address */ page_buf_rw_t mode) /* read/write flag */ { - loff_t cboff; - size_t cpoff; - size_t csize; + size_t bend, cpoff, csize; struct page *page; - cboff = boff; - boff += bsize; /* last */ + bend = boff + bsize; + while (boff < bend) { + page = pb->pb_pages[page_buf_btoct(boff + pb->pb_offset)]; + cpoff = page_buf_poff(boff + pb->pb_offset); + csize = min_t(size_t, + PAGE_CACHE_SIZE-cpoff, pb->pb_count_desired-boff); - while (cboff < boff) { - pagebuf_segment(pb, &cboff, &page, &cpoff, &csize); ASSERT(((csize + cpoff) <= PAGE_CACHE_SIZE)); switch (mode) { @@ -1576,6 +1515,7 @@ pagebuf_iomove( memcpy(page_address(page) + cpoff, data, csize); } + boff += csize; data += csize; } } @@ -1584,13 +1524,17 @@ pagebuf_iomove( * Pagebuf delayed write buffer handling */ +STATIC int pbd_active = 1; +STATIC LIST_HEAD(pbd_delwrite_queue); +STATIC spinlock_t pbd_delwrite_lock = SPIN_LOCK_UNLOCKED; + void pagebuf_delwri_queue( page_buf_t *pb, int unlock) { PB_TRACE(pb, PB_TRACE_REC(delwri_q), unlock); - spin_lock(&pb_daemon->pb_delwrite_lock); + spin_lock(&pbd_delwrite_lock); /* If already in the queue, dequeue and place at tail */ if (!list_empty(&pb->pb_list)) { if (unlock) { @@ -1599,9 +1543,9 @@ pagebuf_delwri_queue( list_del(&pb->pb_list); } - list_add_tail(&pb->pb_list, &pb_daemon->pb_delwrite_l); - PBP(pb)->pb_flushtime = jiffies + pb_params.p_un.age_buffer; - spin_unlock(&pb_daemon->pb_delwrite_lock); + list_add_tail(&pb->pb_list, &pbd_delwrite_queue); + pb->pb_flushtime = jiffies + pb_params.p_un.age_buffer; + spin_unlock(&pbd_delwrite_lock); if (unlock && (pb->pb_flags & _PBF_LOCKABLE)) { pagebuf_unlock(pb); @@ -1613,10 +1557,10 @@ pagebuf_delwri_dequeue( page_buf_t *pb) { PB_TRACE(pb, PB_TRACE_REC(delwri_uq), 0); - spin_lock(&pb_daemon->pb_delwrite_lock); + spin_lock(&pbd_delwrite_lock); list_del_init(&pb->pb_list); pb->pb_flags &= ~PBF_DELWRI; - spin_unlock(&pb_daemon->pb_delwrite_lock); + spin_unlock(&pbd_delwrite_lock); } /* Defines for pagebuf daemon */ @@ -1659,7 +1603,7 @@ pagebuf_daemon( INIT_LIST_HEAD(&tmp); do { - if (pb_daemon->active == 1) { + if (pbd_active == 1) { del_timer(&pb_daemon_timer); pb_daemon_timer.expires = jiffies + pb_params.p_un.flush_interval; @@ -1667,14 +1611,14 @@ pagebuf_daemon( interruptible_sleep_on(&pbd_waitq); } - if (pb_daemon->active == 0) { + if (pbd_active == 0) { del_timer(&pb_daemon_timer); } - spin_lock(&pb_daemon->pb_delwrite_lock); + spin_lock(&pbd_delwrite_lock); count = 0; - list_for_each_safe(curr, next, &pb_daemon->pb_delwrite_l) { + list_for_each_safe(curr, next, &pbd_delwrite_queue) { pb = list_entry(curr, page_buf_t, pb_list); PB_TRACE(pb, PB_TRACE_REC(walkq1), pagebuf_ispin(pb)); @@ -1683,8 +1627,8 @@ pagebuf_daemon( (((pb->pb_flags & _PBF_LOCKABLE) == 0) || !pagebuf_cond_lock(pb))) { - if (!force_flush && time_before(jiffies, - PBP(pb)->pb_flushtime)) { + if (!force_flush && + time_before(jiffies, pb->pb_flushtime)) { pagebuf_unlock(pb); break; } @@ -1696,7 +1640,7 @@ pagebuf_daemon( } } - spin_unlock(&pb_daemon->pb_delwrite_lock); + spin_unlock(&pbd_delwrite_lock); while (!list_empty(&tmp)) { pb = list_entry(tmp.next, page_buf_t, pb_list); list_del_init(&pb->pb_list); @@ -1712,9 +1656,9 @@ pagebuf_daemon( pagebuf_run_queues(NULL); force_flush = 0; - } while (pb_daemon->active == 1); + } while (pbd_active == 1); - pb_daemon->active = -1; + pbd_active = -1; wake_up_interruptible(&pbd_waitq); return 0; @@ -1730,10 +1674,10 @@ pagebuf_delwri_flush( struct list_head *curr, *next, tmp; int pincount = 0; - spin_lock(&pb_daemon->pb_delwrite_lock); + spin_lock(&pbd_delwrite_lock); INIT_LIST_HEAD(&tmp); - list_for_each_safe(curr, next, &pb_daemon->pb_delwrite_l) { + list_for_each_safe(curr, next, &pbd_delwrite_queue) { pb = list_entry(curr, page_buf_t, pb_list); /* @@ -1764,7 +1708,7 @@ pagebuf_delwri_flush( pb->pb_flags &= ~PBF_ASYNC; } - spin_unlock(&pb_daemon->pb_delwrite_lock); + spin_unlock(&pbd_delwrite_lock); if ((flags & PBDF_TRYLOCK) == 0) { pagebuf_lock(pb); @@ -1775,10 +1719,10 @@ pagebuf_delwri_flush( __pagebuf_iorequest(pb); - spin_lock(&pb_daemon->pb_delwrite_lock); + spin_lock(&pbd_delwrite_lock); } - spin_unlock(&pb_daemon->pb_delwrite_lock); + spin_unlock(&pbd_delwrite_lock); pagebuf_run_queues(NULL); @@ -1802,26 +1746,17 @@ pagebuf_delwri_flush( STATIC int pagebuf_daemon_start(void) { - if (!pb_daemon) { - pb_daemon = (pagebuf_daemon_t *) - kmalloc(sizeof(pagebuf_daemon_t), GFP_KERNEL); - if (!pb_daemon) { - return -1; /* error */ - } + int rval; - pb_daemon->active = 1; - pb_daemon->pb_delwrite_lock = SPIN_LOCK_UNLOCKED; - - INIT_LIST_HEAD(&pb_daemon->pb_delwrite_l); + pagebuf_workqueue = create_workqueue("pagebuf"); + if (!pagebuf_workqueue) + return -ENOMEM; - kernel_thread(pagebuf_daemon, (void *)pb_daemon, - CLONE_FS|CLONE_FILES|CLONE_VM); + rval = kernel_thread(pagebuf_daemon, NULL, CLONE_FS|CLONE_FILES); + if (rval < 0) + destroy_workqueue(pagebuf_workqueue); - pagebuf_workqueue = create_workqueue("pagebuf"); - if (!pagebuf_workqueue) - return -1; - } - return 0; + return rval; } /* @@ -1832,19 +1767,10 @@ pagebuf_daemon_start(void) STATIC void pagebuf_daemon_stop(void) { - if (pb_daemon) { - destroy_workqueue(pagebuf_workqueue); - - pb_daemon->active = 0; - - wake_up_interruptible(&pbd_waitq); - while (pb_daemon->active == 0) { - interruptible_sleep_on(&pbd_waitq); - } - - kfree(pb_daemon); - pb_daemon = NULL; - } + pbd_active = 0; + wake_up_interruptible(&pbd_waitq); + wait_event_interruptible(pbd_waitq, pbd_active); + destroy_workqueue(pagebuf_workqueue); } @@ -1965,8 +1891,7 @@ pagebuf_init(void) "fs/pagebuf/stat", 0, 0, pagebuf_readstats, NULL); #endif - pagebuf_cache = kmem_cache_create("page_buf_t", - sizeof(page_buf_private_t), 0, + pagebuf_cache = kmem_cache_create("page_buf_t", sizeof(page_buf_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (pagebuf_cache == NULL) { printk("pagebuf: couldn't init pagebuf cache\n"); diff --git a/fs/xfs/pagebuf/page_buf.h b/fs/xfs/pagebuf/page_buf.h index b7f200be9b1c..7fc72e586fe4 100644 --- a/fs/xfs/pagebuf/page_buf.h +++ b/fs/xfs/pagebuf/page_buf.h @@ -109,7 +109,6 @@ typedef enum page_buf_flags_e { /* pb_flags values */ /* flags used only internally */ _PBF_LOCKABLE = (1 << 19), /* page_buf_t may be locked */ - _PBF_PRIVATE_BH = (1 << 20), /* do not use public buffer heads */ _PBF_ALL_PAGES_MAPPED = (1 << 21), /* all pages in rage are mapped */ _PBF_ADDR_ALLOCATED = (1 << 22), @@ -195,6 +194,10 @@ typedef int (*page_buf_bdstrat_t)(struct page_buf_s *); #define PB_PAGES 4 typedef struct page_buf_s { + struct semaphore pb_sema; /* semaphore for lockables */ + unsigned long pb_flushtime; /* time to flush pagebuf */ + atomic_t pb_pin_count; /* pin count */ + wait_queue_head_t pb_waiters; /* unpin waiters */ struct list_head pb_list; page_buf_flags_t pb_flags; /* status flags */ struct list_head pb_hash_list; @@ -221,6 +224,9 @@ typedef struct page_buf_s { unsigned char pb_hash_index; /* hash table index */ struct page **pb_pages; /* array of page pointers */ struct page *pb_page_array[PB_PAGES]; /* inline pages */ +#ifdef PAGEBUF_LOCK_TRACKING + int pb_last_holder; +#endif } page_buf_t; @@ -244,14 +250,6 @@ extern page_buf_t *pagebuf_get( /* allocate a buffer */ page_buf_flags_t); /* PBF_LOCK, PBF_READ, */ /* PBF_ASYNC */ -extern page_buf_t *pagebuf_lookup( - struct pb_target *, - struct inode *, - loff_t, /* starting offset of range */ - size_t, /* length of range */ - page_buf_flags_t); /* PBF_READ, PBF_WRITE, */ - /* PBF_FORCEIO, _PBF_LOCKABLE */ - extern page_buf_t *pagebuf_get_empty( /* allocate pagebuf struct with */ /* no memory or disk address */ struct pb_target *); /* mount point "fake" inode */ @@ -340,7 +338,7 @@ extern caddr_t pagebuf_offset(page_buf_t *, off_t); extern void pagebuf_iomove( /* move data in/out of pagebuf */ page_buf_t *, /* buffer to manipulate */ - off_t, /* starting buffer offset */ + size_t, /* starting buffer offset */ size_t, /* length in buffer */ caddr_t, /* data pointer */ page_buf_rw_t); /* direction */ diff --git a/fs/xfs/pagebuf/page_buf_internal.h b/fs/xfs/pagebuf/page_buf_internal.h index e24c7d30ddd4..775803f53cb6 100644 --- a/fs/xfs/pagebuf/page_buf_internal.h +++ b/fs/xfs/pagebuf/page_buf_internal.h @@ -48,24 +48,10 @@ #define page_has_buffers(page) ((page)->buffers) #endif -typedef struct page_buf_private_s { - page_buf_t pb_common; /* public part of structure */ - struct semaphore pb_sema; /* semaphore for lockables */ - unsigned long pb_flushtime; /* time to flush pagebuf */ - atomic_t pb_pin_count; /* pin count */ - wait_queue_head_t pb_waiters; /* unpin waiters */ #ifdef PAGEBUF_LOCK_TRACKING - int pb_last_holder; -#endif -} page_buf_private_t; - -#define PBC(pb) (&((pb)->pb_common)) -#define PBP(pb) ((page_buf_private_t *) (pb)) - -#ifdef PAGEBUF_LOCK_TRACKING -#define PB_SET_OWNER(pb) (PBP(pb)->pb_last_holder = current->pid) -#define PB_CLEAR_OWNER(pb) (PBP(pb)->pb_last_holder = -1) -#define PB_GET_OWNER(pb) (PBP(pb)->pb_last_holder) +#define PB_SET_OWNER(pb) (pb->pb_last_holder = current->pid) +#define PB_CLEAR_OWNER(pb) (pb->pb_last_holder = -1) +#define PB_GET_OWNER(pb) (pb->pb_last_holder) #else #define PB_SET_OWNER(pb) #define PB_CLEAR_OWNER(pb) @@ -95,12 +81,6 @@ struct pagebuf_trace_buf { #define PB_TRACE_BUFSIZE 1024 #define CIRC_INC(i) (((i) + 1) & (PB_TRACE_BUFSIZE - 1)) -typedef struct pagebuf_daemon { - int active; - spinlock_t pb_delwrite_lock; - struct list_head pb_delwrite_l; -} pagebuf_daemon_t; - /* * Tunable pagebuf parameters */ diff --git a/fs/xfs/pagebuf/page_buf_locking.c b/fs/xfs/pagebuf/page_buf_locking.c index f2aa771dbca1..ddd53e788a7b 100644 --- a/fs/xfs/pagebuf/page_buf_locking.c +++ b/fs/xfs/pagebuf/page_buf_locking.c @@ -75,7 +75,7 @@ pagebuf_cond_lock( /* lock buffer, if not locked */ ASSERT(pb->pb_flags & _PBF_LOCKABLE); - locked = down_trylock(&PBP(pb)->pb_sema) == 0; + locked = down_trylock(&pb->pb_sema) == 0; if (locked) { PB_SET_OWNER(pb); } @@ -95,7 +95,7 @@ pagebuf_lock_value( page_buf_t *pb) { ASSERT(pb->pb_flags & _PBF_LOCKABLE); - return(atomic_read(&PBP(pb)->pb_sema.count)); + return(atomic_read(&pb->pb_sema.count)); } /* @@ -114,7 +114,7 @@ pagebuf_lock( PB_TRACE(pb, PB_TRACE_REC(lock), 0); pagebuf_run_queues(pb); - down(&PBP(pb)->pb_sema); + down(&pb->pb_sema); PB_SET_OWNER(pb); PB_TRACE(pb, PB_TRACE_REC(locked), 0); return 0; @@ -133,6 +133,6 @@ pagebuf_unlock( /* unlock buffer */ { ASSERT(pb->pb_flags & _PBF_LOCKABLE); PB_CLEAR_OWNER(pb); - up(&PBP(pb)->pb_sema); + up(&pb->pb_sema); PB_TRACE(pb, PB_TRACE_REC(unlock), 0); } diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index db40f7d89f42..c54a9d6b286d 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -428,11 +428,6 @@ int xfs_syncsub(xfs_mount_t *, int, int, int *); void xfs_initialize_perag(xfs_mount_t *, int); void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t); -int xfs_blkdev_get(const char *, struct block_device **); -void xfs_blkdev_put(struct block_device *); -struct xfs_buftarg *xfs_alloc_buftarg(struct block_device *); -void xfs_free_buftarg(struct xfs_buftarg *); - /* * Flags for freeze operations. */ diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index 55ebda332925..3b0d0559afef 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -381,8 +381,9 @@ xfs_finish_flags( * (2) logical volume with data and log subvolumes. * (3) logical volume with data, log, and realtime subvolumes. * - * The Linux VFS took care of finding and opening the data volume for - * us. We have to handle the other two (if present) here. + * We only have to handle opening the log and realtime volumes here if + * they are present. The data subvolume has already been opened by + * get_sb_bdev() and is stored in vfsp->vfs_super->s_bdev. */ STATIC int xfs_mount( @@ -399,18 +400,23 @@ xfs_mount( logdev = rtdev = NULL; /* + * Allocate VFS private data (xfs mount structure). + */ + mp = xfs_mount_init(); + + /* * Open real time and log devices - order is important. */ if (args->logname[0]) { - error = xfs_blkdev_get(args->logname, &logdev); + error = xfs_blkdev_get(mp, args->logname, &logdev); if (error) - return error; + goto free_mp; } if (args->rtname[0]) { - error = xfs_blkdev_get(args->rtname, &rtdev); + error = xfs_blkdev_get(mp, args->rtname, &rtdev); if (error) { xfs_blkdev_put(logdev); - return error; + goto free_mp; } if (rtdev == ddev || rtdev == logdev) { @@ -418,15 +424,11 @@ xfs_mount( "XFS: Cannot mount filesystem with identical rtdev and ddev/logdev."); xfs_blkdev_put(logdev); xfs_blkdev_put(rtdev); - return EINVAL; + error = EINVAL; + goto free_mp; } } - /* - * Allocate VFS private data (xfs mount structure). - */ - mp = xfs_mount_init(); - vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp); mp->m_ddev_targp = xfs_alloc_buftarg(ddev); @@ -459,7 +461,7 @@ xfs_mount( xfs_size_buftarg(mp->m_logdev_targp, mp->m_sb.sb_blocksize, ss); } if (rtdev) - xfs_size_buftarg(mp->m_logdev_targp, mp->m_sb.sb_blocksize, + xfs_size_buftarg(mp->m_rtdev_targp, mp->m_sb.sb_blocksize, mp->m_sb.sb_blocksize); error = xfs_mountfs(vfsp, mp, ddev->bd_dev, flags); @@ -476,6 +478,8 @@ xfs_mount( xfs_binval(mp->m_rtdev_targp); } xfs_unmountfs_close(mp, NULL); + + free_mp: xfs_mount_free(mp, 1); return error; } diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index bc25a4f8944c..9674a62362a0 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -4870,6 +4870,7 @@ vnodeops_t xfs_vnodeops = { BHV_IDENTITY_INIT(VN_BHV_XFS,VNODE_POSITION_XFS), .vop_open = xfs_open, .vop_read = xfs_read, + .vop_sendfile = xfs_sendfile, .vop_write = xfs_write, .vop_ioctl = xfs_ioctl, .vop_getattr = xfs_getattr, diff --git a/fs/xfs/xfsidbg.c b/fs/xfs/xfsidbg.c index cdff412b061e..3f974721030b 100644 --- a/fs/xfs/xfsidbg.c +++ b/fs/xfs/xfsidbg.c @@ -1793,7 +1793,7 @@ kdbm_pb_flags(int argc, const char **argv, const char **envp, struct pt_regs *re static int kdbm_pb(int argc, const char **argv, const char **envp, struct pt_regs *regs) { - page_buf_private_t bp; + page_buf_t bp; unsigned long addr; long offset=0; int nextarg; @@ -1808,43 +1808,43 @@ kdbm_pb(int argc, const char **argv, const char **envp, struct pt_regs *regs) return diag; kdb_printf("page_buf_t at 0x%lx\n", addr); - kdb_printf(" pb_flags %s\n", pb_flags(bp.pb_common.pb_flags)); + kdb_printf(" pb_flags %s\n", pb_flags(bp.pb_flags)); kdb_printf(" pb_target 0x%p pb_hold %d pb_next 0x%p pb_prev 0x%p\n", - bp.pb_common.pb_target, bp.pb_common.pb_hold.counter, - bp.pb_common.pb_list.next, bp.pb_common.pb_list.prev); + bp.pb_target, bp.pb_hold.counter, + bp.pb_list.next, bp.pb_list.prev); kdb_printf(" pb_hash_index %d pb_hash_next 0x%p pb_hash_prev 0x%p\n", - bp.pb_common.pb_hash_index, - bp.pb_common.pb_hash_list.next, - bp.pb_common.pb_hash_list.prev); + bp.pb_hash_index, + bp.pb_hash_list.next, + bp.pb_hash_list.prev); kdb_printf(" pb_file_offset 0x%llx pb_buffer_length 0x%llx pb_addr 0x%p\n", - (unsigned long long) bp.pb_common.pb_file_offset, - (unsigned long long) bp.pb_common.pb_buffer_length, - bp.pb_common.pb_addr); + (unsigned long long) bp.pb_file_offset, + (unsigned long long) bp.pb_buffer_length, + bp.pb_addr); kdb_printf(" pb_bn 0x%Lx pb_count_desired 0x%lx\n", - bp.pb_common.pb_bn, - (unsigned long) bp.pb_common.pb_count_desired); + bp.pb_bn, + (unsigned long) bp.pb_count_desired); kdb_printf(" pb_io_remaining %d pb_error %u\n", - bp.pb_common.pb_io_remaining.counter, - bp.pb_common.pb_error); + bp.pb_io_remaining.counter, + bp.pb_error); kdb_printf(" pb_page_count %u pb_offset 0x%x pb_pages 0x%p\n", - bp.pb_common.pb_page_count, bp.pb_common.pb_offset, - bp.pb_common.pb_pages); + bp.pb_page_count, bp.pb_offset, + bp.pb_pages); #ifdef PAGEBUF_LOCK_TRACKING kdb_printf(" pb_iodonesema (%d,%d) pb_sema (%d,%d) pincount (%d) last holder %d\n", - bp.pb_common.pb_iodonesema.count.counter, - bp.pb_common.pb_iodonesema.sleepers, + bp.pb_iodonesema.count.counter, + bp.pb_iodonesema.sleepers, bp.pb_sema.count.counter, bp.pb_sema.sleepers, bp.pb_pin_count.counter, bp.pb_last_holder); #else kdb_printf(" pb_iodonesema (%d,%d) pb_sema (%d,%d) pincount (%d)\n", - bp.pb_common.pb_iodonesema.count.counter, - bp.pb_common.pb_iodonesema.sleepers, + bp.pb_iodonesema.count.counter, + bp.pb_iodonesema.sleepers, bp.pb_sema.count.counter, bp.pb_sema.sleepers, bp.pb_pin_count.counter); #endif - if (bp.pb_common.pb_fspriv || bp.pb_common.pb_fspriv2) { + if (bp.pb_fspriv || bp.pb_fspriv2) { kdb_printf( "pb_fspriv 0x%p pb_fspriv2 0x%p\n", - bp.pb_common.pb_fspriv, bp.pb_common.pb_fspriv2); + bp.pb_fspriv, bp.pb_fspriv2); } return 0; diff --git a/include/linux/fs.h b/include/linux/fs.h index bd133801c3e0..18557957520f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1098,15 +1098,20 @@ extern int bd_claim(struct block_device *, void *); extern void bd_release(struct block_device *); extern void blk_run_queues(void); -/* fs/devices.c */ +/* fs/char_dev.c */ extern int register_chrdev(unsigned int, const char *, struct file_operations *); extern int unregister_chrdev(unsigned int, const char *); extern int chrdev_open(struct inode *, struct file *); + +/* fs/block_dev.c */ extern const char *__bdevname(dev_t); extern inline const char *bdevname(struct block_device *bdev) { return __bdevname(bdev->bd_dev); } +extern struct block_device *open_bdev_excl(const char *, int, int, void *); +extern void close_bdev_excl(struct block_device *, int); + extern const char * cdevname(kdev_t); extern const char * kdevname(kdev_t); extern void init_special_inode(struct inode *, umode_t, dev_t); diff --git a/kernel/ksyms.c b/kernel/ksyms.c index bb34c96732d2..cbe3fec93bd1 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -203,6 +203,8 @@ EXPORT_SYMBOL(bdget); EXPORT_SYMBOL(bdput); EXPORT_SYMBOL(bd_claim); EXPORT_SYMBOL(bd_release); +EXPORT_SYMBOL(open_bdev_excl); +EXPORT_SYMBOL(close_bdev_excl); EXPORT_SYMBOL(__brelse); EXPORT_SYMBOL(__bforget); EXPORT_SYMBOL(ll_rw_block); |
