From patchwork Wed Jul 14 08:02:21 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shaohua Li X-Patchwork-Id: 111912 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o6E82S9P014550 for ; Wed, 14 Jul 2010 08:02:28 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751945Ab0GNICZ (ORCPT ); Wed, 14 Jul 2010 04:02:25 -0400 Received: from mga02.intel.com ([134.134.136.20]:64236 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751427Ab0GNICY (ORCPT ); Wed, 14 Jul 2010 04:02:24 -0400 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 14 Jul 2010 01:01:11 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.55,200,1278313200"; d="scan'208";a="535365987" Received: from sli10-conroe.sh.intel.com (HELO [10.239.36.181]) ([10.239.36.181]) by orsmga002.jf.intel.com with ESMTP; 14 Jul 2010 01:02:54 -0700 Subject: [patch 1/2]btrfs: add an ioctl to dump metadata info From: Shaohua Li To: chris.mason@oracle.com Cc: linux-btrfs@vger.kernel.org, Arjan van de Ven , "Wu, Fengguang" Date: Wed, 14 Jul 2010 16:02:21 +0800 Message-ID: <1279094541.1528.94.camel@sli10-desk.sh.intel.com> Mime-Version: 1.0 X-Mailer: Evolution 2.28.3 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 14 Jul 2010 08:02:29 +0000 (UTC) Index: linux/fs/btrfs/ioctl.c =================================================================== --- linux.orig/fs/btrfs/ioctl.c 2010-07-14 09:58:20.000000000 +0800 +++ linux/fs/btrfs/ioctl.c 2010-07-14 10:13:55.000000000 +0800 @@ -40,6 +40,7 @@ #include #include #include +#include #include "compat.h" #include "ctree.h" #include "disk-io.h" @@ -1974,6 +1975,108 @@ long btrfs_ioctl_trans_end(struct file * return 0; } +/* + * return value: + * > 0: entries put to user space vector + * = 0: no entries + * < 0: error + */ +static long btrfs_ioctl_meta_incore(struct btrfs_root *root, void __user *argp) +{ + struct inode *btree_inode = root->fs_info->btree_inode; + struct btrfs_ioctl_meta_incore_args args; + struct btrfs_ioctl_meta_incore_ent ent; + struct pagevec pvec; + __u64 index, last_begin, last_end; + __u64 __user vec_addr; + int start = 0, i, nr_pages, entries = 0; + + if (copy_from_user(&args, + (struct btrfs_ioctl_meta_incore_args __user *)argp, + sizeof(args))) + return -EFAULT; + + /* Check the start address: needs to be page-aligned.. */ + if (args.offset & ~PAGE_CACHE_MASK) + return -EINVAL; + + if ((args.vec_size % sizeof(struct btrfs_ioctl_meta_incore_ent)) != 0) + return -EINVAL; + + if (!access_ok(VERIFY_WRITE, args.vec_addr, args.vec_size)) + return -EFAULT; + + index = args.offset >> PAGE_CACHE_SHIFT; + last_begin = 0; + last_end = 0; + ent.unused = 0; + vec_addr = args.vec_addr; + + pagevec_init(&pvec, 0); + while (vec_addr < args.vec_addr + args.vec_size) { + nr_pages = pagevec_lookup(&pvec, btree_inode->i_mapping, + index, PAGEVEC_SIZE); + if (nr_pages == 0) + break; + for (i = 0; i < nr_pages; i++) { + struct page *page = pvec.pages[i]; + __u64 page_offset = page->index; + int valid; + + index = page_offset + 1; + + /* Only take pages with 'referenced' bit set */ + valid = PageUptodate(page) && PageReferenced(page); + if (valid) { + if (!start) { + start = 1; + last_begin = page_offset; + last_end = page_offset + 1; + continue; + } else if (page_offset == last_end) { + last_end = page_offset + 1; + continue; + } + } else if (!start) + continue; + + ent.offset = last_begin << PAGE_CACHE_SHIFT; + ent.size = (last_end - last_begin) << PAGE_CACHE_SHIFT; + if (copy_to_user((void *)(long)vec_addr, &ent, + sizeof(ent))) { + pagevec_release(&pvec); + return -EFAULT; + } + vec_addr += sizeof(ent); + entries++; + + if (valid) { + last_begin = page_offset; + last_end = page_offset + 1; + } else + start = 0; + + if (vec_addr >= args.vec_addr + args.vec_size) + break; + } + pagevec_release(&pvec); + + if (signal_pending(current)) + return -EINTR; + cond_resched(); + } + if (start && last_end > last_begin && + vec_addr < args.vec_addr + args.vec_size) { + ent.offset = last_begin << PAGE_CACHE_SHIFT; + ent.size = (last_end - last_begin) << PAGE_CACHE_SHIFT; + if (copy_to_user((void *)(long)vec_addr, &ent, sizeof(ent))) + return -EFAULT; + entries++; + } + + return entries; +} + long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -2024,6 +2127,8 @@ long btrfs_ioctl(struct file *file, unsi case BTRFS_IOC_SYNC: btrfs_sync_fs(file->f_dentry->d_sb, 1); return 0; + case BTRFS_IOC_META_INCORE: + return btrfs_ioctl_meta_incore(root, argp); } return -ENOTTY; Index: linux/fs/btrfs/ioctl.h =================================================================== --- linux.orig/fs/btrfs/ioctl.h 2010-07-14 09:58:11.000000000 +0800 +++ linux/fs/btrfs/ioctl.h 2010-07-14 10:14:22.000000000 +0800 @@ -138,6 +138,19 @@ struct btrfs_ioctl_space_args { struct btrfs_ioctl_space_info spaces[0]; }; +struct btrfs_ioctl_meta_incore_ent { + __u64 offset; + __u32 size; + __u32 unused; +}; + +struct btrfs_ioctl_meta_incore_args { + __u64 offset; /* offset in meta address */ + __u64 __user vec_addr; /* vector's address */ + __u32 vec_size; /* vector's size */ + __u32 unused; +}; + #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ @@ -178,4 +191,6 @@ struct btrfs_ioctl_space_args { #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64) #define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \ struct btrfs_ioctl_space_args) +#define BTRFS_IOC_META_INCORE _IOW(BTRFS_IOCTL_MAGIC, 21, \ + struct btrfs_ioctl_meta_incore_args) #endif