From 7a92b5181e1983a39630dce31c09407079fdbdbc Mon Sep 17 00:00:00 2001 From: kalpak Date: Fri, 8 Aug 2008 14:47:00 +0000 Subject: [PATCH] b=10555 i=adilger i=green i=nikita i=girish add ldiskfs patches and lustre support for FIEMAP ioctl --- lustre/ChangeLog | 7 + lustre/autoconf/lustre-core.m4 | 22 +++ lustre/include/lustre/Makefile.am | 4 +- lustre/include/lustre/ll_fiemap.h | 127 +++++++++++++ lustre/include/lustre/lustre_idl.h | 9 + lustre/include/lustre/lustre_user.h | 5 + lustre/include/lustre_req_layout.h | 3 + lustre/include/obd.h | 1 + lustre/llite/file.c | 110 +++++++++++ lustre/llite/llite_internal.h | 3 + lustre/lov/lov_obd.c | 357 ++++++++++++++++++++++++++++++++++++ lustre/lvfs/fsfilt_ext3.c | 9 +- lustre/obdfilter/filter.c | 33 ++++ lustre/osc/osc_request.c | 47 ++++- lustre/ptlrpc/layout.c | 25 +++ lustre/ptlrpc/pack_generic.c | 25 +++ lustre/ptlrpc/ptlrpc_module.c | 1 + lustre/tests/sanity.sh | 218 ++++++++++++++++++++++ lustre/utils/req-layout.c | 1 + lustre/utils/wirecheck.c | 46 +++++ 20 files changed, 1049 insertions(+), 4 deletions(-) create mode 100644 lustre/include/lustre/ll_fiemap.h diff --git a/lustre/ChangeLog b/lustre/ChangeLog index a726c5a..83f700f 100644 --- a/lustre/ChangeLog +++ b/lustre/ChangeLog @@ -1288,6 +1288,13 @@ Bugzilla : 16140 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. diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index c0e3a41..6a4e7a6 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -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 + ],[],[ + 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([ diff --git a/lustre/include/lustre/Makefile.am b/lustre/include/lustre/Makefile.am index bcf98cd..77e9d86 100644 --- a/lustre/include/lustre/Makefile.am +++ b/lustre/include/lustre/Makefile.am @@ -35,7 +35,7 @@ # 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 -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 index 0000000..e8620bf --- /dev/null +++ b/lustre/include/lustre/ll_fiemap.h @@ -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 + * Author: Andreas Dilger + */ + +#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 */ diff --git a/lustre/include/lustre/lustre_idl.h b/lustre/include/lustre/lustre_idl.h index 13dbe4e..17b4db6 100644 --- a/lustre/include/lustre/lustre_idl.h +++ b/lustre/include/lustre/lustre_idl.h @@ -88,6 +88,7 @@ /* Defn's shared with user-space. */ #include +#include /* * GENERAL STUFF @@ -972,8 +973,16 @@ struct ost_body { 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_fiemap(struct ll_user_fiemap *fiemap); /* lock value block communicated between the filter and llite */ diff --git a/lustre/include/lustre/lustre_user.h b/lustre/include/lustre/lustre_user.h index edb61e3..2fd8bc5 100644 --- a/lustre/include/lustre/lustre_user.h +++ b/lustre/include/lustre/lustre_user.h @@ -41,6 +41,7 @@ #ifndef _LUSTRE_USER_H #define _LUSTRE_USER_H +#include #if defined(__linux__) #include #elif defined(__APPLE__) @@ -61,8 +62,12 @@ #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 +/* FIEMAP flags supported by Lustre */ +#define LUSTRE_FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_DEVICE_ORDER) + struct obd_statfs; /* diff --git a/lustre/include/lustre_req_layout.h b/lustre/include/lustre_req_layout.h index a0d0468..1853571 100644 --- a/lustre/include/lustre_req_layout.h +++ b/lustre/include/lustre_req_layout.h @@ -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_GET_INFO_FIEMAP; /* 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_FIEMAP_KEY; +extern const struct req_msg_field RMF_FIEMAP_VAL; #endif /* _LUSTRE_REQ_LAYOUT_H__ */ diff --git a/lustre/include/obd.h b/lustre/include/obd.h index c96ff87..00e4a06 100644 --- a/lustre/include/obd.h +++ b/lustre/include/obd.h @@ -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_FIEMAP "FIEMAP" /* XXX unused ?*/ #define KEY_INTERMDS "inter_mds" #define KEY_ASYNC "async" diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 416fe42..73fb0a7 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -47,6 +47,7 @@ #include #include #include "llite_internal.h" +#include /* 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); } +/** + * 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) { @@ -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)); + 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)); diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index c9acb96..b5d9257 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -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 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, diff --git a/lustre/lov/lov_obd.c b/lustre/lov/lov_obd.c index 33def20..25de713 100644 --- a/lustre/lov/lov_obd.c +++ b/lustre/lov/lov_obd.c @@ -64,6 +64,7 @@ #include #include #include +#include #include "lov_internal.h" @@ -2507,6 +2508,358 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len, 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) @@ -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); } + } else if (KEY_IS(KEY_FIEMAP)) { + rc = lov_fiemap(lov, keylen, key, vallen, val, lsm); + GOTO(out, rc); } rc = -EINVAL; + out: lov_putref(obddev); RETURN(rc); diff --git a/lustre/lvfs/fsfilt_ext3.c b/lustre/lvfs/fsfilt_ext3.c index 447701d..4d43591 100644 --- a/lustre/lvfs/fsfilt_ext3.c +++ b/lustre/lvfs/fsfilt_ext3.c @@ -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, +#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, - 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 diff --git a/lustre/obdfilter/filter.c b/lustre/obdfilter/filter.c index 084dc8a..edd5cb8 100644 --- a/lustre/obdfilter/filter.c +++ b/lustre/obdfilter/filter.c @@ -75,6 +75,7 @@ #include #include #include +#include #include "filter_internal.h" @@ -4120,6 +4121,38 @@ static int filter_get_info(struct obd_export *exp, __u32 keylen, 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); } diff --git a/lustre/osc/osc_request.c b/lustre/osc/osc_request.c index f79aab7..dfb123b 100644 --- a/lustre/osc/osc_request.c +++ b/lustre/osc/osc_request.c @@ -3590,7 +3590,8 @@ out: } 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) @@ -3636,7 +3637,51 @@ static int osc_get_info(struct obd_export *exp, obd_count keylen, 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); } diff --git a/lustre/ptlrpc/layout.c b/lustre/ptlrpc/layout.c index c11e836..6e8af2e 100644 --- a/lustre/ptlrpc/layout.c +++ b/lustre/ptlrpc/layout.c @@ -504,6 +504,17 @@ static const struct req_msg_field *ost_get_last_id_server[] = { &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, @@ -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_GET_INFO_FIEMAP, &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); +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. @@ -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); +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__) diff --git a/lustre/ptlrpc/pack_generic.c b/lustre/ptlrpc/pack_generic.c index a60acbc..7df1357 100644 --- a/lustre/ptlrpc/pack_generic.c +++ b/lustre/ptlrpc/pack_generic.c @@ -53,6 +53,7 @@ #include #include #include +#include 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); } +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); diff --git a/lustre/ptlrpc/ptlrpc_module.c b/lustre/ptlrpc/ptlrpc_module.c index 521f6d4..cbdcc88 100644 --- a/lustre/ptlrpc/ptlrpc_module.c +++ b/lustre/ptlrpc/ptlrpc_module.c @@ -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_fiemap); /* recover.c */ EXPORT_SYMBOL(ptlrpc_disconnect_import); diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 8591117..f7d6352 100644 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -5259,6 +5259,224 @@ test_129() { 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 diff --git a/lustre/utils/req-layout.c b/lustre/utils/req-layout.c index 7a36446..ef6d35b 100644 --- a/lustre/utils/req-layout.c +++ b/lustre/utils/req-layout.c @@ -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_fiemap NULL /* * Yes, include .c file. diff --git a/lustre/utils/wirecheck.c b/lustre/utils/wirecheck.c index e3ef19d..a2f72c48 100644 --- a/lustre/utils/wirecheck.c +++ b/lustre/utils/wirecheck.c @@ -1063,6 +1063,50 @@ check_posix_acl_xattr_header(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]; @@ -1314,6 +1358,8 @@ main(int argc, char **argv) #endif check_posix_acl_xattr_entry(); check_posix_acl_xattr_header(); + check_ll_user_fiemap(); + check_ll_fiemap_extent(); printf("#endif\n"); -- 1.8.3.1