X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fllite%2Fllite_lib.c;h=ce55b7f3c59d41e7050677b5ccca9413aef4f639;hp=0f95175562cc1de71f41274d2754dff14761845f;hb=59a3d7237df82ac2ce14b6779577584163f9122b;hpb=acabfb9594c956081b615d22cfc1bd39e8a3f331 diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index 0f95175..ce55b7f 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -37,18 +37,23 @@ #define DEBUG_SUBSYSTEM S_LLITE #include +#include #include #include #include +#include #include #include #include -#ifdef HAVE_UIDGID_HEADER -# include -#endif +#include +#include #include #include +#ifdef HAVE_UAPI_LINUX_MOUNT_H +#include +#endif + #include #include #include @@ -71,44 +76,56 @@ static struct ll_sb_info *ll_init_sbi(void) unsigned long pages; unsigned long lru_page_max; struct sysinfo si; - class_uuid_t uuid; + int rc; int i; + ENTRY; OBD_ALLOC_PTR(sbi); if (sbi == NULL) - RETURN(NULL); + RETURN(ERR_PTR(-ENOMEM)); + + rc = pcc_super_init(&sbi->ll_pcc_super); + if (rc < 0) + GOTO(out_sbi, rc); spin_lock_init(&sbi->ll_lock); mutex_init(&sbi->ll_lco.lco_lock); spin_lock_init(&sbi->ll_pp_extent_lock); spin_lock_init(&sbi->ll_process_lock); sbi->ll_rw_stats_on = 0; + sbi->ll_statfs_max_age = OBD_STATFS_CACHE_SECONDS; si_meminfo(&si); pages = si.totalram - si.totalhigh; lru_page_max = pages / 2; + sbi->ll_ra_info.ra_async_max_active = 0; + sbi->ll_ra_info.ll_readahead_wq = + alloc_workqueue("ll-readahead-wq", WQ_UNBOUND, + sbi->ll_ra_info.ra_async_max_active); + if (!sbi->ll_ra_info.ll_readahead_wq) + GOTO(out_pcc, rc = -ENOMEM); + /* initialize ll_cache data */ sbi->ll_cache = cl_cache_init(lru_page_max); - if (sbi->ll_cache == NULL) { - OBD_FREE(sbi, sizeof(*sbi)); - RETURN(NULL); - } + if (sbi->ll_cache == NULL) + GOTO(out_destroy_ra, rc = -ENOMEM); sbi->ll_ra_info.ra_max_pages_per_file = min(pages / 32, - SBI_DEFAULT_READAHEAD_MAX); + SBI_DEFAULT_READ_AHEAD_MAX); + sbi->ll_ra_info.ra_async_pages_per_file_threshold = + sbi->ll_ra_info.ra_max_pages_per_file; sbi->ll_ra_info.ra_max_pages = sbi->ll_ra_info.ra_max_pages_per_file; sbi->ll_ra_info.ra_max_read_ahead_whole_pages = -1; - ll_generate_random_uuid(uuid); - class_uuid_unparse(uuid, &sbi->ll_sb_uuid); - CDEBUG(D_CONFIG, "generated uuid: %s\n", sbi->ll_sb_uuid.uuid); - sbi->ll_flags |= LL_SBI_VERBOSE; #ifdef ENABLE_CHECKSUM sbi->ll_flags |= LL_SBI_CHECKSUM; #endif +#ifdef ENABLE_FLOCK + sbi->ll_flags |= LL_SBI_FLOCK; +#endif #ifdef HAVE_LRU_RESIZE_SUPPORT sbi->ll_flags |= LL_SBI_LRU_RESIZE; @@ -123,6 +140,7 @@ static struct ll_sb_info *ll_init_sbi(void) } /* metadata statahead is enabled by default */ + sbi->ll_sa_running_max = LL_SA_RUNNING_DEF; sbi->ll_sa_max = LL_SA_RPC_DEF; atomic_set(&sbi->ll_sa_total, 0); atomic_set(&sbi->ll_sa_wrong, 0); @@ -130,14 +148,25 @@ static struct ll_sb_info *ll_init_sbi(void) atomic_set(&sbi->ll_agl_total, 0); sbi->ll_flags |= LL_SBI_AGL_ENABLED; sbi->ll_flags |= LL_SBI_FAST_READ; + sbi->ll_flags |= LL_SBI_TINY_WRITE; /* root squash */ sbi->ll_squash.rsi_uid = 0; sbi->ll_squash.rsi_gid = 0; INIT_LIST_HEAD(&sbi->ll_squash.rsi_nosquash_nids); - init_rwsem(&sbi->ll_squash.rsi_sem); + spin_lock_init(&sbi->ll_squash.rsi_lock); + /* Per-filesystem file heat */ + sbi->ll_heat_decay_weight = SBI_DEFAULT_HEAT_DECAY_WEIGHT; + sbi->ll_heat_period_second = SBI_DEFAULT_HEAT_PERIOD_SECOND; RETURN(sbi); +out_destroy_ra: + destroy_workqueue(sbi->ll_ra_info.ll_readahead_wq); +out_pcc: + pcc_super_fini(&sbi->ll_pcc_super); +out_sbi: + OBD_FREE_PTR(sbi); + RETURN(ERR_PTR(rc)); } static void ll_free_sbi(struct super_block *sb) @@ -148,39 +177,34 @@ static void ll_free_sbi(struct super_block *sb) if (sbi != NULL) { if (!list_empty(&sbi->ll_squash.rsi_nosquash_nids)) cfs_free_nidlist(&sbi->ll_squash.rsi_nosquash_nids); + if (sbi->ll_ra_info.ll_readahead_wq) + destroy_workqueue(sbi->ll_ra_info.ll_readahead_wq); if (sbi->ll_cache != NULL) { cl_cache_decref(sbi->ll_cache); sbi->ll_cache = NULL; } + pcc_super_fini(&sbi->ll_pcc_super); OBD_FREE(sbi, sizeof(*sbi)); } EXIT; } -static inline int obd_connect_has_secctx(struct obd_connect_data *data) -{ - return data->ocd_connect_flags & OBD_CONNECT_FLAGS2 && - data->ocd_connect_flags2 & OBD_CONNECT2_FILE_SECCTX; -} - -static int client_common_fill_super(struct super_block *sb, char *md, char *dt, - struct vfsmount *mnt) +static int client_common_fill_super(struct super_block *sb, char *md, char *dt) { struct inode *root = NULL; - struct ll_sb_info *sbi = ll_s2sbi(sb); - struct obd_device *obd; - struct obd_statfs *osfs = NULL; - struct ptlrpc_request *request = NULL; - struct obd_connect_data *data = NULL; - struct obd_uuid *uuid; - struct md_op_data *op_data; - struct lustre_md lmd; + struct ll_sb_info *sbi = ll_s2sbi(sb); + struct obd_statfs *osfs = NULL; + struct ptlrpc_request *request = NULL; + struct obd_connect_data *data = NULL; + struct obd_uuid *uuid; + struct md_op_data *op_data; + struct lustre_md lmd; u64 valid; - int size, err, checksum; - ENTRY; + int size, err, checksum; - obd = class_name2obd(md); - if (!obd) { + ENTRY; + sbi->ll_md_obd = class_name2obd(md); + if (!sbi->ll_md_obd) { CERROR("MD %s: not setup or attached\n", md); RETURN(-EINVAL); } @@ -223,67 +247,79 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, OBD_CONNECT_GRANT_PARAM | OBD_CONNECT_SHORTIO | OBD_CONNECT_FLAGS2; - data->ocd_connect_flags2 = OBD_CONNECT2_FLR; + data->ocd_connect_flags2 = OBD_CONNECT2_DIR_MIGRATE | + OBD_CONNECT2_SUM_STATFS | + OBD_CONNECT2_OVERSTRIPING | + OBD_CONNECT2_FLR | + OBD_CONNECT2_LOCK_CONVERT | + OBD_CONNECT2_ARCHIVE_ID_ARRAY | + OBD_CONNECT2_INC_XID | + OBD_CONNECT2_LSOM | + OBD_CONNECT2_ASYNC_DISCARD | + OBD_CONNECT2_PCC; #ifdef HAVE_LRU_RESIZE_SUPPORT if (sbi->ll_flags & LL_SBI_LRU_RESIZE) data->ocd_connect_flags |= OBD_CONNECT_LRU_RESIZE; #endif -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_LUSTRE_FS_POSIX_ACL data->ocd_connect_flags |= OBD_CONNECT_ACL | OBD_CONNECT_UMASK | OBD_CONNECT_LARGE_ACL; #endif - data->ocd_cksum_types = cksum_types_supported_client(); + data->ocd_cksum_types = obd_cksum_types_supported_client(); if (OBD_FAIL_CHECK(OBD_FAIL_MDC_LIGHTWEIGHT)) /* flag mdc connection as lightweight, only used for test * purpose, use with care */ - data->ocd_connect_flags |= OBD_CONNECT_LIGHTWEIGHT; + data->ocd_connect_flags |= OBD_CONNECT_LIGHTWEIGHT; - data->ocd_ibits_known = MDS_INODELOCK_FULL; - data->ocd_version = LUSTRE_VERSION_CODE; + data->ocd_ibits_known = MDS_INODELOCK_FULL; + data->ocd_version = LUSTRE_VERSION_CODE; - if (sb->s_flags & MS_RDONLY) - data->ocd_connect_flags |= OBD_CONNECT_RDONLY; - if (sbi->ll_flags & LL_SBI_USER_XATTR) - data->ocd_connect_flags |= OBD_CONNECT_XATTR; + if (sb->s_flags & SB_RDONLY) + data->ocd_connect_flags |= OBD_CONNECT_RDONLY; + if (sbi->ll_flags & LL_SBI_USER_XATTR) + data->ocd_connect_flags |= OBD_CONNECT_XATTR; -#ifdef MS_NOSEC +#ifdef SB_NOSEC /* Setting this indicates we correctly support S_NOSEC (See kernel * commit 9e1f1de02c2275d7172e18dc4e7c2065777611bf) */ - sb->s_flags |= MS_NOSEC; + sb->s_flags |= SB_NOSEC; #endif - if (sbi->ll_flags & LL_SBI_FLOCK) - sbi->ll_fop = &ll_file_operations_flock; - else if (sbi->ll_flags & LL_SBI_LOCALFLOCK) - sbi->ll_fop = &ll_file_operations; - else - sbi->ll_fop = &ll_file_operations_noflock; + if (sbi->ll_flags & LL_SBI_FLOCK) + sbi->ll_fop = &ll_file_operations_flock; + else if (sbi->ll_flags & LL_SBI_LOCALFLOCK) + sbi->ll_fop = &ll_file_operations; + else + sbi->ll_fop = &ll_file_operations_noflock; /* always ping even if server suppress_pings */ if (sbi->ll_flags & LL_SBI_ALWAYS_PING) data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS; -#if defined(HAVE_SECURITY_DENTRY_INIT_SECURITY) && defined(CONFIG_SECURITY) - data->ocd_connect_flags2 |= OBD_CONNECT2_FILE_SECCTX; -#endif /* HAVE_SECURITY_DENTRY_INIT_SECURITY */ + obd_connect_set_secctx(data); + +#if defined(CONFIG_SECURITY) + data->ocd_connect_flags2 |= OBD_CONNECT2_SELINUX_POLICY; +#endif data->ocd_brw_size = MD_MAX_BRW_SIZE; - err = obd_connect(NULL, &sbi->ll_md_exp, obd, &sbi->ll_sb_uuid, data, NULL); - if (err == -EBUSY) { - LCONSOLE_ERROR_MSG(0x14f, "An MDT (md %s) is performing " - "recovery, of which this client is not a " - "part. Please wait for recovery to complete," - " abort, or time out.\n", md); - GOTO(out, err); - } else if (err) { - CERROR("cannot connect to %s: rc = %d\n", md, err); - GOTO(out, err); - } + err = obd_connect(NULL, &sbi->ll_md_exp, sbi->ll_md_obd, + &sbi->ll_sb_uuid, data, sbi->ll_cache); + if (err == -EBUSY) { + LCONSOLE_ERROR_MSG(0x14f, "An MDT (md %s) is performing " + "recovery, of which this client is not a " + "part. Please wait for recovery to complete," + " abort, or time out.\n", md); + GOTO(out, err); + } else if (err) { + CERROR("cannot connect to %s: rc = %d\n", md, err); + GOTO(out, err); + } sbi->ll_md_exp->exp_connect_data = *data; @@ -299,7 +335,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, * can make sure the client can be mounted as long as MDT0 is * avaible */ err = obd_statfs(NULL, sbi->ll_md_exp, osfs, - ktime_get_seconds() -OBD_STATFS_CACHE_SECONDS, + ktime_get_seconds() - sbi->ll_statfs_max_age, OBD_STATFS_FOR_MDT0); if (err) GOTO(out_md_fid, err); @@ -345,28 +381,28 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, sbi->ll_namelen = osfs->os_namelen; sbi->ll_mnt.mnt = current->fs->root.mnt; - if ((sbi->ll_flags & LL_SBI_USER_XATTR) && - !(data->ocd_connect_flags & OBD_CONNECT_XATTR)) { - LCONSOLE_INFO("Disabling user_xattr feature because " - "it is not supported on the server\n"); - sbi->ll_flags &= ~LL_SBI_USER_XATTR; - } + if ((sbi->ll_flags & LL_SBI_USER_XATTR) && + !(data->ocd_connect_flags & OBD_CONNECT_XATTR)) { + LCONSOLE_INFO("Disabling user_xattr feature because " + "it is not supported on the server\n"); + sbi->ll_flags &= ~LL_SBI_USER_XATTR; + } - if (data->ocd_connect_flags & OBD_CONNECT_ACL) { -#ifdef MS_POSIXACL - sb->s_flags |= MS_POSIXACL; + if (data->ocd_connect_flags & OBD_CONNECT_ACL) { +#ifdef SB_POSIXACL + sb->s_flags |= SB_POSIXACL; #endif - sbi->ll_flags |= LL_SBI_ACL; - } else { - LCONSOLE_INFO("client wants to enable acl, but mdt not!\n"); -#ifdef MS_POSIXACL - sb->s_flags &= ~MS_POSIXACL; + sbi->ll_flags |= LL_SBI_ACL; + } else { + LCONSOLE_INFO("client wants to enable acl, but mdt not!\n"); +#ifdef SB_POSIXACL + sb->s_flags &= ~SB_POSIXACL; #endif - sbi->ll_flags &= ~LL_SBI_ACL; - } + sbi->ll_flags &= ~LL_SBI_ACL; + } - if (data->ocd_connect_flags & OBD_CONNECT_64BITHASH) - sbi->ll_flags |= LL_SBI_64BIT_HASH; + if (data->ocd_connect_flags & OBD_CONNECT_64BITHASH) + sbi->ll_flags |= LL_SBI_64BIT_HASH; if (data->ocd_connect_flags & OBD_CONNECT_LAYOUTLOCK) sbi->ll_flags |= LL_SBI_LAYOUT_LOCK; @@ -386,8 +422,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, } } - obd = class_name2obd(dt); - if (!obd) { + sbi->ll_dt_obd = class_name2obd(dt); + if (!sbi->ll_dt_obd) { CERROR("DT %s: not setup or attached\n", dt); GOTO(out_md_fid, err = -ENODEV); } @@ -409,7 +445,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, OBD_CONNECT_LAYOUTLOCK | OBD_CONNECT_PINGLESS | OBD_CONNECT_LFSCK | OBD_CONNECT_BULK_MBITS | OBD_CONNECT_SHORTIO | - OBD_CONNECT_FLAGS2; + OBD_CONNECT_FLAGS2 | OBD_CONNECT_GRANT_SHRINK; /* The client currently advertises support for OBD_CONNECT_LOCKAHEAD_OLD so it * can interoperate with an older version of lockahead which was released prior @@ -427,21 +463,23 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, data->ocd_connect_flags |= OBD_CONNECT_LOCKAHEAD_OLD; #endif - data->ocd_connect_flags2 = OBD_CONNECT2_LOCKAHEAD; + data->ocd_connect_flags2 = OBD_CONNECT2_LOCKAHEAD | + OBD_CONNECT2_INC_XID; if (!OBD_FAIL_CHECK(OBD_FAIL_OSC_CONNECT_GRANT_PARAM)) data->ocd_connect_flags |= OBD_CONNECT_GRANT_PARAM; /* OBD_CONNECT_CKSUM should always be set, even if checksums are * disabled by default, because it can still be enabled on the - * fly via /proc. As a consequence, we still need to come to an - * agreement on the supported algorithms at connect time */ + * fly via /sys. As a consequence, we still need to come to an + * agreement on the supported algorithms at connect time + */ data->ocd_connect_flags |= OBD_CONNECT_CKSUM; if (OBD_FAIL_CHECK(OBD_FAIL_OSC_CKSUM_ADLER_ONLY)) data->ocd_cksum_types = OBD_CKSUM_ADLER; else - data->ocd_cksum_types = cksum_types_supported_client(); + data->ocd_cksum_types = obd_cksum_types_supported_client(); #ifdef HAVE_LRU_RESIZE_SUPPORT data->ocd_connect_flags |= OBD_CONNECT_LRU_RESIZE; @@ -454,13 +492,13 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, "ocd_grant: %d\n", data->ocd_connect_flags, data->ocd_version, data->ocd_grant); - obd->obd_upcall.onu_owner = &sbi->ll_lco; - obd->obd_upcall.onu_upcall = cl_ocd_update; + sbi->ll_dt_obd->obd_upcall.onu_owner = &sbi->ll_lco; + sbi->ll_dt_obd->obd_upcall.onu_upcall = cl_ocd_update; data->ocd_brw_size = DT_MAX_BRW_SIZE; - err = obd_connect(NULL, &sbi->ll_dt_exp, obd, &sbi->ll_sb_uuid, data, - NULL); + err = obd_connect(NULL, &sbi->ll_dt_exp, sbi->ll_dt_obd, + &sbi->ll_sb_uuid, data, sbi->ll_cache); if (err == -EBUSY) { LCONSOLE_ERROR_MSG(0x150, "An OST (dt %s) is performing " "recovery, of which this client is not a " @@ -476,10 +514,15 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, sbi->ll_dt_exp->exp_connect_data = *data; /* Don't change value if it was specified in the config log */ - if (sbi->ll_ra_info.ra_max_read_ahead_whole_pages == -1) + if (sbi->ll_ra_info.ra_max_read_ahead_whole_pages == -1) { sbi->ll_ra_info.ra_max_read_ahead_whole_pages = - max_t(unsigned long, SBI_DEFAULT_READAHEAD_WHOLE_MAX, + max_t(unsigned long, SBI_DEFAULT_READ_AHEAD_WHOLE_MAX, (data->ocd_brw_size >> PAGE_SHIFT)); + if (sbi->ll_ra_info.ra_max_read_ahead_whole_pages > + sbi->ll_ra_info.ra_max_pages_per_file) + sbi->ll_ra_info.ra_max_read_ahead_whole_pages = + sbi->ll_ra_info.ra_max_pages_per_file; + } err = obd_fid_init(sbi->ll_dt_exp->exp_obd, sbi->ll_dt_exp, LUSTRE_SEQ_METADATA); @@ -511,9 +554,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, CDEBUG(D_SUPER, "rootfid "DFID"\n", PFID(&sbi->ll_root_fid)); sb->s_op = &lustre_super_operations; -#ifdef HAVE_XATTR_HANDLER_FLAGS sb->s_xattr = ll_xattr_handlers; -#endif #if THREAD_SIZE >= 8192 /*b=17630*/ sb->s_export_op = &lustre_export_operations; #endif @@ -557,7 +598,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, ptlrpc_req_finished(request); if (IS_ERR(root)) { -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_LUSTRE_FS_POSIX_ACL if (lmd.posix_acl) { posix_acl_release(lmd.posix_acl); lmd.posix_acl = NULL; @@ -565,39 +606,31 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, #endif err = IS_ERR(root) ? PTR_ERR(root) : -EBADF; root = NULL; - CERROR("lustre_lite: bad iget4 for root\n"); + CERROR("%s: bad ll_iget() for root: rc = %d\n", + sbi->ll_fsname, err); GOTO(out_root, err); } checksum = sbi->ll_flags & LL_SBI_CHECKSUM; - err = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_CHECKSUM), - KEY_CHECKSUM, sizeof(checksum), &checksum, - NULL); - if (err) { - CERROR("%s: Set checksum failed: rc = %d\n", - sbi->ll_dt_exp->exp_obd->obd_name, err); - GOTO(out_root, err); + if (sbi->ll_checksum_set) { + err = obd_set_info_async(NULL, sbi->ll_dt_exp, + sizeof(KEY_CHECKSUM), KEY_CHECKSUM, + sizeof(checksum), &checksum, NULL); + if (err) { + CERROR("%s: Set checksum failed: rc = %d\n", + sbi->ll_dt_exp->exp_obd->obd_name, err); + GOTO(out_root, err); + } } cl_sb_init(sb); - err = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_CACHE_SET), - KEY_CACHE_SET, sizeof(*sbi->ll_cache), - sbi->ll_cache, NULL); - if (err) { - CERROR("%s: Set cache_set failed: rc = %d\n", - sbi->ll_dt_exp->exp_obd->obd_name, err); - GOTO(out_root, err); - } - sb->s_root = d_make_root(root); if (sb->s_root == NULL) { - CERROR("%s: can't make root dentry\n", - ll_get_fsname(sb, NULL, 0)); - GOTO(out_root, err = -ENOMEM); + err = -ENOMEM; + CERROR("%s: can't make root dentry: rc = %d\n", + sbi->ll_fsname, err); + GOTO(out_root, err); } -#ifdef HAVE_DCACHE_LOCK - sb->s_root->d_op = &ll_d_ops; -#endif sbi->ll_sdev_orig = sb->s_dev; @@ -615,17 +648,24 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, if (osfs != NULL) OBD_FREE_PTR(osfs); - if (sbi->ll_proc_root != NULL) { - err = lprocfs_ll_register_obd(sb, dt); + if (sbi->ll_dt_obd) { + err = sysfs_create_link(&sbi->ll_kset.kobj, + &sbi->ll_dt_obd->obd_kset.kobj, + sbi->ll_dt_obd->obd_type->typ_name); if (err < 0) { CERROR("%s: could not register %s in llite: rc = %d\n", - dt, ll_get_fsname(sb, NULL, 0), err); + dt, sbi->ll_fsname, err); err = 0; } - err = lprocfs_ll_register_obd(sb, md); + } + + if (sbi->ll_md_obd) { + err = sysfs_create_link(&sbi->ll_kset.kobj, + &sbi->ll_md_obd->obd_kset.kobj, + sbi->ll_md_obd->obd_type->typ_name); if (err < 0) { CERROR("%s: could not register %s in llite: rc = %d\n", - md, ll_get_fsname(sb, NULL, 0), err); + md, sbi->ll_fsname, err); err = 0; } } @@ -639,11 +679,13 @@ out_lock_cn_cb: out_dt: obd_disconnect(sbi->ll_dt_exp); sbi->ll_dt_exp = NULL; + sbi->ll_dt_obd = NULL; out_md_fid: obd_fid_fini(sbi->ll_md_exp->exp_obd); out_md: obd_disconnect(sbi->ll_md_exp); sbi->ll_md_exp = NULL; + sbi->ll_md_obd = NULL; out: if (data != NULL) OBD_FREE_PTR(data); @@ -665,12 +707,16 @@ int ll_get_max_mdsize(struct ll_sb_info *sbi, int *lmmsize) RETURN(rc); } + CDEBUG(D_INFO, "max LOV ea size: %d\n", *lmmsize); + size = sizeof(int); rc = obd_get_info(NULL, sbi->ll_md_exp, sizeof(KEY_MAX_EASIZE), KEY_MAX_EASIZE, &size, lmmsize); if (rc) CERROR("Get max mdsize error rc %d\n", rc); + CDEBUG(D_INFO, "max LMV ea size: %d\n", *lmmsize); + RETURN(rc); } @@ -735,7 +781,7 @@ static void client_common_put_super(struct super_block *sb) obd_disconnect(sbi->ll_dt_exp); sbi->ll_dt_exp = NULL; - lprocfs_ll_unregister_mountpoint(sbi); + ll_debugfs_unregister_super(sb); obd_fid_fini(sbi->ll_md_exp->exp_obd); obd_disconnect(sbi->ll_md_exp); @@ -749,8 +795,8 @@ void ll_kill_super(struct super_block *sb) struct ll_sb_info *sbi; ENTRY; - /* not init sb ?*/ - if (!(sb->s_flags & MS_ACTIVE)) + /* not init sb ?*/ + if (!(sb->s_flags & SB_ACTIVE)) return; sbi = ll_s2sbi(sb); @@ -759,13 +805,11 @@ void ll_kill_super(struct super_block *sb) * put_super not affected real removing devices */ if (sbi) { sb->s_dev = sbi->ll_sdev_orig; - sbi->ll_umounting = 1; /* wait running statahead threads to quit */ - while (atomic_read(&sbi->ll_sa_running) > 0) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(MSEC_PER_SEC >> 3)); - } + while (atomic_read(&sbi->ll_sa_running) > 0) + schedule_timeout_uninterruptible( + cfs_time_seconds(1) >> 3); } EXIT; @@ -773,56 +817,57 @@ void ll_kill_super(struct super_block *sb) static inline int ll_set_opt(const char *opt, char *data, int fl) { - if (strncmp(opt, data, strlen(opt)) != 0) - return(0); - else - return(fl); + if (strncmp(opt, data, strlen(opt)) != 0) + return 0; + else + return fl; } /* non-client-specific mount options are parsed in lmd_parse */ -static int ll_options(char *options, int *flags) +static int ll_options(char *options, struct ll_sb_info *sbi) { - int tmp; - char *s1 = options, *s2; - ENTRY; + int tmp; + char *s1 = options, *s2; + int *flags = &sbi->ll_flags; + ENTRY; - if (!options) - RETURN(0); + if (!options) + RETURN(0); - CDEBUG(D_CONFIG, "Parsing opts %s\n", options); + CDEBUG(D_CONFIG, "Parsing opts %s\n", options); - while (*s1) { - CDEBUG(D_SUPER, "next opt=%s\n", s1); - tmp = ll_set_opt("nolock", s1, LL_SBI_NOLCK); - if (tmp) { - *flags |= tmp; - goto next; - } - tmp = ll_set_opt("flock", s1, LL_SBI_FLOCK); - if (tmp) { - *flags |= tmp; - goto next; - } - tmp = ll_set_opt("localflock", s1, LL_SBI_LOCALFLOCK); - if (tmp) { - *flags |= tmp; - goto next; - } - tmp = ll_set_opt("noflock", s1, LL_SBI_FLOCK|LL_SBI_LOCALFLOCK); - if (tmp) { - *flags &= ~tmp; - goto next; - } - tmp = ll_set_opt("user_xattr", s1, LL_SBI_USER_XATTR); - if (tmp) { - *flags |= tmp; - goto next; - } - tmp = ll_set_opt("nouser_xattr", s1, LL_SBI_USER_XATTR); - if (tmp) { - *flags &= ~tmp; - goto next; - } + while (*s1) { + CDEBUG(D_SUPER, "next opt=%s\n", s1); + tmp = ll_set_opt("nolock", s1, LL_SBI_NOLCK); + if (tmp) { + *flags |= tmp; + goto next; + } + tmp = ll_set_opt("flock", s1, LL_SBI_FLOCK); + if (tmp) { + *flags = (*flags & ~LL_SBI_LOCALFLOCK) | tmp; + goto next; + } + tmp = ll_set_opt("localflock", s1, LL_SBI_LOCALFLOCK); + if (tmp) { + *flags = (*flags & ~LL_SBI_FLOCK) | tmp; + goto next; + } + tmp = ll_set_opt("noflock", s1, LL_SBI_FLOCK|LL_SBI_LOCALFLOCK); + if (tmp) { + *flags &= ~tmp; + goto next; + } + tmp = ll_set_opt("user_xattr", s1, LL_SBI_USER_XATTR); + if (tmp) { + *flags |= tmp; + goto next; + } + tmp = ll_set_opt("nouser_xattr", s1, LL_SBI_USER_XATTR); + if (tmp) { + *flags &= ~tmp; + goto next; + } tmp = ll_set_opt("context", s1, 1); if (tmp) goto next; @@ -846,16 +891,18 @@ static int ll_options(char *options, int *flags) goto next; } - tmp = ll_set_opt("checksum", s1, LL_SBI_CHECKSUM); - if (tmp) { - *flags |= tmp; - goto next; - } - tmp = ll_set_opt("nochecksum", s1, LL_SBI_CHECKSUM); - if (tmp) { - *flags &= ~tmp; - goto next; - } + tmp = ll_set_opt("checksum", s1, LL_SBI_CHECKSUM); + if (tmp) { + *flags |= tmp; + sbi->ll_checksum_set = 1; + goto next; + } + tmp = ll_set_opt("nochecksum", s1, LL_SBI_CHECKSUM); + if (tmp) { + *flags &= ~tmp; + sbi->ll_checksum_set = 1; + goto next; + } tmp = ll_set_opt("lruresize", s1, LL_SBI_LRU_RESIZE); if (tmp) { *flags |= tmp; @@ -935,28 +982,40 @@ void ll_lli_init(struct ll_inode_info *lli) LASSERT(lli->lli_vfs_inode.i_mode != 0); if (S_ISDIR(lli->lli_vfs_inode.i_mode)) { - mutex_init(&lli->lli_readdir_mutex); lli->lli_opendir_key = NULL; lli->lli_sai = NULL; spin_lock_init(&lli->lli_sa_lock); lli->lli_opendir_pid = 0; lli->lli_sa_enabled = 0; - lli->lli_def_stripe_offset = -1; + init_rwsem(&lli->lli_lsm_sem); } else { mutex_init(&lli->lli_size_mutex); lli->lli_symlink_name = NULL; - init_rwsem(&lli->lli_trunc_sem); + ll_trunc_sem_init(&lli->lli_trunc_sem); range_lock_tree_init(&lli->lli_write_tree); init_rwsem(&lli->lli_glimpse_sem); lli->lli_glimpse_time = ktime_set(0, 0); INIT_LIST_HEAD(&lli->lli_agl_list); lli->lli_agl_index = 0; lli->lli_async_rc = 0; + spin_lock_init(&lli->lli_heat_lock); + obd_heat_clear(lli->lli_heat_instances, OBD_HEAT_COUNT); + lli->lli_heat_flags = 0; + mutex_init(&lli->lli_pcc_lock); + lli->lli_pcc_state = PCC_STATE_FL_NONE; + lli->lli_pcc_inode = NULL; + lli->lli_pcc_dsflags = PCC_DATASET_INVALID; + lli->lli_pcc_generation = 0; + mutex_init(&lli->lli_group_mutex); + lli->lli_group_users = 0; + lli->lli_group_gid = 0; } mutex_init(&lli->lli_layout_mutex); - memset(lli->lli_jobid, 0, LUSTRE_JOBID_SIZE); + memset(lli->lli_jobid, 0, sizeof(lli->lli_jobid)); } +#define MAX_STRING_SIZE 128 + #ifndef HAVE_SUPER_SETUP_BDI_NAME #define LSI_BDI_INITIALIZED 0x00400000 @@ -965,8 +1024,6 @@ void ll_lli_init(struct ll_inode_info *lli) # define BDI_CAP_MAP_COPY 0 #endif -#define MAX_STRING_SIZE 128 - static int super_setup_bdi_name(struct super_block *sb, char *fmt, ...) { struct lustre_sb_info *lsi = s2lsi(sb); @@ -993,7 +1050,7 @@ static int super_setup_bdi_name(struct super_block *sb, char *fmt, ...) } #endif /* !HAVE_SUPER_SETUP_BDI_NAME */ -int ll_fill_super(struct super_block *sb, struct vfsmount *mnt) +int ll_fill_super(struct super_block *sb) { struct lustre_profile *lprof = NULL; struct lustre_sb_info *lsi = s2lsi(sb); @@ -1002,60 +1059,91 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt) char *profilenm = get_profile_name(sb); struct config_llog_instance *cfg; /* %p for void* in printf needs 16+2 characters: 0xffffffffffffffff */ - const int instlen = sizeof(cfg->cfg_instance) * 2 + 2; - int md_len = 0; - int dt_len = 0; - int err; - ENTRY; - - CDEBUG(D_VFSTRACE, "VFS Op: sb %p\n", sb); + const int instlen = LUSTRE_MAXINSTANCE + 2; + unsigned long cfg_instance = ll_get_cfg_instance(sb); + char name[MAX_STRING_SIZE]; + int md_len = 0; + int dt_len = 0; + uuid_t uuid; + char *ptr; + int len; + int err; - try_module_get(THIS_MODULE); + ENTRY; + /* for ASLR, to map between cfg_instance and hashed ptr */ + CDEBUG(D_VFSTRACE, "VFS Op: cfg_instance %s-%016lx (sb %p)\n", + profilenm, cfg_instance, sb); OBD_ALLOC_PTR(cfg); if (cfg == NULL) - GOTO(out_free, err = -ENOMEM); + GOTO(out_free_cfg, err = -ENOMEM); /* client additional sb info */ lsi->lsi_llsbi = sbi = ll_init_sbi(); - if (!sbi) - GOTO(out_free, err = -ENOMEM); + if (IS_ERR(sbi)) + GOTO(out_free_cfg, err = PTR_ERR(sbi)); - err = ll_options(lsi->lsi_lmd->lmd_opts, &sbi->ll_flags); + err = ll_options(lsi->lsi_lmd->lmd_opts, sbi); if (err) - GOTO(out_free, err); + GOTO(out_free_cfg, err); - err = super_setup_bdi_name(sb, "lustre-%p", sb); - if (err) - GOTO(out_free, err); - -#ifndef HAVE_DCACHE_LOCK /* kernel >= 2.6.38 store dentry operations in sb->s_d_op. */ sb->s_d_op = &ll_d_ops; -#endif - /* Call lprocfs_ll_register_mountpoint() before lustre_process_log() - * so that "llite.*.*" params can be processed correctly. */ - if (proc_lustre_fs_root != NULL) { - err = lprocfs_ll_register_mountpoint(proc_lustre_fs_root, sb); - if (err < 0) { - CERROR("%s: could not register mountpoint in llite: " - "rc = %d\n", ll_get_fsname(sb, NULL, 0), err); - err = 0; - } + /* UUID handling */ + generate_random_uuid(uuid.b); + snprintf(sbi->ll_sb_uuid.uuid, UUID_SIZE, "%pU", uuid.b); + + CDEBUG(D_CONFIG, "llite sb uuid: %s\n", sbi->ll_sb_uuid.uuid); + + /* Get fsname */ + len = strlen(profilenm); + ptr = strrchr(profilenm, '-'); + if (ptr && (strcmp(ptr, "-client") == 0)) + len -= 7; + + if (len > LUSTRE_MAXFSNAME) { + if (unlikely(len >= MAX_STRING_SIZE)) + len = MAX_STRING_SIZE - 1; + strncpy(name, profilenm, len); + name[len] = '\0'; + err = -ENAMETOOLONG; + CERROR("%s: fsname longer than %u characters: rc = %d\n", + name, LUSTRE_MAXFSNAME, err); + GOTO(out_free_cfg, err); + } + strncpy(sbi->ll_fsname, profilenm, len); + sbi->ll_fsname[len] = '\0'; + + /* Mount info */ + snprintf(name, sizeof(name), "%.*s-%016lx", len, + profilenm, cfg_instance); + + err = super_setup_bdi_name(sb, "%s", name); + if (err) + GOTO(out_free_cfg, err); + + /* Call ll_debugfs_register_super() before lustre_process_log() + * so that "llite.*.*" params can be processed correctly. + */ + err = ll_debugfs_register_super(sb, name); + if (err < 0) { + CERROR("%s: could not register mountpoint in llite: rc = %d\n", + sbi->ll_fsname, err); + err = 0; } - /* Generate a string unique to this super, in case some joker tries - to mount the same fs at two mount points. - Use the address of the super itself.*/ - cfg->cfg_instance = sb; + /* The cfg_instance is a value unique to this super, in case some + * joker tries to mount the same fs at two mount points. + */ + cfg->cfg_instance = cfg_instance; cfg->cfg_uuid = lsi->lsi_llsbi->ll_sb_uuid; cfg->cfg_callback = class_config_llog_handler; cfg->cfg_sub_clds = CONFIG_SUB_CLIENT; /* set up client obds */ err = lustre_process_log(sb, profilenm, cfg); if (err < 0) - GOTO(out_proc, err); + GOTO(out_debugfs, err); /* Profile set with LCFG_MOUNTOPT so we can find our mdc and osc obds */ lprof = class_get_profile(profilenm); @@ -1063,7 +1151,7 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt) LCONSOLE_ERROR_MSG(0x156, "The client profile '%s' could not be" " read from the MGS. Does that filesystem " "exist?\n", profilenm); - GOTO(out_proc, err = -EINVAL); + GOTO(out_debugfs, err = -EINVAL); } CDEBUG(D_CONFIG, "Found profile %s: mdc=%s osc=%s\n", profilenm, lprof->lp_md, lprof->lp_dt); @@ -1071,34 +1159,38 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt) dt_len = strlen(lprof->lp_dt) + instlen + 2; OBD_ALLOC(dt, dt_len); if (!dt) - GOTO(out_proc, err = -ENOMEM); - snprintf(dt, dt_len - 1, "%s-%p", lprof->lp_dt, cfg->cfg_instance); + GOTO(out_profile, err = -ENOMEM); + snprintf(dt, dt_len - 1, "%s-%016lx", lprof->lp_dt, cfg_instance); md_len = strlen(lprof->lp_md) + instlen + 2; OBD_ALLOC(md, md_len); if (!md) - GOTO(out_proc, err = -ENOMEM); - snprintf(md, md_len - 1, "%s-%p", lprof->lp_md, cfg->cfg_instance); + GOTO(out_free_dt, err = -ENOMEM); + snprintf(md, md_len - 1, "%s-%016lx", lprof->lp_md, cfg_instance); /* connections, registrations, sb setup */ - err = client_common_fill_super(sb, md, dt, mnt); + err = client_common_fill_super(sb, md, dt); if (err < 0) - GOTO(out_proc, err); + GOTO(out_free_md, err); sbi->ll_client_common_fill_super_succeeded = 1; -out_proc: - if (err < 0) - lprocfs_ll_unregister_mountpoint(sbi); -out_free: +out_free_md: if (md) OBD_FREE(md, md_len); +out_free_dt: if (dt) OBD_FREE(dt, dt_len); - if (lprof != NULL) +out_profile: + if (lprof) class_put_profile(lprof); +out_debugfs: + if (err < 0) + ll_debugfs_unregister_super(sb); +out_free_cfg: if (cfg) OBD_FREE_PTR(cfg); + if (err) ll_put_super(sb); else if (sbi->ll_flags & LL_SBI_VERBOSE) @@ -1109,69 +1201,70 @@ out_free: void ll_put_super(struct super_block *sb) { struct config_llog_instance cfg, params_cfg; - struct obd_device *obd; - struct lustre_sb_info *lsi = s2lsi(sb); - struct ll_sb_info *sbi = ll_s2sbi(sb); - char *profilenm = get_profile_name(sb); + struct obd_device *obd; + struct lustre_sb_info *lsi = s2lsi(sb); + struct ll_sb_info *sbi = ll_s2sbi(sb); + char *profilenm = get_profile_name(sb); + unsigned long cfg_instance = ll_get_cfg_instance(sb); long ccc_count; int next, force = 1, rc = 0; - ENTRY; + ENTRY; - if (!sbi) + if (IS_ERR(sbi)) GOTO(out_no_sbi, 0); - CDEBUG(D_VFSTRACE, "VFS Op: sb %p - %s\n", sb, profilenm); + /* Should replace instance_id with something better for ASLR */ + CDEBUG(D_VFSTRACE, "VFS Op: cfg_instance %s-%016lx (sb %p)\n", + profilenm, cfg_instance, sb); - cfg.cfg_instance = sb; - lustre_end_log(sb, profilenm, &cfg); + cfg.cfg_instance = cfg_instance; + lustre_end_log(sb, profilenm, &cfg); - params_cfg.cfg_instance = sb; + params_cfg.cfg_instance = cfg_instance; lustre_end_log(sb, PARAMS_FILENAME, ¶ms_cfg); - if (sbi->ll_md_exp) { - obd = class_exp2obd(sbi->ll_md_exp); - if (obd) - force = obd->obd_force; - } + if (sbi->ll_md_exp) { + obd = class_exp2obd(sbi->ll_md_exp); + if (obd) + force = obd->obd_force; + } /* Wait for unstable pages to be committed to stable storage */ if (force == 0) { - struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); - rc = l_wait_event(sbi->ll_cache->ccc_unstable_waitq, - atomic_long_read(&sbi->ll_cache->ccc_unstable_nr) == 0, - &lwi); + rc = l_wait_event_abortable( + sbi->ll_cache->ccc_unstable_waitq, + atomic_long_read(&sbi->ll_cache->ccc_unstable_nr) == 0); } ccc_count = atomic_long_read(&sbi->ll_cache->ccc_unstable_nr); - if (force == 0 && rc != -EINTR) + if (force == 0 && rc != -ERESTARTSYS) LASSERTF(ccc_count == 0, "count: %li\n", ccc_count); - - /* We need to set force before the lov_disconnect in - lustre_common_put_super, since l_d cleans up osc's as well. */ - if (force) { - next = 0; - while ((obd = class_devices_in_group(&sbi->ll_sb_uuid, - &next)) != NULL) { - obd->obd_force = force; - } - } + /* We need to set force before the lov_disconnect in + * lustre_common_put_super, since l_d cleans up osc's as well. + */ + if (force) { + next = 0; + while ((obd = class_devices_in_group(&sbi->ll_sb_uuid, + &next)) != NULL) { + obd->obd_force = force; + } + } if (sbi->ll_client_common_fill_super_succeeded) { /* Only if client_common_fill_super succeeded */ client_common_put_super(sb); } - next = 0; - while ((obd = class_devices_in_group(&sbi->ll_sb_uuid, &next)) !=NULL) { - class_manual_cleanup(obd); - } + next = 0; + while ((obd = class_devices_in_group(&sbi->ll_sb_uuid, &next))) + class_manual_cleanup(obd); - if (sbi->ll_flags & LL_SBI_VERBOSE) - LCONSOLE_WARN("Unmounted %s\n", profilenm ? profilenm : ""); + if (sbi->ll_flags & LL_SBI_VERBOSE) + LCONSOLE_WARN("Unmounted %s\n", profilenm ? profilenm : ""); - if (profilenm) - class_del_profile(profilenm); + if (profilenm) + class_del_profile(profilenm); #ifndef HAVE_SUPER_SETUP_BDI_NAME if (lsi->lsi_flags & LSI_BDI_INITIALIZED) { @@ -1180,8 +1273,8 @@ void ll_put_super(struct super_block *sb) } #endif - ll_free_sbi(sb); - lsi->lsi_llsbi = NULL; + ll_free_sbi(sb); + lsi->lsi_llsbi = NULL; out_no_sbi: lustre_common_put_super(sb); @@ -1223,10 +1316,15 @@ void ll_dir_clear_lsm_md(struct inode *inode) LASSERT(S_ISDIR(inode->i_mode)); - if (lli->lli_lsm_md != NULL) { + if (lli->lli_lsm_md) { lmv_free_memmd(lli->lli_lsm_md); lli->lli_lsm_md = NULL; } + + if (lli->lli_default_lsm_md) { + lmv_free_memmd(lli->lli_default_lsm_md); + lli->lli_default_lsm_md = NULL; + } } static struct inode *ll_iget_anon_dir(struct super_block *sb, @@ -1243,7 +1341,7 @@ static struct inode *ll_iget_anon_dir(struct super_block *sb, inode = iget_locked(sb, ino); if (inode == NULL) { CERROR("%s: failed get simple inode "DFID": rc = -ENOENT\n", - ll_get_fsname(sb, NULL, 0), PFID(fid)); + sbi->ll_fsname, PFID(fid)); RETURN(ERR_PTR(-ENOENT)); } @@ -1256,9 +1354,9 @@ static struct inode *ll_iget_anon_dir(struct super_block *sb, LASSERTF(S_ISDIR(inode->i_mode), "Not slave inode "DFID"\n", PFID(fid)); - LTIME_S(inode->i_mtime) = 0; - LTIME_S(inode->i_atime) = 0; - LTIME_S(inode->i_ctime) = 0; + inode->i_mtime.tv_sec = 0; + inode->i_atime.tv_sec = 0; + inode->i_ctime.tv_sec = 0; inode->i_rdev = 0; #ifdef HAVE_BACKING_DEV_INFO @@ -1286,108 +1384,176 @@ static int ll_init_lsm_md(struct inode *inode, struct lustre_md *md) { struct lu_fid *fid; struct lmv_stripe_md *lsm = md->lmv; + struct ll_inode_info *lli = ll_i2info(inode); int i; LASSERT(lsm != NULL); + + CDEBUG(D_INODE, "%s: "DFID" set dir layout:\n", + ll_i2sbi(inode)->ll_fsname, PFID(&lli->lli_fid)); + lsm_md_dump(D_INODE, lsm); + + if (!lmv_dir_striped(lsm)) + goto out; + /* XXX sigh, this lsm_root initialization should be in * LMV layer, but it needs ll_iget right now, so we * put this here right now. */ for (i = 0; i < lsm->lsm_md_stripe_count; i++) { fid = &lsm->lsm_md_oinfo[i].lmo_fid; LASSERT(lsm->lsm_md_oinfo[i].lmo_root == NULL); + + if (!fid_is_sane(fid)) + continue; + /* Unfortunately ll_iget will call ll_update_inode, * where the initialization of slave inode is slightly * different, so it reset lsm_md to NULL to avoid * initializing lsm for slave inode. */ - /* For migrating inode, master stripe and master object will - * be same, so we only need assign this inode */ - if (lsm->lsm_md_hash_type & LMV_HASH_FLAG_MIGRATION && i == 0) - lsm->lsm_md_oinfo[i].lmo_root = inode; - else - lsm->lsm_md_oinfo[i].lmo_root = + lsm->lsm_md_oinfo[i].lmo_root = ll_iget_anon_dir(inode->i_sb, fid, md); - if (IS_ERR(lsm->lsm_md_oinfo[i].lmo_root)) { int rc = PTR_ERR(lsm->lsm_md_oinfo[i].lmo_root); lsm->lsm_md_oinfo[i].lmo_root = NULL; + while (i-- > 0) { + iput(lsm->lsm_md_oinfo[i].lmo_root); + lsm->lsm_md_oinfo[i].lmo_root = NULL; + } return rc; } } +out: + lli->lli_lsm_md = lsm; return 0; } -static inline int lli_lsm_md_eq(const struct lmv_stripe_md *lsm_md1, - const struct lmv_stripe_md *lsm_md2) +static void ll_update_default_lsm_md(struct inode *inode, struct lustre_md *md) { - return lsm_md1->lsm_md_magic == lsm_md2->lsm_md_magic && - lsm_md1->lsm_md_stripe_count == lsm_md2->lsm_md_stripe_count && - lsm_md1->lsm_md_master_mdt_index == - lsm_md2->lsm_md_master_mdt_index && - lsm_md1->lsm_md_hash_type == lsm_md2->lsm_md_hash_type && - lsm_md1->lsm_md_layout_version == - lsm_md2->lsm_md_layout_version && - strcmp(lsm_md1->lsm_md_pool_name, - lsm_md2->lsm_md_pool_name) == 0; + struct ll_inode_info *lli = ll_i2info(inode); + + if (!md->default_lmv) { + /* clear default lsm */ + if (lli->lli_default_lsm_md) { + down_write(&lli->lli_lsm_sem); + if (lli->lli_default_lsm_md) { + lmv_free_memmd(lli->lli_default_lsm_md); + lli->lli_default_lsm_md = NULL; + } + up_write(&lli->lli_lsm_sem); + } + } else if (lli->lli_default_lsm_md) { + /* update default lsm if it changes */ + down_read(&lli->lli_lsm_sem); + if (lli->lli_default_lsm_md && + !lsm_md_eq(lli->lli_default_lsm_md, md->default_lmv)) { + up_read(&lli->lli_lsm_sem); + down_write(&lli->lli_lsm_sem); + if (lli->lli_default_lsm_md) + lmv_free_memmd(lli->lli_default_lsm_md); + lli->lli_default_lsm_md = md->default_lmv; + lsm_md_dump(D_INODE, md->default_lmv); + md->default_lmv = NULL; + up_write(&lli->lli_lsm_sem); + } else { + up_read(&lli->lli_lsm_sem); + } + } else { + /* init default lsm */ + down_write(&lli->lli_lsm_sem); + lli->lli_default_lsm_md = md->default_lmv; + lsm_md_dump(D_INODE, md->default_lmv); + md->default_lmv = NULL; + up_write(&lli->lli_lsm_sem); + } } static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md) { struct ll_inode_info *lli = ll_i2info(inode); struct lmv_stripe_md *lsm = md->lmv; - int rc; + struct cl_attr *attr; + int rc = 0; + ENTRY; LASSERT(S_ISDIR(inode->i_mode)); CDEBUG(D_INODE, "update lsm %p of "DFID"\n", lli->lli_lsm_md, PFID(ll_inode2fid(inode))); - /* no striped information from request. */ - if (lsm == NULL) { - if (lli->lli_lsm_md == NULL) { - RETURN(0); - } else if (lli->lli_lsm_md->lsm_md_hash_type & - LMV_HASH_FLAG_MIGRATION) { - /* migration is done, the temporay MIGRATE layout has - * been removed */ - CDEBUG(D_INODE, DFID" finish migration.\n", - PFID(ll_inode2fid(inode))); - lmv_free_memmd(lli->lli_lsm_md); - lli->lli_lsm_md = NULL; - RETURN(0); - } else { - /* The lustre_md from req does not include stripeEA, - * see ll_md_setattr */ - RETURN(0); - } + /* update default LMV */ + if (md->default_lmv) + ll_update_default_lsm_md(inode, md); + + /* + * no striped information from request, lustre_md from req does not + * include stripeEA, see ll_md_setattr() + */ + if (!lsm) + RETURN(0); + + /* + * normally dir layout doesn't change, only take read lock to check + * that to avoid blocking other MD operations. + */ + down_read(&lli->lli_lsm_sem); + + /* some current lookup initialized lsm, and unchanged */ + if (lli->lli_lsm_md && lsm_md_eq(lli->lli_lsm_md, lsm)) + GOTO(unlock, rc = 0); + + /* if dir layout doesn't match, check whether version is increased, + * which means layout is changed, this happens in dir split/merge and + * lfsck. + * + * foreign LMV should not change. + */ + if (lli->lli_lsm_md && lmv_dir_striped(lli->lli_lsm_md) && + lsm->lsm_md_layout_version <= + lli->lli_lsm_md->lsm_md_layout_version) { + CERROR("%s: "DFID" dir layout mismatch:\n", + ll_i2sbi(inode)->ll_fsname, PFID(&lli->lli_fid)); + lsm_md_dump(D_ERROR, lli->lli_lsm_md); + lsm_md_dump(D_ERROR, lsm); + GOTO(unlock, rc = -EINVAL); + } + + up_read(&lli->lli_lsm_sem); + down_write(&lli->lli_lsm_sem); + /* clear existing lsm */ + if (lli->lli_lsm_md) { + lmv_free_memmd(lli->lli_lsm_md); + lli->lli_lsm_md = NULL; } - /* set the directory layout */ - if (lli->lli_lsm_md == NULL) { - struct cl_attr *attr; + rc = ll_init_lsm_md(inode, md); + up_write(&lli->lli_lsm_sem); - rc = ll_init_lsm_md(inode, md); - if (rc != 0) - RETURN(rc); + if (rc) + RETURN(rc); - /* set md->lmv to NULL, so the following free lustre_md - * will not free this lsm */ - md->lmv = NULL; - lli->lli_lsm_md = lsm; + /* set md->lmv to NULL, so the following free lustre_md will not free + * this lsm. + */ + md->lmv = NULL; - OBD_ALLOC_PTR(attr); - if (attr == NULL) - RETURN(-ENOMEM); + /* md_merge_attr() may take long, since lsm is already set, switch to + * read lock. + */ + down_read(&lli->lli_lsm_sem); - /* validate the lsm */ - rc = md_merge_attr(ll_i2mdexp(inode), lsm, attr, - ll_md_blocking_ast); - if (rc != 0) { - OBD_FREE_PTR(attr); - RETURN(rc); - } + if (!lmv_dir_striped(lli->lli_lsm_md)) + GOTO(unlock, rc = 0); + OBD_ALLOC_PTR(attr); + if (!attr) + GOTO(unlock, rc = -ENOMEM); + + /* validate the lsm */ + rc = md_merge_attr(ll_i2mdexp(inode), lli->lli_lsm_md, attr, + ll_md_blocking_ast); + if (!rc) { if (md->body->mbo_valid & OBD_MD_FLNLINK) md->body->mbo_nlink = attr->cat_nlink; if (md->body->mbo_valid & OBD_MD_FLSIZE) @@ -1398,68 +1564,34 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md) md->body->mbo_ctime = attr->cat_ctime; if (md->body->mbo_valid & OBD_MD_FLMTIME) md->body->mbo_mtime = attr->cat_mtime; - - OBD_FREE_PTR(attr); - - CDEBUG(D_INODE, "Set lsm %p magic %x to "DFID"\n", lsm, - lsm->lsm_md_magic, PFID(ll_inode2fid(inode))); - RETURN(0); } - /* Compare the old and new stripe information */ - if (!lsm_md_eq(lli->lli_lsm_md, lsm)) { - struct lmv_stripe_md *old_lsm = lli->lli_lsm_md; - int idx; - - CERROR("%s: inode "DFID"(%p)'s lmv layout mismatch (%p)/(%p)" - "magic:0x%x/0x%x stripe count: %d/%d master_mdt: %d/%d" - "hash_type:0x%x/0x%x layout: 0x%x/0x%x pool:%s/%s\n", - ll_get_fsname(inode->i_sb, NULL, 0), PFID(&lli->lli_fid), - inode, lsm, old_lsm, - lsm->lsm_md_magic, old_lsm->lsm_md_magic, - lsm->lsm_md_stripe_count, - old_lsm->lsm_md_stripe_count, - lsm->lsm_md_master_mdt_index, - old_lsm->lsm_md_master_mdt_index, - lsm->lsm_md_hash_type, old_lsm->lsm_md_hash_type, - lsm->lsm_md_layout_version, - old_lsm->lsm_md_layout_version, - lsm->lsm_md_pool_name, - old_lsm->lsm_md_pool_name); - - for (idx = 0; idx < old_lsm->lsm_md_stripe_count; idx++) { - CERROR("%s: sub FIDs in old lsm idx %d, old: "DFID"\n", - ll_get_fsname(inode->i_sb, NULL, 0), idx, - PFID(&old_lsm->lsm_md_oinfo[idx].lmo_fid)); - } - - for (idx = 0; idx < lsm->lsm_md_stripe_count; idx++) { - CERROR("%s: sub FIDs in new lsm idx %d, new: "DFID"\n", - ll_get_fsname(inode->i_sb, NULL, 0), idx, - PFID(&lsm->lsm_md_oinfo[idx].lmo_fid)); - } + OBD_FREE_PTR(attr); + GOTO(unlock, rc); +unlock: + up_read(&lli->lli_lsm_sem); - RETURN(-EIO); - } - - RETURN(0); + return rc; } void ll_clear_inode(struct inode *inode) { struct ll_inode_info *lli = ll_i2info(inode); struct ll_sb_info *sbi = ll_i2sbi(inode); + ENTRY; CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n", PFID(ll_inode2fid(inode)), inode); - if (S_ISDIR(inode->i_mode)) { - /* these should have been cleared in ll_file_release */ - LASSERT(lli->lli_opendir_key == NULL); - LASSERT(lli->lli_sai == NULL); - LASSERT(lli->lli_opendir_pid == 0); - } + if (S_ISDIR(inode->i_mode)) { + /* these should have been cleared in ll_file_release */ + LASSERT(lli->lli_opendir_key == NULL); + LASSERT(lli->lli_sai == NULL); + LASSERT(lli->lli_opendir_pid == 0); + } else { + pcc_inode_free(inode); + } md_null_inode(sbi->ll_md_exp, ll_inode2fid(inode)); @@ -1482,10 +1614,9 @@ void ll_clear_inode(struct inode *inode) ll_xattr_cache_destroy(inode); -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_LUSTRE_FS_POSIX_ACL forget_all_cached_acls(inode); if (lli->lli_posix_acl) { - LASSERT(atomic_read(&lli->lli_posix_acl->a_refcount) == 1); posix_acl_release(lli->lli_posix_acl); lli->lli_posix_acl = NULL; } @@ -1579,17 +1710,20 @@ static int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data) * * In case of HSMimport, we only set attr on MDS. */ -int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import) +int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, + enum op_xvalid xvalid, bool hsm_import) { struct inode *inode = dentry->d_inode; struct ll_inode_info *lli = ll_i2info(inode); struct md_op_data *op_data = NULL; + ktime_t kstart = ktime_get(); int rc = 0; + ENTRY; CDEBUG(D_VFSTRACE, "%s: setattr inode "DFID"(%p) from %llu to %llu, " "valid %x, hsm_import %d\n", - ll_get_fsname(inode->i_sb, NULL, 0), PFID(&lli->lli_fid), + ll_i2sbi(inode)->ll_fsname, PFID(&lli->lli_fid), inode, i_size_read(inode), attr->ia_size, attr->ia_valid, hsm_import); @@ -1619,12 +1753,12 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import) RETURN(-EPERM); } - /* We mark all of the fields "set" so MDS/OST does not re-set them */ - if (!(attr->ia_valid & ATTR_CTIME_SET) && - (attr->ia_valid & ATTR_CTIME)) { + /* We mark all of the fields "set" so MDS/OST does not re-set them */ + if (!(xvalid & OP_XVALID_CTIME_SET) && + (attr->ia_valid & ATTR_CTIME)) { attr->ia_ctime = current_time(inode); - attr->ia_valid |= ATTR_CTIME_SET; - } + xvalid |= OP_XVALID_CTIME_SET; + } if (!(attr->ia_valid & ATTR_ATIME_SET) && (attr->ia_valid & ATTR_ATIME)) { attr->ia_atime = current_time(inode); @@ -1637,15 +1771,12 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import) } if (attr->ia_valid & (ATTR_MTIME | ATTR_CTIME)) - CDEBUG(D_INODE, "setting mtime %lu, ctime %lu, now = %llu\n", - LTIME_S(attr->ia_mtime), LTIME_S(attr->ia_ctime), - (s64)ktime_get_real_seconds()); + CDEBUG(D_INODE, "setting mtime %lld, ctime %lld, now = %lld\n", + (s64)attr->ia_mtime.tv_sec, (s64)attr->ia_ctime.tv_sec, + ktime_get_real_seconds()); - if (S_ISREG(inode->i_mode)) { - if (attr->ia_valid & ATTR_SIZE) - inode_dio_write_done(inode); + if (S_ISREG(inode->i_mode)) inode_unlock(inode); - } /* We always do an MDS RPC, even if we're only changing the size; * only the MDS knows whether truncate() should fail with -ETXTBUSY */ @@ -1656,13 +1787,22 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import) if (!hsm_import && attr->ia_valid & ATTR_SIZE) { /* If we are changing file size, file content is - * modified, flag it. */ - attr->ia_valid |= MDS_OPEN_OWNEROVERRIDE; + * modified, flag it. + */ + xvalid |= OP_XVALID_OWNEROVERRIDE; op_data->op_bias |= MDS_DATA_MODIFIED; ll_file_clear_flag(lli, LLIF_DATA_MODIFIED); } + if (attr->ia_valid & ATTR_FILE) { + struct ll_file_data *fd = attr->ia_file->private_data; + + if (fd->fd_lease_och) + op_data->op_bias |= MDS_TRUNC_KEEP_LEASE; + } + op_data->op_attr = *attr; + op_data->op_xvalid = xvalid; rc = ll_md_setattr(dentry, op_data); if (rc) @@ -1671,17 +1811,31 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import) if (!S_ISREG(inode->i_mode) || hsm_import) GOTO(out, rc = 0); - if (attr->ia_valid & (ATTR_SIZE | - ATTR_ATIME | ATTR_ATIME_SET | - ATTR_MTIME | ATTR_MTIME_SET | - ATTR_CTIME | ATTR_CTIME_SET)) { - /* For truncate and utimes sending attributes to OSTs, setting - * mtime/atime to the past will be performed under PW [0:EOF] - * extent lock (new_size:EOF for truncate). It may seem - * excessive to send mtime/atime updates to OSTs when not - * setting times to past, but it is necessary due to possible - * time de-synchronization between MDT inode and OST objects */ - rc = cl_setattr_ost(lli->lli_clob, attr, 0); + if (attr->ia_valid & (ATTR_SIZE | ATTR_ATIME | ATTR_ATIME_SET | + ATTR_MTIME | ATTR_MTIME_SET | ATTR_CTIME) || + xvalid & OP_XVALID_CTIME_SET) { + bool cached = false; + + rc = pcc_inode_setattr(inode, attr, &cached); + if (cached) { + if (rc) { + CERROR("%s: PCC inode "DFID" setattr failed: " + "rc = %d\n", + ll_i2sbi(inode)->ll_fsname, + PFID(&lli->lli_fid), rc); + GOTO(out, rc); + } + } else { + /* For truncate and utimes sending attributes to OSTs, + * setting mtime/atime to the past will be performed + * under PW [0:EOF] extent lock (new_size:EOF for + * truncate). It may seem excessive to send mtime/atime + * updates to OSTs when not setting times to past, but + * it is necessary due to possible time + * de-synchronization between MDT inode and OST objects + */ + rc = cl_setattr_ost(lli->lli_clob, attr, xvalid, 0); + } } /* If the file was restored, it needs to set dirty flag. @@ -1732,8 +1886,10 @@ out: inode_has_no_xattr(inode); } - ll_stats_ops_tally(ll_i2sbi(inode), (attr->ia_valid & ATTR_SIZE) ? - LPROC_LL_TRUNC : LPROC_LL_SETATTR, 1); + if (!rc) + ll_stats_ops_tally(ll_i2sbi(inode), attr->ia_valid & ATTR_SIZE ? + LPROC_LL_TRUNC : LPROC_LL_SETATTR, + ktime_us_delta(ktime_get(), kstart)); return rc; } @@ -1741,10 +1897,11 @@ out: int ll_setattr(struct dentry *de, struct iattr *attr) { int mode = de->d_inode->i_mode; + enum op_xvalid xvalid = 0; if ((attr->ia_valid & (ATTR_CTIME|ATTR_SIZE|ATTR_MODE)) == (ATTR_CTIME|ATTR_SIZE|ATTR_MODE)) - attr->ia_valid |= MDS_OPEN_OWNEROVERRIDE; + xvalid |= OP_XVALID_OWNEROVERRIDE; if (((attr->ia_valid & (ATTR_MODE|ATTR_FORCE|ATTR_SIZE)) == (ATTR_SIZE|ATTR_MODE)) && @@ -1765,77 +1922,74 @@ int ll_setattr(struct dentry *de, struct iattr *attr) !(attr->ia_valid & ATTR_KILL_SGID)) attr->ia_valid |= ATTR_KILL_SGID; - /* avoid polluted from ATTR_TIMES_SET, - * projid is not expected to be set here */ - attr->ia_valid &= ~MDS_ATTR_PROJID; - - return ll_setattr_raw(de, attr, false); + return ll_setattr_raw(de, attr, xvalid, false); } -int ll_statfs_internal(struct super_block *sb, struct obd_statfs *osfs, +int ll_statfs_internal(struct ll_sb_info *sbi, struct obd_statfs *osfs, u32 flags) { - struct ll_sb_info *sbi = ll_s2sbi(sb); - struct obd_statfs obd_osfs; + struct obd_statfs obd_osfs = { 0 }; time64_t max_age; int rc; ENTRY; - max_age = ktime_get_seconds() - OBD_STATFS_CACHE_SECONDS; + max_age = ktime_get_seconds() - sbi->ll_statfs_max_age; - rc = obd_statfs(NULL, sbi->ll_md_exp, osfs, max_age, flags); - if (rc) { - CERROR("md_statfs fails: rc = %d\n", rc); - RETURN(rc); - } + if (sbi->ll_flags & LL_SBI_LAZYSTATFS) + flags |= OBD_STATFS_NODELAY; - osfs->os_type = sb->s_magic; + rc = obd_statfs(NULL, sbi->ll_md_exp, osfs, max_age, flags); + if (rc) + RETURN(rc); + + osfs->os_type = LL_SUPER_MAGIC; CDEBUG(D_SUPER, "MDC blocks %llu/%llu objects %llu/%llu\n", - osfs->os_bavail, osfs->os_blocks, osfs->os_ffree,osfs->os_files); + osfs->os_bavail, osfs->os_blocks, osfs->os_ffree, osfs->os_files); - if (sbi->ll_flags & LL_SBI_LAZYSTATFS) - flags |= OBD_STATFS_NODELAY; + if (osfs->os_state & OS_STATE_SUM) + GOTO(out, rc); rc = obd_statfs(NULL, sbi->ll_dt_exp, &obd_osfs, max_age, flags); - if (rc) { - CERROR("obd_statfs fails: rc = %d\n", rc); - RETURN(rc); - } + if (rc) /* Possibly a filesystem with no OSTs. Report MDT totals. */ + GOTO(out, rc = 0); CDEBUG(D_SUPER, "OSC blocks %llu/%llu objects %llu/%llu\n", - obd_osfs.os_bavail, obd_osfs.os_blocks, obd_osfs.os_ffree, - obd_osfs.os_files); - - osfs->os_bsize = obd_osfs.os_bsize; - osfs->os_blocks = obd_osfs.os_blocks; - osfs->os_bfree = obd_osfs.os_bfree; - osfs->os_bavail = obd_osfs.os_bavail; - - /* If we don't have as many objects free on the OST as inodes - * on the MDS, we reduce the total number of inodes to - * compensate, so that the "inodes in use" number is correct. - */ - if (obd_osfs.os_ffree < osfs->os_ffree) { - osfs->os_files = (osfs->os_files - osfs->os_ffree) + - obd_osfs.os_ffree; - osfs->os_ffree = obd_osfs.os_ffree; - } + obd_osfs.os_bavail, obd_osfs.os_blocks, obd_osfs.os_ffree, + obd_osfs.os_files); + + osfs->os_bsize = obd_osfs.os_bsize; + osfs->os_blocks = obd_osfs.os_blocks; + osfs->os_bfree = obd_osfs.os_bfree; + osfs->os_bavail = obd_osfs.os_bavail; + + /* If we have _some_ OSTs, but don't have as many free objects on the + * OSTs as inodes on the MDTs, reduce the reported number of inodes + * to compensate, so that the "inodes in use" number is correct. + * This should be kept in sync with lod_statfs() behaviour. + */ + if (obd_osfs.os_files && obd_osfs.os_ffree < osfs->os_ffree) { + osfs->os_files = (osfs->os_files - osfs->os_ffree) + + obd_osfs.os_ffree; + osfs->os_ffree = obd_osfs.os_ffree; + } - RETURN(rc); +out: + RETURN(rc); } + int ll_statfs(struct dentry *de, struct kstatfs *sfs) { struct super_block *sb = de->d_sb; struct obd_statfs osfs; __u64 fsid = huge_encode_dev(sb->s_dev); + ktime_t kstart = ktime_get(); int rc; - CDEBUG(D_VFSTRACE, "VFS Op: at %llu jiffies\n", get_jiffies_64()); - ll_stats_ops_tally(ll_s2sbi(sb), LPROC_LL_STAFS, 1); + CDEBUG(D_VFSTRACE, "VFS Op:sb=%s (%p)\n", sb->s_id, sb); /* Some amount of caching on the client is allowed */ - rc = ll_statfs_internal(sb, &osfs, 0); + rc = ll_statfs_internal(ll_s2sbi(sb), &osfs, OBD_STATFS_SUM); if (rc) return rc; @@ -1855,11 +2009,15 @@ int ll_statfs(struct dentry *de, struct kstatfs *sfs) } } - sfs->f_blocks = osfs.os_blocks; - sfs->f_bfree = osfs.os_bfree; - sfs->f_bavail = osfs.os_bavail; + sfs->f_blocks = osfs.os_blocks; + sfs->f_bfree = osfs.os_bfree; + sfs->f_bavail = osfs.os_bavail; sfs->f_fsid.val[0] = (__u32)fsid; sfs->f_fsid.val[1] = (__u32)(fsid >> 32); + + ll_stats_ops_tally(ll_s2sbi(sb), LPROC_LL_STATFS, + ktime_us_delta(ktime_get(), kstart)); + return 0; } @@ -1881,6 +2039,15 @@ void ll_inode_size_unlock(struct inode *inode) mutex_unlock(&lli->lli_size_mutex); } +void ll_update_inode_flags(struct inode *inode, int ext_flags) +{ + inode->i_flags = ll_ext_to_inode_flags(ext_flags); + if (ext_flags & LUSTRE_PROJINHERIT_FL) + ll_file_set_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT); + else + ll_file_clear_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT); +} + int ll_update_inode(struct inode *inode, struct lustre_md *md) { struct ll_inode_info *lli = ll_i2info(inode); @@ -1900,7 +2067,7 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md) return rc; } -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_LUSTRE_FS_POSIX_ACL if (body->mbo_valid & OBD_MD_FLACL) { spin_lock(&lli->lli_lock); if (lli->lli_posix_acl) @@ -1914,30 +2081,31 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md) inode->i_generation = cl_fid_build_gen(&body->mbo_fid1); if (body->mbo_valid & OBD_MD_FLATIME) { - if (body->mbo_atime > LTIME_S(inode->i_atime)) - LTIME_S(inode->i_atime) = body->mbo_atime; + if (body->mbo_atime > inode->i_atime.tv_sec) + inode->i_atime.tv_sec = body->mbo_atime; lli->lli_atime = body->mbo_atime; } if (body->mbo_valid & OBD_MD_FLMTIME) { - if (body->mbo_mtime > LTIME_S(inode->i_mtime)) { - CDEBUG(D_INODE, "setting ino %lu mtime from %lu " - "to %llu\n", inode->i_ino, - LTIME_S(inode->i_mtime), body->mbo_mtime); - LTIME_S(inode->i_mtime) = body->mbo_mtime; + if (body->mbo_mtime > inode->i_mtime.tv_sec) { + CDEBUG(D_INODE, + "setting ino %lu mtime from %lld to %llu\n", + inode->i_ino, (s64)inode->i_mtime.tv_sec, + body->mbo_mtime); + inode->i_mtime.tv_sec = body->mbo_mtime; } lli->lli_mtime = body->mbo_mtime; } if (body->mbo_valid & OBD_MD_FLCTIME) { - if (body->mbo_ctime > LTIME_S(inode->i_ctime)) - LTIME_S(inode->i_ctime) = body->mbo_ctime; + if (body->mbo_ctime > inode->i_ctime.tv_sec) + inode->i_ctime.tv_sec = body->mbo_ctime; lli->lli_ctime = body->mbo_ctime; } /* Clear i_flags to remove S_NOSEC before permissions are updated */ if (body->mbo_valid & OBD_MD_FLFLAGS) - inode->i_flags = ll_ext_to_inode_flags(body->mbo_flags); + ll_update_inode_flags(inode, body->mbo_flags); if (body->mbo_valid & OBD_MD_FLMODE) inode->i_mode = (inode->i_mode & S_IFMT) | (body->mbo_mode & ~S_IFMT); @@ -2017,11 +2185,12 @@ int ll_read_inode2(struct inode *inode, void *opaque) /* Core attributes from the MDS first. This is a new inode, and * the VFS doesn't zero times in the core inode so we have to do * it ourselves. They will be overwritten by either MDS or OST - * attributes - we just need to make sure they aren't newer. */ - LTIME_S(inode->i_mtime) = 0; - LTIME_S(inode->i_atime) = 0; - LTIME_S(inode->i_ctime) = 0; - inode->i_rdev = 0; + * attributes - we just need to make sure they aren't newer. + */ + inode->i_mtime.tv_sec = 0; + inode->i_atime.tv_sec = 0; + inode->i_ctime.tv_sec = 0; + inode->i_rdev = 0; rc = ll_update_inode(inode, md); if (rc != 0) RETURN(rc); @@ -2060,22 +2229,45 @@ int ll_read_inode2(struct inode *inode, void *opaque) void ll_delete_inode(struct inode *inode) { struct ll_inode_info *lli = ll_i2info(inode); + struct address_space *mapping = &inode->i_data; + unsigned long nrpages; + unsigned long flags; + ENTRY; - if (S_ISREG(inode->i_mode) && lli->lli_clob != NULL) + if (S_ISREG(inode->i_mode) && lli->lli_clob != NULL) { /* It is last chance to write out dirty pages, - * otherwise we may lose data while umount */ - cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, CL_FSYNC_LOCAL, 1); - - truncate_inode_pages_final(&inode->i_data); + * otherwise we may lose data while umount. + * + * If i_nlink is 0 then just discard data. This is safe because + * local inode gets i_nlink 0 from server only for the last + * unlink, so that file is not opened somewhere else + */ + cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, inode->i_nlink ? + CL_FSYNC_LOCAL : CL_FSYNC_DISCARD, 1); + } + truncate_inode_pages_final(mapping); - LASSERTF(inode->i_data.nrpages == 0, "inode="DFID"(%p) nrpages=%lu, " - "see https://jira.hpdd.intel.com/browse/LU-118\n", - PFID(ll_inode2fid(inode)), inode, inode->i_data.nrpages); + /* Workaround for LU-118: Note nrpages may not be totally updated when + * truncate_inode_pages() returns, as there can be a page in the process + * of deletion (inside __delete_from_page_cache()) in the specified + * range. Thus mapping->nrpages can be non-zero when this function + * returns even after truncation of the whole mapping. Only do this if + * npages isn't already zero. + */ + nrpages = mapping->nrpages; + if (nrpages) { + xa_lock_irqsave(&mapping->i_pages, flags); + nrpages = mapping->nrpages; + xa_unlock_irqrestore(&mapping->i_pages, flags); + } /* Workaround end */ + + LASSERTF(nrpages == 0, "%s: inode="DFID"(%p) nrpages=%lu, " + "see https://jira.whamcloud.com/browse/LU-118\n", + ll_i2sbi(inode)->ll_fsname, + PFID(ll_inode2fid(inode)), inode, nrpages); -#ifdef HAVE_SBOPS_EVICT_INODE ll_clear_inode(inode); -#endif clear_inode(inode); EXIT; @@ -2084,13 +2276,13 @@ void ll_delete_inode(struct inode *inode) int ll_iocontrol(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct ll_sb_info *sbi = ll_i2sbi(inode); - struct ptlrpc_request *req = NULL; - int rc, flags = 0; - ENTRY; + struct ll_sb_info *sbi = ll_i2sbi(inode); + struct ptlrpc_request *req = NULL; + int rc, flags = 0; + ENTRY; - switch(cmd) { - case FSFILT_IOC_GETFLAGS: { + switch (cmd) { + case FS_IOC_GETFLAGS: { struct mdt_body *body; struct md_op_data *op_data; @@ -2114,32 +2306,41 @@ int ll_iocontrol(struct inode *inode, struct file *file, flags = body->mbo_flags; - ptlrpc_req_finished(req); + ptlrpc_req_finished(req); RETURN(put_user(flags, (int __user *)arg)); - } - case FSFILT_IOC_SETFLAGS: { + } + case FS_IOC_SETFLAGS: { struct iattr *attr; struct md_op_data *op_data; struct cl_object *obj; + struct fsxattr fa = { 0 }; if (get_user(flags, (int __user *)arg)) RETURN(-EFAULT); - op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0, - LUSTRE_OPC_ANY, NULL); - if (IS_ERR(op_data)) - RETURN(PTR_ERR(op_data)); + fa.fsx_projid = ll_i2info(inode)->lli_projid; + if (flags & LUSTRE_PROJINHERIT_FL) + fa.fsx_xflags = FS_XFLAG_PROJINHERIT; + + rc = ll_ioctl_check_project(inode, &fa); + if (rc) + RETURN(rc); + + op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0, + LUSTRE_OPC_ANY, NULL); + if (IS_ERR(op_data)) + RETURN(PTR_ERR(op_data)); op_data->op_attr_flags = flags; - op_data->op_attr.ia_valid |= ATTR_ATTR_FLAG; + op_data->op_xvalid |= OP_XVALID_FLAGS; rc = md_setattr(sbi->ll_md_exp, op_data, NULL, 0, &req); ll_finish_md_op_data(op_data); ptlrpc_req_finished(req); if (rc) RETURN(rc); - inode->i_flags = ll_ext_to_inode_flags(flags); + ll_update_inode_flags(inode, flags); obj = ll_i2info(inode)->lli_clob; if (obj == NULL) @@ -2149,8 +2350,7 @@ int ll_iocontrol(struct inode *inode, struct file *file, if (attr == NULL) RETURN(-ENOMEM); - attr->ia_valid = ATTR_ATTR_FLAG; - rc = cl_setattr_ost(obj, attr, flags); + rc = cl_setattr_ost(obj, attr, OP_XVALID_FLAGS, flags); OBD_FREE_PTR(attr); RETURN(rc); @@ -2184,8 +2384,7 @@ void ll_umount_begin(struct super_block *sb) struct ll_sb_info *sbi = ll_s2sbi(sb); struct obd_device *obd; struct obd_ioctl_data *ioc_data; - struct l_wait_info lwi; - wait_queue_head_t waitq; + int cnt; ENTRY; CDEBUG(D_VFSTRACE, "VFS Op: superblock %p count %d active %d\n", sb, @@ -2200,16 +2399,16 @@ void ll_umount_begin(struct super_block *sb) } obd->obd_force = 1; - obd = class_exp2obd(sbi->ll_dt_exp); - if (obd == NULL) { + obd = class_exp2obd(sbi->ll_dt_exp); + if (obd == NULL) { CERROR("Invalid LOV connection handle %#llx\n", - sbi->ll_dt_exp->exp_handle.h_cookie); - EXIT; - return; - } - obd->obd_force = 1; + sbi->ll_dt_exp->exp_handle.h_cookie); + EXIT; + return; + } + obd->obd_force = 1; - OBD_ALLOC_PTR(ioc_data); + OBD_ALLOC_PTR(ioc_data); if (ioc_data) { obd_iocontrol(IOC_OSC_SET_ACTIVE, sbi->ll_md_exp, sizeof *ioc_data, ioc_data, NULL); @@ -2224,44 +2423,46 @@ void ll_umount_begin(struct super_block *sb) * and then continue. For now, we just periodically checking for vfs * to decrement mnt_cnt and hope to finish it within 10sec. */ - init_waitqueue_head(&waitq); - lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(10), - cfs_time_seconds(1), NULL, NULL); - l_wait_event(waitq, may_umount(sbi->ll_mnt.mnt), &lwi); + cnt = 10; + while (cnt > 0 && + !may_umount(sbi->ll_mnt.mnt)) { + ssleep(1); + cnt -= 1; + } EXIT; } int ll_remount_fs(struct super_block *sb, int *flags, char *data) { - struct ll_sb_info *sbi = ll_s2sbi(sb); - char *profilenm = get_profile_name(sb); - int err; - __u32 read_only; - - if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { - read_only = *flags & MS_RDONLY; - err = obd_set_info_async(NULL, sbi->ll_md_exp, - sizeof(KEY_READ_ONLY), - KEY_READ_ONLY, sizeof(read_only), - &read_only, NULL); - if (err) { - LCONSOLE_WARN("Failed to remount %s %s (%d)\n", - profilenm, read_only ? - "read-only" : "read-write", err); - return err; - } + struct ll_sb_info *sbi = ll_s2sbi(sb); + char *profilenm = get_profile_name(sb); + int err; + __u32 read_only; + + if ((*flags & MS_RDONLY) != (sb->s_flags & SB_RDONLY)) { + read_only = *flags & MS_RDONLY; + err = obd_set_info_async(NULL, sbi->ll_md_exp, + sizeof(KEY_READ_ONLY), + KEY_READ_ONLY, sizeof(read_only), + &read_only, NULL); + if (err) { + LCONSOLE_WARN("Failed to remount %s %s (%d)\n", + profilenm, read_only ? + "read-only" : "read-write", err); + return err; + } - if (read_only) - sb->s_flags |= MS_RDONLY; - else - sb->s_flags &= ~MS_RDONLY; + if (read_only) + sb->s_flags |= SB_RDONLY; + else + sb->s_flags &= ~SB_RDONLY; - if (sbi->ll_flags & LL_SBI_VERBOSE) - LCONSOLE_WARN("Remounted %s %s\n", profilenm, - read_only ? "read-only" : "read-write"); - } - return 0; + if (sbi->ll_flags & LL_SBI_VERBOSE) + LCONSOLE_WARN("Remounted %s %s\n", profilenm, + read_only ? "read-only" : "read-write"); + } + return 0; } /** @@ -2291,14 +2492,13 @@ void ll_open_cleanup(struct super_block *sb, struct ptlrpc_request *open_req) OBD_ALLOC_PTR(op_data); if (op_data == NULL) { CWARN("%s: cannot allocate op_data to release open handle for " - DFID"\n", - ll_get_fsname(sb, NULL, 0), PFID(&body->mbo_fid1)); + DFID"\n", ll_s2sbi(sb)->ll_fsname, PFID(&body->mbo_fid1)); RETURN_EXIT; } op_data->op_fid1 = body->mbo_fid1; - op_data->op_handle = body->mbo_handle; + op_data->op_open_handle = body->mbo_open_handle; op_data->op_mod_time = ktime_get_real_seconds(); md_close(exp, op_data, NULL, &close_req); ptlrpc_req_finished(close_req); @@ -2312,7 +2512,9 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, { struct ll_sb_info *sbi = NULL; struct lustre_md md = { NULL }; + bool default_lmv_deleted = false; int rc; + ENTRY; LASSERT(*inode || sb); @@ -2320,7 +2522,16 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, rc = md_get_lustre_md(sbi->ll_md_exp, req, sbi->ll_dt_exp, sbi->ll_md_exp, &md); if (rc != 0) - GOTO(cleanup, rc); + GOTO(out, rc); + + /* + * clear default_lmv only if intent_getattr reply doesn't contain it. + * but it needs to be done after iget, check this early because + * ll_update_lsm_md() may change md. + */ + if (it && (it->it_op & (IT_LOOKUP | IT_GETATTR)) && + S_ISDIR(md.body->mbo_mode) && !md.default_lmv) + default_lmv_deleted = true; if (*inode) { rc = ll_update_inode(*inode, &md); @@ -2335,7 +2546,7 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, */ if (!fid_is_sane(&md.body->mbo_fid1)) { CERROR("%s: Fid is insane "DFID"\n", - ll_get_fsname(sb, NULL, 0), + sbi->ll_fsname, PFID(&md.body->mbo_fid1)); GOTO(out, rc = -EINVAL); } @@ -2344,7 +2555,7 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, sbi->ll_flags & LL_SBI_32BIT_API), &md); if (IS_ERR(*inode)) { -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_LUSTRE_FS_POSIX_ACL if (md.posix_acl) { posix_acl_release(md.posix_acl); md.posix_acl = NULL; @@ -2385,14 +2596,19 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, LDLM_LOCK_PUT(lock); } + if (default_lmv_deleted) + ll_update_default_lsm_md(*inode, &md); + GOTO(out, rc = 0); out: + /* cleanup will be done if necessary */ md_free_lustre_md(sbi->ll_md_exp, &md); -cleanup: - if (rc != 0 && it != NULL && it->it_op & IT_OPEN) + if (rc != 0 && it != NULL && it->it_op & IT_OPEN) { + ll_intent_drop_lock(it); ll_open_cleanup(sb != NULL ? sb : (*inode)->i_sb, req); + } return rc; } @@ -2440,37 +2656,29 @@ out_statfs: return rc; } -int ll_process_config(struct lustre_cfg *lcfg) +/* + * this is normally called in ll_fini_md_op_data(), but sometimes it needs to + * be called early to avoid deadlock. + */ +void ll_unlock_md_op_lsm(struct md_op_data *op_data) { - struct super_block *sb; - unsigned long x; - int rc = 0; - char *ptr; + if (op_data->op_mea2_sem) { + up_read(op_data->op_mea2_sem); + op_data->op_mea2_sem = NULL; + } - /* The instance name contains the sb: lustre-client-aacfe000 */ - ptr = strrchr(lustre_cfg_string(lcfg, 0), '-'); - if (!ptr || !*(++ptr)) - return -EINVAL; - if (sscanf(ptr, "%lx", &x) != 1) - return -EINVAL; - sb = (struct super_block *)x; - /* This better be a real Lustre superblock! */ - LASSERT(s2lsi(sb)->lsi_lmd->lmd_magic == LMD_MAGIC); - - /* Note we have not called client_common_fill_super yet, so - proc fns must be able to handle that! */ - rc = class_process_proc_param(PARAM_LLITE, lprocfs_llite_obd_vars, - lcfg, sb); - if (rc > 0) - rc = 0; - return rc; + if (op_data->op_mea1_sem) { + up_read(op_data->op_mea1_sem); + op_data->op_mea1_sem = NULL; + } } /* this function prepares md_op_data hint for passing it down to MD stack. */ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, struct inode *i1, struct inode *i2, const char *name, size_t namelen, - __u32 mode, __u32 opc, void *data) + __u32 mode, enum md_op_code opc, + void *data) { LASSERT(i1 != NULL); @@ -2494,18 +2702,25 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, ll_i2gids(op_data->op_suppgids, i1, i2); op_data->op_fid1 = *ll_inode2fid(i1); - op_data->op_default_stripe_offset = -1; + op_data->op_code = opc; + if (S_ISDIR(i1->i_mode)) { + down_read(&ll_i2info(i1)->lli_lsm_sem); + op_data->op_mea1_sem = &ll_i2info(i1)->lli_lsm_sem; op_data->op_mea1 = ll_i2info(i1)->lli_lsm_md; - if (opc == LUSTRE_OPC_MKDIR) - op_data->op_default_stripe_offset = - ll_i2info(i1)->lli_def_stripe_offset; + op_data->op_default_mea1 = ll_i2info(i1)->lli_default_lsm_md; } if (i2) { op_data->op_fid2 = *ll_inode2fid(i2); - if (S_ISDIR(i2->i_mode)) + if (S_ISDIR(i2->i_mode)) { + if (i2 != i1) { + down_read(&ll_i2info(i2)->lli_lsm_sem); + op_data->op_mea2_sem = + &ll_i2info(i2)->lli_lsm_sem; + } op_data->op_mea2 = ll_i2info(i2)->lli_lsm_md; + } } else { fid_zero(&op_data->op_fid2); } @@ -2535,41 +2750,38 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, void ll_finish_md_op_data(struct md_op_data *op_data) { + ll_unlock_md_op_lsm(op_data); security_release_secctx(op_data->op_file_secctx, op_data->op_file_secctx_size); OBD_FREE_PTR(op_data); } -#ifdef HAVE_SUPEROPS_USE_DENTRY int ll_show_options(struct seq_file *seq, struct dentry *dentry) -#else -int ll_show_options(struct seq_file *seq, struct vfsmount *vfs) -#endif { - struct ll_sb_info *sbi; + struct ll_sb_info *sbi; -#ifdef HAVE_SUPEROPS_USE_DENTRY - LASSERT((seq != NULL) && (dentry != NULL)); + LASSERT(seq && dentry); sbi = ll_s2sbi(dentry->d_sb); -#else - LASSERT((seq != NULL) && (vfs != NULL)); - sbi = ll_s2sbi(vfs->mnt_sb); -#endif - - if (sbi->ll_flags & LL_SBI_NOLCK) - seq_puts(seq, ",nolock"); - if (sbi->ll_flags & LL_SBI_FLOCK) - seq_puts(seq, ",flock"); + if (sbi->ll_flags & LL_SBI_NOLCK) + seq_puts(seq, ",nolock"); - if (sbi->ll_flags & LL_SBI_LOCALFLOCK) - seq_puts(seq, ",localflock"); + /* "flock" is the default since 2.13, but it wasn't for many years, + * so it is still useful to print this to show it is enabled. + * Start to print "noflock" so it is now clear when flock is disabled. + */ + if (sbi->ll_flags & LL_SBI_FLOCK) + seq_puts(seq, ",flock"); + else if (sbi->ll_flags & LL_SBI_LOCALFLOCK) + seq_puts(seq, ",localflock"); + else + seq_puts(seq, ",noflock"); - if (sbi->ll_flags & LL_SBI_USER_XATTR) - seq_puts(seq, ",user_xattr"); + if (sbi->ll_flags & LL_SBI_USER_XATTR) + seq_puts(seq, ",user_xattr"); - if (sbi->ll_flags & LL_SBI_LAZYSTATFS) - seq_puts(seq, ",lazystatfs"); + if (sbi->ll_flags & LL_SBI_LAZYSTATFS) + seq_puts(seq, ",lazystatfs"); if (sbi->ll_flags & LL_SBI_USER_FID2PATH) seq_puts(seq, ",user_fid2path"); @@ -2577,7 +2789,7 @@ int ll_show_options(struct seq_file *seq, struct vfsmount *vfs) if (sbi->ll_flags & LL_SBI_ALWAYS_PING) seq_puts(seq, ",always_ping"); - RETURN(0); + RETURN(0); } /** @@ -2606,39 +2818,6 @@ int ll_get_obd_name(struct inode *inode, unsigned int cmd, unsigned long arg) RETURN(0); } -/** - * Get lustre file system name by \a sbi. If \a buf is provided(non-NULL), the - * fsname will be returned in this buffer; otherwise, a static buffer will be - * used to store the fsname and returned to caller. - */ -char *ll_get_fsname(struct super_block *sb, char *buf, int buflen) -{ - static char fsname_static[MTI_NAME_MAXLEN]; - struct lustre_sb_info *lsi = s2lsi(sb); - char *ptr; - int len; - - if (buf == NULL) { - /* this means the caller wants to use static buffer - * and it doesn't care about race. Usually this is - * in error reporting path */ - buf = fsname_static; - buflen = sizeof(fsname_static); - } - - len = strlen(lsi->lsi_lmd->lmd_profile); - ptr = strrchr(lsi->lsi_lmd->lmd_profile, '-'); - if (ptr && (strcmp(ptr, "-client") == 0)) - len -= 7; - - if (unlikely(len >= buflen)) - len = buflen - 1; - strncpy(buf, lsi->lsi_lmd->lmd_profile, len); - buf[len] = '\0'; - - return buf; -} - static char* ll_d_path(struct dentry *dentry, char *buf, int bufsize) { char *path = NULL; @@ -2667,9 +2846,10 @@ void ll_dirty_page_discard_warn(struct page *page, int ioret) path = ll_d_path(dentry, buf, PAGE_SIZE); } + /* The below message is checked in recovery-small.sh test_24b */ CDEBUG(D_WARNING, "%s: dirty page discard: %s/fid: "DFID"/%s may get corrupted " - "(rc %d)\n", ll_get_fsname(page->mapping->host->i_sb, NULL, 0), + "(rc %d)\n", ll_i2sbi(inode)->ll_fsname, s2lsi(page->mapping->host->i_sb)->lsi_lmd->lmd_dev, PFID(ll_inode2fid(inode)), (path && !IS_ERR(path)) ? path : "", ioret); @@ -2695,12 +2875,12 @@ ssize_t ll_copy_user_md(const struct lov_user_md __user *md, if (lum_size < 0) RETURN(lum_size); - OBD_ALLOC(*kbuf, lum_size); + OBD_ALLOC_LARGE(*kbuf, lum_size); if (*kbuf == NULL) RETURN(-ENOMEM); if (copy_from_user(*kbuf, md, lum_size) != 0) { - OBD_FREE(*kbuf, lum_size); + OBD_FREE_LARGE(*kbuf, lum_size); RETURN(-EFAULT); } @@ -2719,7 +2899,7 @@ void ll_compute_rootsquash_state(struct ll_sb_info *sbi) struct lnet_process_id id; /* Update norootsquash flag */ - down_write(&squash->rsi_sem); + spin_lock(&squash->rsi_lock); if (list_empty(&squash->rsi_nosquash_nids)) sbi->ll_flags &= ~LL_SBI_NOROOTSQUASH; else { @@ -2740,7 +2920,7 @@ void ll_compute_rootsquash_state(struct ll_sb_info *sbi) else sbi->ll_flags &= ~LL_SBI_NOROOTSQUASH; } - up_write(&squash->rsi_sem); + spin_unlock(&squash->rsi_lock); } /** @@ -2832,13 +3012,8 @@ int ll_getparent(struct file *file, struct getparent __user *arg) if (rc < 0) GOTO(ldata_free, rc); -#ifdef HAVE_XATTR_HANDLER_FLAGS rc = ll_xattr_list(inode, XATTR_NAME_LINK, XATTR_TRUSTED_T, buf.lb_buf, buf.lb_len, OBD_MD_FLXATTR); -#else - rc = ll_getxattr(file_dentry(file), XATTR_NAME_LINK, buf.lb_buf, - buf.lb_len); -#endif /* HAVE_XATTR_HANDLER_FLAGS */ if (rc < 0) GOTO(lb_free, rc);