Whamcloud - gitweb
b=10555
authorkalpak <kalpak>
Fri, 8 Aug 2008 14:47:00 +0000 (14:47 +0000)
committerkalpak <kalpak>
Fri, 8 Aug 2008 14:47:00 +0000 (14:47 +0000)
i=adilger
i=green
i=nikita
i=girish

add ldiskfs patches and lustre support for FIEMAP ioctl

20 files changed:
lustre/ChangeLog
lustre/autoconf/lustre-core.m4
lustre/include/lustre/Makefile.am
lustre/include/lustre/ll_fiemap.h [new file with mode: 0644]
lustre/include/lustre/lustre_idl.h
lustre/include/lustre/lustre_user.h
lustre/include/lustre_req_layout.h
lustre/include/obd.h
lustre/llite/file.c
lustre/llite/llite_internal.h
lustre/lov/lov_obd.c
lustre/lvfs/fsfilt_ext3.c
lustre/obdfilter/filter.c
lustre/osc/osc_request.c
lustre/ptlrpc/layout.c
lustre/ptlrpc/pack_generic.c
lustre/ptlrpc/ptlrpc_module.c
lustre/tests/sanity.sh
lustre/utils/req-layout.c
lustre/utils/wirecheck.c

index a726c5a..83f700f 100644 (file)
@@ -1288,6 +1288,13 @@ Bugzilla   : 16140
 Description: journal_dev option does not work in b1_6
 Details    : pass mount option during pre-mount.
 
 Description: journal_dev option does not work in b1_6
 Details    : pass mount option during pre-mount.
 
+Severity   : enhancement
+Bugzilla   : 10555
+Description: Add a FIEMAP(FIle Extent MAP) ioctl
+Details    : FIEMAP ioctl will allow an application to efficiently fetch the
+             extent information of a file. It can be used to map logical blocks
+             in a file to physical blocks in the block device.
+
 --------------------------------------------------------------------------------
 
 2007-08-10         Cluster File Systems, Inc. <info@clusterfs.com>
 --------------------------------------------------------------------------------
 
 2007-08-10         Cluster File Systems, Inc. <info@clusterfs.com>
index c0e3a41..6a4e7a6 100644 (file)
@@ -577,6 +577,28 @@ AC_DEFUN([LC_XATTR_ACL],
 [])
 ])
 
 [])
 ])
 
+#
+# LC_LINUX_FIEMAP_H
+#
+# If we have fiemap.h
+# after 2.6.27 use fiemap.h in include/linux
+#
+AC_DEFUN([LC_LINUX_FIEMAP_H],
+[LB_CHECK_FILE([$LINUX/include/linux/fiemap.h],[
+        AC_MSG_CHECKING([if fiemap.h can be compiled])
+        LB_LINUX_TRY_COMPILE([
+                #include <linux/fiemap.h>
+        ],[],[
+                AC_MSG_RESULT([yes])
+                AC_DEFINE(HAVE_LINUX_FIEMAP_H, 1, [Kernel has fiemap.h])
+        ],[
+                AC_MSG_RESULT([no])
+        ])
+],
+[])
+])
+
+
 AC_DEFUN([LC_STRUCT_INTENT_FILE],
 [AC_MSG_CHECKING([if struct open_intent has a file field])
 LB_LINUX_TRY_COMPILE([
 AC_DEFUN([LC_STRUCT_INTENT_FILE],
 [AC_MSG_CHECKING([if struct open_intent has a file field])
 LB_LINUX_TRY_COMPILE([
index bcf98cd..77e9d86 100644 (file)
@@ -35,7 +35,7 @@
 #
 
 if UTILS
 #
 
 if UTILS
-pkginclude_HEADERS = lustre_idl.h lustre_user.h liblustreapi.h libiam.h 
+pkginclude_HEADERS = lustre_idl.h lustre_user.h liblustreapi.h libiam.h ll_fiemap.h
 endif
 
 endif
 
-EXTRA_DIST = lustre_idl.h lustre_user.h liblustreapi.h libiam.h 
+EXTRA_DIST = lustre_idl.h lustre_user.h liblustreapi.h libiam.h ll_fiemap.h
diff --git a/lustre/include/lustre/ll_fiemap.h b/lustre/include/lustre/ll_fiemap.h
new file mode 100644 (file)
index 0000000..e8620bf
--- /dev/null
@@ -0,0 +1,127 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright  2008 Sun Microsystems, Inc. All rights reserved
+ * Use is subject to license terms.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ *
+ * lustre/include/lustre/ll_fiemap.h
+ *
+ * FIEMAP data structures and flags. This header file will be used until
+ * fiemap.h is available in the upstream kernel.
+ *
+ * Author: Kalpak Shah <kalpak.shah@sun.com>
+ * Author: Andreas Dilger <adilger@sun.com>
+ */
+
+#ifndef _LUSTRE_FIEMAP_H
+#define _LUSTRE_FIEMAP_H
+
+#ifndef HAVE_LINUX_FIEMAP_H
+
+struct ll_fiemap_extent {
+        __u64   fe_logical;  /* logical offset in bytes for the start of
+                              * the extent from the beginning of the file */
+        __u64   fe_physical; /* physical offset in bytes for the start
+                              * of the extent from the beginning of the disk */
+        __u64   fe_length;   /* length in bytes for the extent */
+        __u32   fe_flags;    /* FIEMAP_EXTENT_* flags for the extent */
+        __u32   fe_device;   /* device number for this extent */
+};
+
+struct ll_user_fiemap {
+        __u64   fm_start;         /* logical offset (inclusive) at
+                                   * which to start mapping (in) */
+        __u64   fm_length;        /* logical length of mapping which
+                                   * userspace wants (in) */
+        __u32   fm_flags;         /* FIEMAP_FLAG_* flags for request (in/out) */
+        __u32   fm_mapped_extents;/* number of extents that were mapped (out) */
+        __u32   fm_extent_count;  /* size of fm_extents array (in) */
+        __u32   fm_reserved;
+        struct  ll_fiemap_extent   fm_extents[0]; /* array of mapped extents (out).
+                                                   * Lustre uses first extent to
+                                                   * send end_offset */
+};
+
+#define FIEMAP_MAX_OFFSET      (~0ULL)
+
+#define FIEMAP_FLAG_SYNC         0x00000001 /* sync file data before map */
+#define FIEMAP_FLAG_XATTR        0x00000002 /* map extended attribute tree */
+#define FIEMAP_FLAG_DEVICE_ORDER 0x40000000 /* return device ordered mapping */
+
+#define FIEMAP_FLAGS_COMPAT    (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR | \
+                                FIEMAP_FLAG_DEVICE_ORDER)
+
+#define FIEMAP_EXTENT_LAST             0x00000001 /* Last extent in file. */
+#define FIEMAP_EXTENT_UNKNOWN          0x00000002 /* Data location unknown. */
+#define FIEMAP_EXTENT_DELALLOC         0x00000004 /* Location still pending.
+                                                   * Sets EXTENT_UNKNOWN. */
+#define FIEMAP_EXTENT_NO_DIRECT        0x00000008 /* Data mapping undefined */
+#define FIEMAP_EXTENT_SECONDARY        0x00000010 /* Data copied offline. May
+                                                   * set EXTENT_NO_DIRECT. */
+#define FIEMAP_EXTENT_NET              0x00000020 /* Data stored remotely.
+                                                   * Sets EXTENT_NO_DIRECT. */
+#define FIEMAP_EXTENT_DATA_COMPRESSED  0x00000040 /* Data is compressed by fs.
+                                                   * Sets EXTENT_NO_DIRECT. */
+#define FIEMAP_EXTENT_DATA_ENCRYPTED   0x00000080 /* Data is encrypted by fs.
+                                                   * Sets EXTENT_NO_DIRECT. */
+#define FIEMAP_EXTENT_NOT_ALIGNED      0x00000100 /* Extent offsets may not be
+                                                   * block aligned. */
+#define FIEMAP_EXTENT_DATA_INLINE      0x00000200 /* Data mixed with metadata.
+                                                   * Sets EXTENT_NOT_ALIGNED.*/
+#define FIEMAP_EXTENT_DATA_TAIL        0x00000400 /* Multiple files in block.
+                                                   * Sets EXTENT_NOT_ALIGNED.*/
+#define FIEMAP_EXTENT_UNWRITTEN        0x00000800 /* Space allocated, but
+                                                   * no data (i.e. zero). */
+#define FIEMAP_EXTENT_MERGED           0x00001000 /* File does not natively
+                                                   * support extents. Result
+                                                   * merged for efficiency. */
+
+#else
+
+#define ll_fiemap_extent fiemap_extent
+#define ll_user_fiemap   fiemap
+
+#endif /* HAVE_LINUX_FIEMAP_H */
+
+static inline size_t fiemap_count_to_size(size_t extent_count)
+{
+        return (sizeof(struct ll_user_fiemap) + extent_count *
+                                               sizeof(struct ll_fiemap_extent));
+}
+
+static inline unsigned fiemap_size_to_count(size_t array_size)
+{
+        return ((array_size - sizeof(struct ll_user_fiemap)) /
+                                               sizeof(struct ll_fiemap_extent));
+}
+
+#endif /* _LUSTRE_FIEMAP_H */
index 13dbe4e..17b4db6 100644 (file)
@@ -88,6 +88,7 @@
 
 /* Defn's shared with user-space. */
 #include <lustre/lustre_user.h>
 
 /* Defn's shared with user-space. */
 #include <lustre/lustre_user.h>
+#include <lustre/ll_fiemap.h>
 
 /*
  *  GENERAL STUFF
 
 /*
  *  GENERAL STUFF
@@ -972,8 +973,16 @@ struct ost_body {
         struct  obdo oa;
 };
 
         struct  obdo oa;
 };
 
+/* Key for FIEMAP to be used in get_info calls */
+struct ll_fiemap_info_key {
+        char    name[8];
+        struct  obdo oa;
+        struct  ll_user_fiemap fiemap;
+};
+
 extern void lustre_swab_ost_body (struct ost_body *b);
 extern void lustre_swab_ost_last_id(obd_id *id);
 extern void lustre_swab_ost_body (struct ost_body *b);
 extern void lustre_swab_ost_last_id(obd_id *id);
+extern void lustre_swab_fiemap(struct ll_user_fiemap *fiemap);
 
 /* lock value block communicated between the filter and llite */
 
 
 /* lock value block communicated between the filter and llite */
 
index edb61e3..2fd8bc5 100644 (file)
@@ -41,6 +41,7 @@
 #ifndef _LUSTRE_USER_H
 #define _LUSTRE_USER_H
 
 #ifndef _LUSTRE_USER_H
 #define _LUSTRE_USER_H
 
+#include <lustre/ll_fiemap.h>
 #if defined(__linux__)
 #include <linux/lustre_user.h>
 #elif defined(__APPLE__)
 #if defined(__linux__)
 #include <linux/lustre_user.h>
 #elif defined(__APPLE__)
 #define EXT3_IOC_SETVERSION             _IOW('f', 4, long)
 #define EXT3_IOC_GETVERSION_OLD         _IOR('v', 1, long)
 #define EXT3_IOC_SETVERSION_OLD         _IOW('v', 2, long)
 #define EXT3_IOC_SETVERSION             _IOW('f', 4, long)
 #define EXT3_IOC_GETVERSION_OLD         _IOR('v', 1, long)
 #define EXT3_IOC_SETVERSION_OLD         _IOW('v', 2, long)
+#define EXT3_IOC_FIEMAP                 _IOWR('f', 10, struct ll_user_fiemap)
 #endif
 
 #endif
 
+/* FIEMAP flags supported by Lustre */
+#define LUSTRE_FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_DEVICE_ORDER)
+
 struct obd_statfs;
 
 /* 
 struct obd_statfs;
 
 /* 
index a0d0468..1853571 100644 (file)
@@ -188,6 +188,7 @@ extern const struct req_format RQF_OST_STATFS;
 extern const struct req_format RQF_OST_SET_INFO;
 extern const struct req_format RQF_OST_GET_INFO_GENERIC;
 extern const struct req_format RQF_OST_GET_INFO_LAST_ID;
 extern const struct req_format RQF_OST_SET_INFO;
 extern const struct req_format RQF_OST_GET_INFO_GENERIC;
 extern const struct req_format RQF_OST_GET_INFO_LAST_ID;
+extern const struct req_format RQF_OST_GET_INFO_FIEMAP;
 
 /* LDLM req_format */
 extern const struct req_format RQF_LDLM_ENQUEUE;
 
 /* LDLM req_format */
 extern const struct req_format RQF_LDLM_ENQUEUE;
@@ -265,5 +266,7 @@ extern const struct req_msg_field RMF_OST_BODY;
 extern const struct req_msg_field RMF_OBD_IOOBJ;
 extern const struct req_msg_field RMF_OBD_ID;
 extern const struct req_msg_field RMF_NIOBUF_REMOTE;
 extern const struct req_msg_field RMF_OBD_IOOBJ;
 extern const struct req_msg_field RMF_OBD_ID;
 extern const struct req_msg_field RMF_NIOBUF_REMOTE;
+extern const struct req_msg_field RMF_FIEMAP_KEY;
+extern const struct req_msg_field RMF_FIEMAP_VAL;
 
 #endif /* _LUSTRE_REQ_LAYOUT_H__ */
 
 #endif /* _LUSTRE_REQ_LAYOUT_H__ */
index c96ff87..00e4a06 100644 (file)
@@ -1057,6 +1057,7 @@ enum obd_cleanup_stage {
 #define KEY_CLEAR_FS            "clear_fs"
 #define KEY_BLOCKSIZE           "blocksize"
 #define KEY_BLOCKSIZE_BITS      "blocksize_bits"
 #define KEY_CLEAR_FS            "clear_fs"
 #define KEY_BLOCKSIZE           "blocksize"
 #define KEY_BLOCKSIZE_BITS      "blocksize_bits"
+#define KEY_FIEMAP              "FIEMAP"
 /* XXX unused ?*/
 #define KEY_INTERMDS            "inter_mds"
 #define KEY_ASYNC               "async"
 /* XXX unused ?*/
 #define KEY_INTERMDS            "inter_mds"
 #define KEY_ASYNC               "async"
index 416fe42..73fb0a7 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/pagemap.h>
 #include <linux/file.h>
 #include "llite_internal.h"
 #include <linux/pagemap.h>
 #include <linux/file.h>
 #include "llite_internal.h"
+#include <lustre/ll_fiemap.h>
 
 /* also used by llite/special.c:ll_special_open() */
 struct ll_file_data *ll_file_data_get(void)
 
 /* also used by llite/special.c:ll_special_open() */
 struct ll_file_data *ll_file_data_get(void)
@@ -2489,6 +2490,49 @@ int ll_release_openhandle(struct dentry *dentry, struct lookup_intent *it)
         RETURN(rc);
 }
 
         RETURN(rc);
 }
 
+/**
+ * Get size for inode for which FIEMAP mapping is requested.
+ * Make the FIEMAP get_info call and returns the result.
+ */
+int ll_fiemap(struct inode *inode, struct ll_user_fiemap *fiemap,
+              int num_bytes)
+{
+        struct obd_export *exp = ll_i2dtexp(inode);
+        struct lov_stripe_md *lsm = ll_i2info(inode)->lli_smd;
+        struct ll_fiemap_info_key fm_key = { .name = KEY_FIEMAP, };
+        int vallen = num_bytes;
+        int rc;
+        ENTRY;
+
+        /* If the stripe_count > 1 and the application does not understand
+         * DEVICE_ORDER flag, then it cannot interpret the extents correctly.
+         */
+        if (lsm->lsm_stripe_count > 1 &&
+            !(fiemap->fm_flags & FIEMAP_FLAG_DEVICE_ORDER))
+                return -EOPNOTSUPP;
+
+        fm_key.oa.o_id = lsm->lsm_object_id;
+        fm_key.oa.o_gr = lsm->lsm_object_gr;
+        fm_key.oa.o_valid = OBD_MD_FLID | OBD_MD_FLGROUP;
+
+        obdo_from_inode(&fm_key.oa, inode, OBD_MD_FLFID | OBD_MD_FLGROUP |
+                        OBD_MD_FLSIZE);
+
+        /* If filesize is 0, then there would be no objects for mapping */
+        if (fm_key.oa.o_size == 0) {
+                fiemap->fm_mapped_extents = 0;
+                RETURN(0);
+        }
+
+        memcpy(&fm_key.fiemap, fiemap, sizeof(*fiemap));
+
+        rc = obd_get_info(exp, sizeof(fm_key), &fm_key, &vallen, fiemap, lsm);
+        if (rc)
+                CERROR("obd_get_info failed: rc = %d\n", rc);
+
+        RETURN(rc);
+}
+
 int ll_file_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                   unsigned long arg)
 {
 int ll_file_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                   unsigned long arg)
 {
@@ -2538,6 +2582,72 @@ int ll_file_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                 RETURN(ll_lov_getstripe(inode, arg));
         case LL_IOC_RECREATE_OBJ:
                 RETURN(ll_lov_recreate_obj(inode, file, arg));
                 RETURN(ll_lov_getstripe(inode, arg));
         case LL_IOC_RECREATE_OBJ:
                 RETURN(ll_lov_recreate_obj(inode, file, arg));
+        case EXT3_IOC_FIEMAP: {
+                struct ll_user_fiemap *fiemap_s;
+                size_t num_bytes, ret_bytes;
+                unsigned int extent_count;
+                int rc = 0;
+
+                /* Get the extent count so we can calculate the size of
+                 * required fiemap buffer */
+                if (get_user(extent_count,
+                    &((struct ll_user_fiemap __user *)arg)->fm_extent_count))
+                        RETURN(-EFAULT);
+                num_bytes = sizeof(*fiemap_s) + (extent_count *
+                                                 sizeof(struct ll_fiemap_extent));
+                OBD_VMALLOC(fiemap_s, num_bytes);
+                if (fiemap_s == NULL)
+                        RETURN(-ENOMEM);
+
+                if (copy_from_user(fiemap_s,(struct ll_user_fiemap __user *)arg,
+                                   sizeof(*fiemap_s)))
+                        GOTO(error, rc = -EFAULT);
+
+                if (fiemap_s->fm_flags & ~LUSTRE_FIEMAP_FLAGS_COMPAT) {
+                        fiemap_s->fm_flags = fiemap_s->fm_flags &
+                                                    ~LUSTRE_FIEMAP_FLAGS_COMPAT;
+                        if (copy_to_user((char *)arg, fiemap_s,
+                                         sizeof(*fiemap_s)))
+                                GOTO(error, rc = -EFAULT);
+
+                        GOTO(error, rc = -EBADR);
+                }
+
+                /* If fm_extent_count is non-zero, read the first extent since
+                 * it is used to calculate end_offset and device from previous
+                 * fiemap call. */
+                if (extent_count) {
+                        if (copy_from_user(&fiemap_s->fm_extents[0],
+                            (char __user *)arg + sizeof(*fiemap_s),
+                            sizeof(struct ll_fiemap_extent)))
+                                GOTO(error, rc = -EFAULT);
+                }
+
+                if (fiemap_s->fm_flags & FIEMAP_FLAG_SYNC) {
+                        int rc;
+
+                        rc = filemap_fdatawrite(inode->i_mapping);
+                        if (rc)
+                                GOTO(error, rc);
+                }
+
+                rc = ll_fiemap(inode, fiemap_s, num_bytes);
+                if (rc)
+                        GOTO(error, rc);
+
+                ret_bytes = sizeof(struct ll_user_fiemap);
+
+                if (extent_count != 0)
+                        ret_bytes += (fiemap_s->fm_mapped_extents *
+                                         sizeof(struct ll_fiemap_extent));
+
+                if (copy_to_user((void *)arg, fiemap_s, ret_bytes))
+                        rc = -EFAULT;
+
+error:
+                OBD_VFREE(fiemap_s, num_bytes);
+                RETURN(rc);
+        }
         case EXT3_IOC_GETFLAGS:
         case EXT3_IOC_SETFLAGS:
                 RETURN(ll_iocontrol(inode, file, cmd, arg));
         case EXT3_IOC_GETFLAGS:
         case EXT3_IOC_SETFLAGS:
                 RETURN(ll_iocontrol(inode, file, cmd, arg));
index c9acb96..b5d9257 100644 (file)
@@ -804,6 +804,9 @@ int ll_dir_setstripe(struct inode *inode, struct lov_user_md *lump,
                      int set_default);
 int ll_dir_getstripe(struct inode *inode, struct lov_mds_md **lmm, 
                      int *lmm_size, struct ptlrpc_request **request);
                      int set_default);
 int ll_dir_getstripe(struct inode *inode, struct lov_mds_md **lmm, 
                      int *lmm_size, struct ptlrpc_request **request);
+int ll_fsync(struct file *file, struct dentry *dentry, int data);
+int ll_fiemap(struct inode *inode, struct ll_user_fiemap *fiemap,
+              int num_bytes);
 void ll_pin_extent_cb(void *data);
 int ll_page_removal_cb(void *data, int discard);
 int ll_extent_lock_cancel_cb(struct ldlm_lock *lock, struct ldlm_lock_desc *new,
 void ll_pin_extent_cb(void *data);
 int ll_page_removal_cb(void *data, int discard);
 int ll_extent_lock_cancel_cb(struct ldlm_lock *lock, struct ldlm_lock_desc *new,
index 33def20..25de713 100644 (file)
@@ -64,6 +64,7 @@
 #include <lprocfs_status.h>
 #include <lustre_param.h>
 #include <lustre_cache.h>
 #include <lprocfs_status.h>
 #include <lustre_param.h>
 #include <lustre_cache.h>
+#include <lustre/ll_fiemap.h>
 
 #include "lov_internal.h"
 
 
 #include "lov_internal.h"
 
@@ -2507,6 +2508,358 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
         RETURN(rc);
 }
 
         RETURN(rc);
 }
 
+#define FIEMAP_BUFFER_SIZE 4096
+
+/**
+ * Non-zero fe_logical indicates that this is a continuation FIEMAP
+ * call. The local end offset and the device are sent in the first
+ * fm_extent. This function calculates the stripe number from the index.
+ * This function returns a stripe_no on which mapping is to be restarted.
+ *
+ * This function returns fm_end_offset which is the in-OST offset at which
+ * mapping should be restarted. If fm_end_offset=0 is returned then caller
+ * will re-calculate proper offset in next stripe.
+ * Note that the first extent is passed to lov_get_info via the value field.
+ *
+ * \param fiemap fiemap request header
+ * \param lsm striping information for the file
+ * \param fm_start logical start of mapping
+ * \param fm_end logical end of mapping
+ * \param start_stripe starting stripe will be returned in this
+ */
+obd_size fiemap_calc_fm_end_offset(struct ll_user_fiemap *fiemap,
+                                   struct lov_stripe_md *lsm, obd_size fm_start,
+                                   obd_size fm_end, int *start_stripe)
+{
+        obd_size local_end = fiemap->fm_extents[0].fe_logical;
+        obd_off lun_start, lun_end;
+        obd_size fm_end_offset;
+        int stripe_no = -1, i;
+
+        if (fiemap->fm_extent_count == 0 ||
+            fiemap->fm_extents[0].fe_logical == 0)
+                return 0;
+
+        /* Find out stripe_no from ost_index saved in the fe_device */
+        for (i = 0; i < lsm->lsm_stripe_count; i++) {
+                if (lsm->lsm_oinfo[i]->loi_ost_idx ==
+                                        fiemap->fm_extents[0].fe_device) {
+                        stripe_no = i;
+                        break;
+                }
+        }
+
+        /* If we have finished mapping on previous device, shift logical
+         * offset to start of next device */
+        if ((lov_stripe_intersects(lsm, stripe_no, fm_start, fm_end,
+                                   &lun_start, &lun_end)) != 0 &&
+                                   local_end < lun_end) {
+                fm_end_offset = local_end;
+                *start_stripe = stripe_no;
+        } else {
+                /* This is a special value to indicate that caller should
+                 * calculate offset in next stripe. */
+                fm_end_offset = 0;
+                *start_stripe = (stripe_no + 1) % lsm->lsm_stripe_count;
+        }
+
+        return fm_end_offset;
+}
+
+/**
+ * We calculate on which OST the mapping will end. If the length of mapping
+ * is greater than (stripe_size * stripe_count) then the last_stripe will
+ * will be one just before start_stripe. Else we check if the mapping
+ * intersects each OST and find last_stripe.
+ * This function returns the last_stripe and also sets the stripe_count
+ * over which the mapping is spread
+ *
+ * \param lsm striping information for the file
+ * \param fm_start logical start of mapping
+ * \param fm_end logical end of mapping
+ * \param start_stripe starting stripe of the mapping
+ * \param stripe_count the number of stripes across which to map is returned
+ *
+ * \retval last_stripe return the last stripe of the mapping
+ */
+int fiemap_calc_last_stripe(struct lov_stripe_md *lsm, obd_size fm_start,
+                            obd_size fm_end, int start_stripe,
+                            int *stripe_count)
+{
+        int last_stripe;
+        obd_off obd_start, obd_end;
+        int i, j;
+
+        if (fm_end - fm_start > lsm->lsm_stripe_size * lsm->lsm_stripe_count) {
+                last_stripe = (start_stripe < 1 ? lsm->lsm_stripe_count - 1 :
+                                                              start_stripe - 1);
+                *stripe_count = lsm->lsm_stripe_count;
+        } else {
+                for (j = 0, i = start_stripe; j < lsm->lsm_stripe_count;
+                     i = (i + 1) % lsm->lsm_stripe_count, j++) {
+                        if ((lov_stripe_intersects(lsm, i, fm_start, fm_end,
+                                                   &obd_start, &obd_end)) == 0)
+                                break;
+                }
+                *stripe_count = j;
+                last_stripe = (start_stripe + j - 1) %lsm->lsm_stripe_count;
+        }
+
+        return last_stripe;
+}
+
+/**
+ * Set fe_device and copy extents from local buffer into main return buffer.
+ *
+ * \param fiemap fiemap request header
+ * \param lcl_fm_ext array of local fiemap extents to be copied
+ * \param ost_index OST index to be written into the fm_device field for each
+                    extent
+ * \param ext_count number of extents to be copied
+ * \param current_extent where to start copying in main extent array
+ */
+void fiemap_prepare_and_copy_exts(struct ll_user_fiemap *fiemap,
+                                  struct ll_fiemap_extent *lcl_fm_ext,
+                                  int ost_index, unsigned int ext_count,
+                                  int current_extent)
+{
+        char *to;
+        int ext;
+
+        for (ext = 0; ext < ext_count; ext++) {
+                lcl_fm_ext[ext].fe_device = ost_index;
+                lcl_fm_ext[ext].fe_flags |= FIEMAP_EXTENT_NET;
+        }
+
+        /* Copy fm_extent's from fm_local to return buffer */
+        to = (char *)fiemap + fiemap_count_to_size(current_extent);
+        memcpy(to, lcl_fm_ext, ext_count * sizeof(struct ll_fiemap_extent));
+}
+
+/**
+ * Break down the FIEMAP request and send appropriate calls to individual OSTs.
+ * This also handles the restarting of FIEMAP calls in case mapping overflows
+ * the available number of extents in single call.
+ */
+static int lov_fiemap(struct lov_obd *lov, __u32 keylen, void *key,
+                      __u32 *vallen, void *val, struct lov_stripe_md *lsm)
+{
+        struct ll_fiemap_info_key *fm_key = key;
+        struct ll_user_fiemap *fiemap = val;
+        struct ll_user_fiemap *fm_local = NULL;
+        struct ll_fiemap_extent *lcl_fm_ext;
+        int count_local;
+        unsigned int get_num_extents = 0;
+        int ost_index = 0, actual_start_stripe, start_stripe;
+        obd_size fm_start, fm_end, fm_length, fm_end_offset = 0;
+        obd_size curr_loc;
+        int current_extent = 0, rc = 0, i;
+        int ost_eof = 0; /* EOF for object */
+        int ost_done = 0; /* done with required mapping for this OST? */
+        int last_stripe;
+        int cur_stripe = 0, cur_stripe_wrap = 0, stripe_count;
+        unsigned int buffer_size = FIEMAP_BUFFER_SIZE;
+
+        if (lsm == NULL)
+                GOTO(out, rc = 0);
+
+        if (fiemap_count_to_size(fm_key->fiemap.fm_extent_count) < buffer_size)
+                buffer_size = fiemap_count_to_size(fm_key->fiemap.fm_extent_count);
+
+        OBD_ALLOC(fm_local, buffer_size);
+        if (fm_local == NULL)
+                GOTO(out, rc = -ENOMEM);
+        lcl_fm_ext = &fm_local->fm_extents[0];
+
+        count_local = fiemap_size_to_count(buffer_size);
+
+        memcpy(fiemap, &fm_key->fiemap, sizeof(*fiemap));
+        fm_start = fiemap->fm_start;
+        fm_length = fiemap->fm_length;
+        /* Calculate start stripe, last stripe and length of mapping */
+        actual_start_stripe = start_stripe = lov_stripe_number(lsm, fm_start);
+        fm_end = (fm_length == ~0ULL ? fm_key->oa.o_size :
+                                                fm_start + fm_length - 1);
+        /* If fm_length != ~0ULL but fm_start+fm_length-1 exceeds file size */
+        if (fm_end > fm_key->oa.o_size)
+                fm_end = fm_key->oa.o_size;
+
+        last_stripe = fiemap_calc_last_stripe(lsm, fm_start, fm_end,
+                                            actual_start_stripe, &stripe_count);
+
+        fm_end_offset = fiemap_calc_fm_end_offset(fiemap, lsm, fm_start, fm_end,
+                                                  &start_stripe);
+
+        if (fiemap->fm_extent_count == 0) {
+                get_num_extents = 1;
+                count_local = 0;
+        }
+
+        /* Check each stripe */
+        for (cur_stripe = start_stripe, i = 0; i < stripe_count;
+             i++, cur_stripe = (cur_stripe + 1) % lsm->lsm_stripe_count) {
+                obd_size req_fm_len; /* Stores length of required mapping */
+                obd_size len_mapped_single_call;
+                obd_off lun_start, lun_end, obd_object_end;
+                unsigned int ext_count;
+
+                cur_stripe_wrap = cur_stripe;
+
+                /* Find out range of mapping on this stripe */
+                if ((lov_stripe_intersects(lsm, cur_stripe, fm_start, fm_end,
+                                           &lun_start, &obd_object_end)) == 0)
+                        continue;
+
+                /* If this is a continuation FIEMAP call and we are on
+                 * starting stripe then lun_start needs to be set to
+                 * fm_end_offset */
+                if (fm_end_offset != 0 && cur_stripe == start_stripe)
+                        lun_start = fm_end_offset;
+
+                if (fm_length != ~0ULL) {
+                        /* Handle fm_start + fm_length overflow */
+                        if (fm_start + fm_length < fm_start)
+                                fm_length = ~0ULL - fm_start;
+                        lun_end = lov_size_to_stripe(lsm, fm_start + fm_length,
+                                                     cur_stripe);
+                } else {
+                        lun_end = ~0ULL;
+                }
+
+                if (lun_start == lun_end)
+                        continue;
+
+                req_fm_len = obd_object_end - lun_start;
+                fm_local->fm_length = 0;
+                len_mapped_single_call = 0;
+
+                /* If the output buffer is very large and the objects have many
+                 * extents we may need to loop on a single OST repeatedly */
+                ost_eof = 0;
+                ost_done = 0;
+                do {
+                        if (get_num_extents == 0) {
+                                /* Don't get too many extents. */
+                                if (current_extent + count_local >
+                                    fiemap->fm_extent_count)
+                                        count_local = fiemap->fm_extent_count -
+                                                                 current_extent;
+                        }
+
+                        lun_start += len_mapped_single_call;
+                        fm_local->fm_length = req_fm_len - len_mapped_single_call;
+                        req_fm_len = fm_local->fm_length;
+                        fm_local->fm_extent_count = count_local;
+                        fm_local->fm_mapped_extents = 0;
+                        fm_local->fm_flags = fiemap->fm_flags;
+
+                        fm_key->oa.o_id = lsm->lsm_oinfo[cur_stripe]->loi_id;
+                        ost_index = lsm->lsm_oinfo[cur_stripe]->loi_ost_idx;
+
+                        if (ost_index < 0 || ost_index >=lov->desc.ld_tgt_count)
+                                GOTO(out, rc = -EINVAL);
+
+                        /* If OST is inactive, return extent with UNKNOWN flag */
+                        if (lov && !lov->lov_tgts[ost_index]->ltd_active) {
+                                fm_local->fm_flags |= FIEMAP_EXTENT_LAST;
+                                fm_local->fm_mapped_extents = 1;
+
+                                lcl_fm_ext[0].fe_logical = lun_start;
+                                lcl_fm_ext[0].fe_length = obd_object_end -
+                                                                      lun_start;
+                                lcl_fm_ext[0].fe_flags |= FIEMAP_EXTENT_UNKNOWN;
+
+                                goto inactive_tgt;
+                        }
+
+                        fm_local->fm_start = lun_start;
+                        fm_local->fm_flags &= ~FIEMAP_FLAG_DEVICE_ORDER;
+                        memcpy(&fm_key->fiemap, fm_local, sizeof(*fm_local));
+                        *vallen=fiemap_count_to_size(fm_local->fm_extent_count);
+                        rc = obd_get_info(lov->lov_tgts[ost_index]->ltd_exp,
+                                          keylen, key, vallen, fm_local, lsm);
+                        if (rc != 0)
+                                GOTO(out, rc);
+
+inactive_tgt:
+                        ext_count = fm_local->fm_mapped_extents;
+                        if (ext_count == 0) {
+                                ost_done = 1;
+                                /* If last stripe has hole at the end,
+                                 * then we need to return */
+                                if (cur_stripe_wrap == last_stripe) {
+                                        fiemap->fm_mapped_extents = 0;
+                                        goto finish;
+                                }
+                                break;
+                        }
+
+                        /* If we just need num of extents then go to next device */
+                        if (get_num_extents) {
+                                current_extent += ext_count;
+                                break;
+                        }
+
+                        len_mapped_single_call = lcl_fm_ext[ext_count-1].fe_logical -
+                                  lun_start + lcl_fm_ext[ext_count - 1].fe_length;
+
+                        /* Have we finished mapping on this device? */
+                        if (req_fm_len <= len_mapped_single_call)
+                                ost_done = 1;
+
+                        /* Clear the EXTENT_LAST flag which can be present on
+                         * last extent */
+                        if (lcl_fm_ext[ext_count-1].fe_flags & FIEMAP_EXTENT_LAST)
+                                lcl_fm_ext[ext_count - 1].fe_flags &=
+                                                            ~FIEMAP_EXTENT_LAST;
+
+                        curr_loc = lov_stripe_size(lsm,
+                                           lcl_fm_ext[ext_count - 1].fe_logical+
+                                           lcl_fm_ext[ext_count - 1].fe_length,
+                                           cur_stripe);
+                        if (curr_loc >= fm_key->oa.o_size)
+                                ost_eof = 1;
+
+                        fiemap_prepare_and_copy_exts(fiemap, lcl_fm_ext,
+                                                     ost_index, ext_count,
+                                                     current_extent);
+
+                        current_extent += ext_count;
+
+                        /* Ran out of available extents? */
+                        if (current_extent >= fiemap->fm_extent_count)
+                                goto finish;
+                } while (ost_done == 0 && ost_eof == 0);
+
+                if (cur_stripe_wrap == last_stripe)
+                        goto finish;
+        }
+
+finish:
+        /* Indicate that we are returning device offsets unless file just has
+         * single stripe */
+        if (lsm->lsm_stripe_count > 1)
+                fiemap->fm_flags |= FIEMAP_FLAG_DEVICE_ORDER;
+
+        if (get_num_extents)
+                goto skip_last_device_calc;
+
+        /* Check if we have reached the last stripe and whether mapping for that
+         * stripe is done. */
+        if (cur_stripe_wrap == last_stripe) {
+                if (ost_done || ost_eof)
+                        fiemap->fm_extents[current_extent - 1].fe_flags |=
+                                                             FIEMAP_EXTENT_LAST;
+        }
+
+skip_last_device_calc:
+        fiemap->fm_mapped_extents = current_extent;
+
+out:
+        OBD_FREE(fm_local, buffer_size);
+        return rc;
+}
+
 static int lov_get_info(struct obd_export *exp, __u32 keylen,
                         void *key, __u32 *vallen, void *val,
                         struct lov_stripe_md *lsm)
 static int lov_get_info(struct obd_export *exp, __u32 keylen,
                         void *key, __u32 *vallen, void *val,
                         struct lov_stripe_md *lsm)
@@ -2580,9 +2933,13 @@ static int lov_get_info(struct obd_export *exp, __u32 keylen,
                         if (tgt && obd_uuid_equals(val, &tgt->ltd_uuid))
                                 GOTO(out, rc = i);
                 }
                         if (tgt && obd_uuid_equals(val, &tgt->ltd_uuid))
                                 GOTO(out, rc = i);
                 }
+        } else if (KEY_IS(KEY_FIEMAP)) {
+                rc = lov_fiemap(lov, keylen, key, vallen, val, lsm);
+                GOTO(out, rc);
         }
 
         rc = -EINVAL;
         }
 
         rc = -EINVAL;
+
 out:
         lov_putref(obddev);
         RETURN(rc);
 out:
         lov_putref(obddev);
         RETURN(rc);
index 447701d..4d43591 100644 (file)
@@ -890,13 +890,20 @@ static unsigned long new_blocks(handle_t *handle, struct ext3_ext_base *base,
 static int ext3_ext_new_extent_cb(struct ext3_ext_base *base,
                                   struct ext3_ext_path *path,
                                   struct ext3_ext_cache *cex,
 static int ext3_ext_new_extent_cb(struct ext3_ext_base *base,
                                   struct ext3_ext_path *path,
                                   struct ext3_ext_cache *cex,
+#ifdef HAVE_EXT_PREPARE_CB_EXTENT
+                                   struct ext3_extent *ex,
+#endif
                                   void *cbdata)
 {
         struct bpointers *bp = cbdata;
 #else
 static int ext3_ext_new_extent_cb(struct ext3_ext_base *base,
                                   struct ext3_ext_path *path,
                                   void *cbdata)
 {
         struct bpointers *bp = cbdata;
 #else
 static int ext3_ext_new_extent_cb(struct ext3_ext_base *base,
                                   struct ext3_ext_path *path,
-                                  struct ext3_ext_cache *cex)
+                                  struct ext3_ext_cache *cex
+#ifdef HAVE_EXT_PREPARE_CB_EXTENT
+                                  , struct ext3_extent *ex
+#endif
+                                 )
 {
         struct bpointers *bp = base->private;
 #endif
 {
         struct bpointers *bp = base->private;
 #endif
index 084dc8a..edd5cb8 100644 (file)
@@ -75,6 +75,7 @@
 #include <lustre_quota.h>
 #include <linux/slab.h>
 #include <lustre_param.h>
 #include <lustre_quota.h>
 #include <linux/slab.h>
 #include <lustre_param.h>
+#include <lustre/ll_fiemap.h>
 
 #include "filter_internal.h"
 
 
 #include "filter_internal.h"
 
@@ -4120,6 +4121,38 @@ static int filter_get_info(struct obd_export *exp, __u32 keylen,
                 RETURN(0);
         }
 
                 RETURN(0);
         }
 
+        if (KEY_IS(KEY_FIEMAP)) {
+                struct ll_fiemap_info_key *fm_key = key;
+                struct dentry *dentry;
+                struct ll_user_fiemap *fiemap = val;
+                struct lvfs_run_ctxt saved;
+                int rc;
+
+                if (fiemap == NULL) {
+                        *vallen = fiemap_count_to_size(
+                                                fm_key->fiemap.fm_extent_count);
+                        RETURN(0);
+                }
+
+                dentry = __filter_oa2dentry(exp->exp_obd, &fm_key->oa,
+                                            __FUNCTION__, 1);
+                if (IS_ERR(dentry))
+                        RETURN(PTR_ERR(dentry));
+
+                memcpy(fiemap, &fm_key->fiemap, sizeof(*fiemap));
+                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+                rc = fsfilt_iocontrol(obd, dentry->d_inode, NULL,
+                                      EXT3_IOC_FIEMAP, (long)fiemap);
+                if (rc) {
+                        f_dput(dentry);
+                        RETURN(rc);
+                }
+                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+                f_dput(dentry);
+                RETURN(0);
+        }
+
         CDEBUG(D_IOCTL, "invalid key\n");
         RETURN(-EINVAL);
 }
         CDEBUG(D_IOCTL, "invalid key\n");
         RETURN(-EINVAL);
 }
index f79aab7..dfb123b 100644 (file)
@@ -3590,7 +3590,8 @@ out:
 }
 
 static int osc_get_info(struct obd_export *exp, obd_count keylen,
 }
 
 static int osc_get_info(struct obd_export *exp, obd_count keylen,
-                        void *key, __u32 *vallen, void *val, struct lov_stripe_md *lsm)
+                        void *key, __u32 *vallen, void *val,
+                        struct lov_stripe_md *lsm)
 {
         ENTRY;
         if (!vallen || !val)
 {
         ENTRY;
         if (!vallen || !val)
@@ -3636,7 +3637,51 @@ static int osc_get_info(struct obd_export *exp, obd_count keylen,
         out:
                 ptlrpc_req_finished(req);
                 RETURN(rc);
         out:
                 ptlrpc_req_finished(req);
                 RETURN(rc);
+        } else if (KEY_IS(KEY_FIEMAP)) {
+                struct ptlrpc_request *req;
+                struct ll_user_fiemap *reply;
+                char *tmp;
+                int rc;
+
+                req = ptlrpc_request_alloc(class_exp2cliimp(exp),
+                                           &RQF_OST_GET_INFO_FIEMAP);
+                if (req == NULL)
+                        RETURN(-ENOMEM);
+
+                req_capsule_set_size(&req->rq_pill, &RMF_FIEMAP_KEY,
+                                     RCL_CLIENT, keylen);
+                req_capsule_set_size(&req->rq_pill, &RMF_FIEMAP_VAL,
+                                     RCL_CLIENT, *vallen);
+                req_capsule_set_size(&req->rq_pill, &RMF_FIEMAP_VAL,
+                                     RCL_SERVER, *vallen);
+
+                rc = ptlrpc_request_pack(req, LUSTRE_OST_VERSION, OST_GET_INFO);
+                if (rc) {
+                        ptlrpc_request_free(req);
+                        RETURN(rc);
+                }
+
+                tmp = req_capsule_client_get(&req->rq_pill, &RMF_FIEMAP_KEY);
+                memcpy(tmp, key, keylen);
+                tmp = req_capsule_client_get(&req->rq_pill, &RMF_FIEMAP_VAL);
+                memcpy(tmp, val, *vallen);
+
+                ptlrpc_request_set_replen(req);
+                rc = ptlrpc_queue_wait(req);
+                if (rc)
+                        GOTO(out1, rc);
+
+                reply = req_capsule_server_get(&req->rq_pill, &RMF_FIEMAP_VAL);
+                if (reply == NULL)
+                        GOTO(out1, rc = -EPROTO);
+
+                memcpy(val, reply, *vallen);
+        out1:
+                ptlrpc_req_finished(req);
+
+                RETURN(rc);
         }
         }
+
         RETURN(-EINVAL);
 }
 
         RETURN(-EINVAL);
 }
 
index c11e836..6e8af2e 100644 (file)
@@ -504,6 +504,17 @@ static const struct req_msg_field *ost_get_last_id_server[] = {
         &RMF_OBD_ID
 };
 
         &RMF_OBD_ID
 };
 
+static const struct req_msg_field *ost_get_fiemap_client[] = {
+        &RMF_PTLRPC_BODY,
+        &RMF_FIEMAP_KEY,
+        &RMF_FIEMAP_VAL
+};
+
+static const struct req_msg_field *ost_get_fiemap_server[] = {
+        &RMF_PTLRPC_BODY,
+        &RMF_FIEMAP_VAL
+};
+
 static const struct req_format *req_formats[] = {
         &RQF_OBD_PING,
         &RQF_SEC_CTX,
 static const struct req_format *req_formats[] = {
         &RQF_OBD_PING,
         &RQF_SEC_CTX,
@@ -556,6 +567,7 @@ static const struct req_format *req_formats[] = {
         &RQF_OST_SET_INFO,
         &RQF_OST_GET_INFO_GENERIC,
         &RQF_OST_GET_INFO_LAST_ID,
         &RQF_OST_SET_INFO,
         &RQF_OST_GET_INFO_GENERIC,
         &RQF_OST_GET_INFO_LAST_ID,
+        &RQF_OST_GET_INFO_FIEMAP,
         &RQF_LDLM_ENQUEUE,
         &RQF_LDLM_ENQUEUE_LVB,
         &RQF_LDLM_CONVERT,
         &RQF_LDLM_ENQUEUE,
         &RQF_LDLM_ENQUEUE_LVB,
         &RQF_LDLM_CONVERT,
@@ -809,6 +821,14 @@ const struct req_msg_field RMF_OBD_ID =
                     sizeof(obd_id), lustre_swab_ost_last_id);
 EXPORT_SYMBOL(RMF_OBD_ID);
 
                     sizeof(obd_id), lustre_swab_ost_last_id);
 EXPORT_SYMBOL(RMF_OBD_ID);
 
+const struct req_msg_field RMF_FIEMAP_KEY =
+        DEFINE_MSGF("FIEMAP", 0, sizeof(struct ll_fiemap_info_key),
+                    lustre_swab_fiemap);
+EXPORT_SYMBOL(RMF_FIEMAP_KEY);
+
+const struct req_msg_field RMF_FIEMAP_VAL =
+        DEFINE_MSGF("FIEMAP", 0, -1, lustre_swab_fiemap);
+EXPORT_SYMBOL(RMF_FIEMAP_VAL);
 
 /*
  * Request formats.
 
 /*
  * Request formats.
@@ -1172,6 +1192,11 @@ const struct req_format RQF_OST_GET_INFO_LAST_ID =
                                                 ost_get_last_id_server);
 EXPORT_SYMBOL(RQF_OST_GET_INFO_LAST_ID);
 
                                                 ost_get_last_id_server);
 EXPORT_SYMBOL(RQF_OST_GET_INFO_LAST_ID);
 
+const struct req_format RQF_OST_GET_INFO_FIEMAP =
+        DEFINE_REQ_FMT0("OST_GET_INFO_FIEMAP", ost_get_fiemap_client,
+                                               ost_get_fiemap_server);
+EXPORT_SYMBOL(RQF_OST_GET_INFO_FIEMAP);
+
 
 #if !defined(__REQ_LAYOUT_USER__)
 
 
 #if !defined(__REQ_LAYOUT_USER__)
 
index a60acbc..7df1357 100644 (file)
@@ -53,6 +53,7 @@
 #include <obd_class.h>
 #include <lustre_net.h>
 #include <obd_cksum.h>
 #include <obd_class.h>
 #include <lustre_net.h>
 #include <obd_cksum.h>
+#include <lustre/ll_fiemap.h>
 
 static inline int lustre_msg_hdr_size_v2(int count)
 {
 
 static inline int lustre_msg_hdr_size_v2(int count)
 {
@@ -1846,6 +1847,30 @@ void lustre_swab_mds_rec_unlink (struct mds_rec_unlink *ul)
         CLASSERT(offsetof(typeof(*ul), ul_padding_4) != 0);
 }
 
         CLASSERT(offsetof(typeof(*ul), ul_padding_4) != 0);
 }
 
+void lustre_swab_fiemap_extent(struct ll_fiemap_extent *fm_extent)
+{
+        __swab64s(&fm_extent->fe_logical);
+        __swab64s(&fm_extent->fe_physical);
+        __swab64s(&fm_extent->fe_length);
+        __swab32s(&fm_extent->fe_flags);
+        __swab32s(&fm_extent->fe_device);
+}
+
+void lustre_swab_fiemap(struct ll_user_fiemap *fiemap)
+{
+        int i;
+
+        __swab64s(&fiemap->fm_start);
+        __swab64s(&fiemap->fm_length);
+        __swab32s(&fiemap->fm_flags);
+        __swab32s(&fiemap->fm_mapped_extents);
+        __swab32s(&fiemap->fm_extent_count);
+        __swab32s(&fiemap->fm_reserved);
+
+        for (i = 0; i < fiemap->fm_mapped_extents; i++)
+                lustre_swab_fiemap_extent(&fiemap->fm_extents[i]);
+}
+
 void lustre_swab_mds_rec_rename (struct mds_rec_rename *rn)
 {
         __swab32s (&rn->rn_opcode);
 void lustre_swab_mds_rec_rename (struct mds_rec_rename *rn)
 {
         __swab32s (&rn->rn_opcode);
index 521f6d4..cbdcc88 100644 (file)
@@ -306,6 +306,7 @@ EXPORT_SYMBOL(lustre_swab_md_fld);
 EXPORT_SYMBOL(lustre_swab_generic_32s);
 EXPORT_SYMBOL(lustre_swab_lustre_capa);
 EXPORT_SYMBOL(lustre_swab_lustre_capa_key);
 EXPORT_SYMBOL(lustre_swab_generic_32s);
 EXPORT_SYMBOL(lustre_swab_lustre_capa);
 EXPORT_SYMBOL(lustre_swab_lustre_capa_key);
+EXPORT_SYMBOL(lustre_swab_fiemap);
 
 /* recover.c */
 EXPORT_SYMBOL(ptlrpc_disconnect_import);
 
 /* recover.c */
 EXPORT_SYMBOL(ptlrpc_disconnect_import);
index 8591117..f7d6352 100644 (file)
@@ -5259,6 +5259,224 @@ test_129() {
 run_test 129 "test directory size limit ========================"
 
 
 run_test 129 "test directory size limit ========================"
 
 
+test_130a() {
+       filefrag_op=$(filefrag -e 2>&1 | grep "invalid option")
+       [ -n "$filefrag_op" ] && skip '"filefrag does not support FIEMAP" && return'
+
+       local fm_file=$DIR/$tfile
+       lfs setstripe -s 65536 -c 1 $fm_file || error "setstripe failed on $fm_file"
+       dd if=/dev/zero of=$fm_file bs=65536 count=1 || error "dd failed for $fm_file"
+
+       filefrag -ves $fm_file || error "filefrag $fm_file failed"
+       filefrag_op=`filefrag -ve $fm_file | grep -A 100 "ext:" | grep -v "ext:" | grep -v "found"`
+
+       lun=`$GETSTRIPE $fm_file  | grep -A 10 obdidx | awk '{print $1}' | grep -v "obdidx"`
+
+       start_blk=`echo $filefrag_op | cut -d: -f2 | cut -d. -f1`
+       IFS=$'\n'
+       tot_len=0
+       for line in $filefrag_op
+       do
+               frag_lun=`echo $line | cut -d: -f5`
+               ext_len=`echo $line | cut -d: -f4`
+               if (( $frag_lun != $lun )); then
+                       error "FIEMAP on 1-stripe file($fm_file) failed"
+                       return
+               fi
+               (( tot_len += ext_len ))
+       done
+
+       if (( lun != frag_lun || start_blk != 0 || tot_len != 64 )); then
+               error "FIEMAP on 1-stripe file($fm_file) failed;"
+               return
+       fi
+       echo "FIEMAP on single striped file succeeded"
+}
+run_test 130a "FIEMAP (1-stripe file)"
+
+test_130b() {
+       [ "$OSTCOUNT" -lt "2" ] && skip "skipping FIEMAP on 2-stripe file test" && return
+
+       filefrag_op=$(filefrag -e 2>&1 | grep "invalid option")
+       [ -n "$filefrag_op" ] && skip '"filefrag does not support FIEMAP" && return'
+
+       local fm_file=$DIR/$tfile
+       lfs setstripe -s 65536 -c 2 $fm_file || error "setstripe failed on $fm_file"
+       dd if=/dev/zero of=$fm_file bs=1M count=2 || error "dd failed on $fm_file"
+
+       filefrag -ves $fm_file || error "filefrag $fm_file failed"
+       filefrag_op=`filefrag -ve $fm_file | grep -A 100 "ext:" | grep -v "ext:" | grep -v "found"`
+
+       last_lun=`echo $filefrag_op | cut -d: -f5`
+
+       IFS=$'\n'
+       tot_len=0
+       num_luns=1
+       for line in $filefrag_op
+       do
+               frag_lun=`echo $line | cut -d: -f5`
+               ext_len=`echo $line | cut -d: -f4`
+               if (( $frag_lun != $last_lun )); then
+                       if (( tot_len != 1024 )); then
+                               error "FIEMAP on $fm_file failed; returned len $tot_len for OST $last_lun instead of 256"
+                               return
+                       else
+                               (( num_luns += 1 ))
+                               tot_len=0
+                       fi
+               fi
+               (( tot_len += ext_len ))
+               last_lun=$frag_lun
+       done
+       if (( num_luns != 2 || tot_len != 1024 )); then
+               error "FIEMAP on $fm_file failed; returned wrong number of luns or wrong len for OST $last_lun"
+               return
+       fi
+
+       echo "FIEMAP on 2-stripe file succeeded"
+}
+run_test 130b "FIEMAP (2-stripe file)"
+
+test_130c() {
+       [ "$OSTCOUNT" -lt "2" ] && skip "skipping FIEMAP on 2-stripe file with hole test" && return
+
+       filefrag_op=$(filefrag -e 2>&1 | grep "invalid option")
+       [ -n "$filefrag_op" ] && skip '"filefrag does not support FIEMAP" && return'
+
+       local fm_file=$DIR/$tfile
+       lfs setstripe -s 65536 -c 2 $fm_file || error "setstripe failed on $fm_file"
+       dd if=/dev/zero of=$fm_file seek=1 bs=1M count=1 || error "dd failed on $fm_file"
+
+       filefrag -ves $fm_file || error "filefrag $fm_file failed"
+       filefrag_op=`filefrag -ve $fm_file | grep -A 100 "ext:" | grep -v "ext:" | grep -v "found"`
+
+       last_lun=`echo $filefrag_op | cut -d: -f5`
+
+       IFS=$'\n'
+       tot_len=0
+       num_luns=1
+       for line in $filefrag_op
+       do
+               frag_lun=`echo $line | cut -d: -f5`
+               ext_len=`echo $line | cut -d: -f4`
+               if (( $frag_lun != $last_lun )); then
+                       logical=`echo $line | cut -d: -f2 | cut -d. -f1`
+                       if (( logical != 512 )); then
+                               error "FIEMAP on $fm_file failed; returned logical start for lun $logical instead of 512"
+                               return
+                       fi
+                       if (( tot_len != 512 )); then
+                               error "FIEMAP on $fm_file failed; returned len $tot_len for OST $last_lun instead of 1024"
+                               return
+                       else
+                               (( num_luns += 1 ))
+                               tot_len=0
+                       fi
+               fi
+               (( tot_len += ext_len ))
+               last_lun=$frag_lun
+       done
+       if (( num_luns != 2 || tot_len != 512 )); then
+               error "FIEMAP on $fm_file failed; returned wrong number of luns or wrong len for OST $last_lun"
+               return
+       fi
+
+       echo "FIEMAP on 2-stripe file with hole succeeded"
+}
+run_test 130c "FIEMAP (2-stripe file with hole)"
+
+test_130d() {
+       [ "$OSTCOUNT" -lt "3" ] && skip "skipping FIEMAP on N-stripe file test" && return
+
+       filefrag_op=$(filefrag -e 2>&1 | grep "invalid option")
+       [ -n "$filefrag_op" ] && skip '"filefrag does not support FIEMAP" && return'
+
+       local fm_file=$DIR/$tfile
+       lfs setstripe -s 65536 -c $OSTCOUNT $fm_file || error "setstripe failed on $fm_file"
+       dd if=/dev/zero of=$fm_file bs=1M count=$OSTCOUNT || error "dd failed on $fm_file"
+
+       filefrag -ves $fm_file || error "filefrag $fm_file failed"
+       filefrag_op=`filefrag -ve $fm_file | grep -A 100 "ext:" | grep -v "ext:" | grep -v "found"`
+
+       last_lun=`echo $filefrag_op | cut -d: -f5`
+
+       IFS=$'\n'
+       tot_len=0
+       num_luns=1
+       for line in $filefrag_op
+       do
+               frag_lun=`echo $line | cut -d: -f5`
+               ext_len=`echo $line | cut -d: -f4`
+               if (( $frag_lun != $last_lun )); then
+                       if (( tot_len != 1024 )); then
+                               error "FIEMAP on $fm_file failed; returned len $tot_len for OST $last_lun instead of 1024"
+                               return
+                       else
+                               (( num_luns += 1 ))
+                               tot_len=0
+                       fi
+               fi
+               (( tot_len += ext_len ))
+               last_lun=$frag_lun
+       done
+       if (( num_luns != OSTCOUNT || tot_len != 1024 )); then
+               error "FIEMAP on $fm_file failed; returned wrong number of luns or wrong len for OST $last_lun"
+               return
+       fi
+
+       echo "FIEMAP on N-stripe file succeeded"
+}
+run_test 130d "FIEMAP (N-stripe file)"
+
+test_130e() {
+       [ "$OSTCOUNT" -lt "2" ] && skip "skipping continuation FIEMAP test" && return
+
+       filefrag_op=$(filefrag -e 2>&1 | grep "invalid option")
+       [ -n "$filefrag_op" ] && skip '"filefrag does not support FIEMAP" && return'
+
+       local fm_file=$DIR/$tfile
+       lfs setstripe -s 65536 -c 2 $fm_file || error "setstripe failed on $fm_file"
+       NUM_BLKS=512
+       EXPECTED_LEN=$(( (NUM_BLKS / 2) * 4 ))
+       for ((i = 0; i < $NUM_BLKS; i++))
+       do
+               dd if=/dev/zero of=$fm_file count=1 bs=4096 seek=$((2*$i)) conv=notrunc > /dev/null 2>&1
+       done
+
+       filefrag -ves $fm_file || error "filefrag $fm_file failed"
+       filefrag_op=`filefrag -ve $fm_file | grep -A 750 "ext:" | grep -v "ext:" | grep -v "found"`
+
+       last_lun=`echo $filefrag_op | cut -d: -f5`
+
+       IFS=$'\n'
+       tot_len=0
+       num_luns=1
+       for line in $filefrag_op
+       do
+               frag_lun=`echo $line | cut -d: -f5`
+               ext_len=`echo $line | cut -d: -f4`
+               if (( $frag_lun != $last_lun )); then
+                       if (( tot_len != $EXPECTED_LEN )); then
+                               error "FIEMAP on $fm_file failed; returned len $tot_len for OST $last_lun instead of $EXPECTED_LEN"
+                               return
+                       else
+                               (( num_luns += 1 ))
+                               tot_len=0
+                       fi
+               fi
+               (( tot_len += ext_len ))
+               last_lun=$frag_lun
+       done
+       if (( num_luns != 2 || tot_len != $EXPECTED_LEN )); then
+               echo "$num_luns $tot_len"
+               error "FIEMAP on $fm_file failed; returned wrong number of luns or wrong len for OST $last_lun"
+               return
+       fi
+
+       echo "FIEMAP with continuation calls succeeded"
+}
+run_test 130e "FIEMAP (test continuation FIEMAP calls)"
+
 TMPDIR=$OLDTMPDIR
 TMP=$OLDTMP
 HOME=$OLDHOME
 TMPDIR=$OLDTMPDIR
 TMP=$OLDTMP
 HOME=$OLDHOME
index 7a36446..ef6d35b 100644 (file)
@@ -74,6 +74,7 @@
 #define lustre_swab_obd_ioobj NULL
 #define lustre_swab_ost_body NULL
 #define lustre_swab_ost_last_id NULL
 #define lustre_swab_obd_ioobj NULL
 #define lustre_swab_ost_body NULL
 #define lustre_swab_ost_last_id NULL
+#define lustre_swab_fiemap NULL
 
 /*
  * Yes, include .c file.
 
 /*
  * Yes, include .c file.
index e3ef19d..a2f72c4 100644 (file)
@@ -1063,6 +1063,50 @@ check_posix_acl_xattr_header(void)
 }
 
 static void
 }
 
 static void
+check_ll_user_fiemap(void)
+{
+        BLANK_LINE();
+        CHECK_STRUCT_TYPEDEF(ll_user_fiemap);
+        CHECK_MEMBER_TYPEDEF(ll_user_fiemap, fm_start);
+        CHECK_MEMBER_TYPEDEF(ll_user_fiemap, fm_length);
+        CHECK_MEMBER_TYPEDEF(ll_user_fiemap, fm_flags);
+        CHECK_MEMBER_TYPEDEF(ll_user_fiemap, fm_mapped_extents);
+        CHECK_MEMBER_TYPEDEF(ll_user_fiemap, fm_extent_count);
+        CHECK_MEMBER_TYPEDEF(ll_user_fiemap, fm_reserved);
+        CHECK_MEMBER_TYPEDEF(ll_user_fiemap, fm_extents);
+
+        CHECK_CDEFINE(FIEMAP_FLAG_SYNC);
+        CHECK_CDEFINE(FIEMAP_FLAG_XATTR);
+        CHECK_CDEFINE(FIEMAP_FLAG_DEVICE_ORDER);
+}
+
+static void
+check_ll_fiemap_extent(void)
+{
+        BLANK_LINE();
+        CHECK_STRUCT_TYPEDEF(ll_fiemap_extent);
+        CHECK_MEMBER_TYPEDEF(ll_fiemap_extent, fe_logical);
+        CHECK_MEMBER_TYPEDEF(ll_fiemap_extent, fe_physical);
+        CHECK_MEMBER_TYPEDEF(ll_fiemap_extent, fe_length);
+        CHECK_MEMBER_TYPEDEF(ll_fiemap_extent, fe_flags);
+        CHECK_MEMBER_TYPEDEF(ll_fiemap_extent, fe_device);
+
+        CHECK_CDEFINE(FIEMAP_EXTENT_LAST);
+        CHECK_CDEFINE(FIEMAP_EXTENT_UNKNOWN);
+        CHECK_CDEFINE(FIEMAP_EXTENT_DELALLOC);
+        CHECK_CDEFINE(FIEMAP_EXTENT_NO_DIRECT);
+        CHECK_CDEFINE(FIEMAP_EXTENT_SECONDARY);
+        CHECK_CDEFINE(FIEMAP_EXTENT_NET);
+        CHECK_CDEFINE(FIEMAP_EXTENT_DATA_COMPRESSED);
+        CHECK_CDEFINE(FIEMAP_EXTENT_DATA_ENCRYPTED);
+        CHECK_CDEFINE(FIEMAP_EXTENT_NOT_ALIGNED);
+        CHECK_CDEFINE(FIEMAP_EXTENT_DATA_INLINE);
+        CHECK_CDEFINE(FIEMAP_EXTENT_DATA_TAIL);
+        CHECK_CDEFINE(FIEMAP_EXTENT_UNWRITTEN);
+        CHECK_CDEFINE(FIEMAP_EXTENT_MERGED);
+}
+
+static void
 system_string (char *cmdline, char *str, int len)
 {
         int   fds[2];
 system_string (char *cmdline, char *str, int len)
 {
         int   fds[2];
@@ -1314,6 +1358,8 @@ main(int argc, char **argv)
 #endif
         check_posix_acl_xattr_entry();
         check_posix_acl_xattr_header();
 #endif
         check_posix_acl_xattr_entry();
         check_posix_acl_xattr_header();
+        check_ll_user_fiemap();
+        check_ll_fiemap_extent();
         printf("#endif\n");
 
 
         printf("#endif\n");