X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fllite%2Fllite_lib.c;h=126efaa94c3a61ec7f47894baa9a776049ba7d05;hp=a984eb1061c491322968204f738b91e51a71ecc9;hb=472fe13982952c9ccad969a996c054f9cf643847;hpb=b4e0446ad189788529e4d69d4dfa9c822f2e3bae diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index a984eb1..126efaa 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -1,6 +1,4 @@ -/* -*- 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. @@ -28,6 +26,8 @@ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. + * + * Copyright (c) 2011, 2012, Whamcloud, Inc. */ /* * This file is part of Lustre, http://www.lustre.org/ @@ -59,10 +59,13 @@ cfs_mem_cache_t *ll_file_data_slab; CFS_LIST_HEAD(ll_super_blocks); -cfs_spinlock_t ll_sb_lock = CFS_SPIN_LOCK_UNLOCKED; +DEFINE_SPINLOCK(ll_sb_lock); +#ifndef MS_HAS_NEW_AOPS extern struct address_space_operations ll_aops; -extern struct address_space_operations ll_dir_aops; +#else +extern struct address_space_operations_ext ll_aops; +#endif #ifndef log2 #define log2(n) cfs_ffz(~(n)) @@ -70,8 +73,9 @@ extern struct address_space_operations ll_dir_aops; static struct ll_sb_info *ll_init_sbi(void) { - struct ll_sb_info *sbi = NULL; - unsigned long pages; + struct ll_sb_info *sbi = NULL; + unsigned long pages; + unsigned long lru_page_max; struct sysinfo si; class_uuid_t uuid; int i; @@ -82,7 +86,7 @@ static struct ll_sb_info *ll_init_sbi(void) RETURN(NULL); cfs_spin_lock_init(&sbi->ll_lock); - cfs_init_mutex(&sbi->ll_lco.lco_lock); + cfs_mutex_init(&sbi->ll_lco.lco_lock); cfs_spin_lock_init(&sbi->ll_pp_extent_lock); cfs_spin_lock_init(&sbi->ll_process_lock); sbi->ll_rw_stats_on = 0; @@ -91,13 +95,20 @@ static struct ll_sb_info *ll_init_sbi(void) pages = si.totalram - si.totalhigh; if (pages >> (20 - CFS_PAGE_SHIFT) < 512) { #ifdef HAVE_BGL_SUPPORT - sbi->ll_async_page_max = pages / 4; + lru_page_max = pages / 4; #else - sbi->ll_async_page_max = pages / 2; + lru_page_max = pages / 2; #endif - } else { - sbi->ll_async_page_max = (pages / 4) * 3; - } + } else { + lru_page_max = (pages / 4) * 3; + } + + /* initialize lru data */ + cfs_atomic_set(&sbi->ll_lru.ccl_users, 0); + sbi->ll_lru.ccl_page_max = lru_page_max; + cfs_atomic_set(&sbi->ll_lru.ccl_page_left, lru_page_max); + cfs_spin_lock_init(&sbi->ll_lru.ccl_lock); + CFS_INIT_LIST_HEAD(&sbi->ll_lru.ccl_list); sbi->ll_ra_info.ra_max_pages_per_file = min(pages / 32, SBI_DEFAULT_READAHEAD_MAX); @@ -115,6 +126,7 @@ static struct ll_sb_info *ll_init_sbi(void) cfs_list_add_tail(&sbi->ll_list, &ll_super_blocks); cfs_spin_unlock(&ll_sb_lock); + sbi->ll_flags |= LL_SBI_VERBOSE; #ifdef ENABLE_CHECKSUM sbi->ll_flags |= LL_SBI_CHECKSUM; #endif @@ -132,8 +144,10 @@ static struct ll_sb_info *ll_init_sbi(void) /* metadata statahead is enabled by default */ sbi->ll_sa_max = LL_SA_RPC_DEF; - atomic_set(&sbi->ll_sa_total, 0); - atomic_set(&sbi->ll_sa_wrong, 0); + cfs_atomic_set(&sbi->ll_sa_total, 0); + cfs_atomic_set(&sbi->ll_sa_wrong, 0); + cfs_atomic_set(&sbi->ll_agl_total, 0); + sbi->ll_flags |= LL_SBI_AGL_ENABLED; RETURN(sbi); } @@ -157,13 +171,14 @@ static struct dentry_operations ll_d_root_ops = { .d_revalidate = ll_revalidate_nd, }; -static int client_common_fill_super(struct super_block *sb, char *md, char *dt) +static int client_common_fill_super(struct super_block *sb, char *md, char *dt, + struct vfsmount *mnt) { struct inode *root = 0; struct ll_sb_info *sbi = ll_s2sbi(sb); struct obd_device *obd; struct obd_capa *oc = NULL; - struct obd_statfs osfs; + struct obd_statfs *osfs = NULL; struct ptlrpc_request *request = NULL; struct obd_connect_data *data = NULL; struct obd_uuid *uuid; @@ -183,6 +198,12 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) if (data == NULL) RETURN(-ENOMEM); + OBD_ALLOC_PTR(osfs); + if (osfs == NULL) { + OBD_FREE_PTR(data); + RETURN(-ENOMEM); + } + if (proc_lustre_fs_root) { err = lprocfs_register_mountpoint(proc_lustre_fs_root, sb, dt, md); @@ -192,12 +213,15 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) /* indicate the features supported by this client */ data->ocd_connect_flags = OBD_CONNECT_IBITS | OBD_CONNECT_NODEVOH | - OBD_CONNECT_JOIN | OBD_CONNECT_ATTRFID | - OBD_CONNECT_VERSION | OBD_CONNECT_MDS_CAPA | - OBD_CONNECT_OSS_CAPA | OBD_CONNECT_CANCELSET| - OBD_CONNECT_FID | OBD_CONNECT_AT | - OBD_CONNECT_LOV_V3 | OBD_CONNECT_RMT_CLIENT | - OBD_CONNECT_VBR | OBD_CONNECT_FULL20; + OBD_CONNECT_ATTRFID | + OBD_CONNECT_VERSION | OBD_CONNECT_BRW_SIZE | + OBD_CONNECT_MDS_CAPA | OBD_CONNECT_OSS_CAPA | + OBD_CONNECT_CANCELSET | OBD_CONNECT_FID | + OBD_CONNECT_AT | OBD_CONNECT_LOV_V3 | + OBD_CONNECT_RMT_CLIENT | OBD_CONNECT_VBR | + OBD_CONNECT_FULL20 | OBD_CONNECT_64BITHASH| + OBD_CONNECT_EINPROGRESS | + OBD_CONNECT_JOBSTATS; if (sbi->ll_flags & LL_SBI_SOM_PREVIEW) data->ocd_connect_flags |= OBD_CONNECT_SOM; @@ -209,6 +233,12 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) #ifdef CONFIG_FS_POSIX_ACL data->ocd_connect_flags |= OBD_CONNECT_ACL; #endif + + 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_ibits_known = MDS_INODELOCK_FULL; data->ocd_version = LUSTRE_VERSION_CODE; @@ -221,6 +251,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) /* force vfs to use lustre handler for flock() calls - bug 10743 */ sb->s_flags |= MS_FLOCK_LOCK; #endif +#ifdef MS_HAS_NEW_AOPS + sb->s_flags |= MS_HAS_NEW_AOPS; +#endif if (sbi->ll_flags & LL_SBI_FLOCK) sbi->ll_fop = &ll_file_operations_flock; @@ -234,6 +267,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) if (sbi->ll_flags & LL_SBI_RMT_CLIENT) data->ocd_connect_flags |= OBD_CONNECT_RMT_CLIENT_FORCE; + data->ocd_brw_size = PTLRPC_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 " @@ -253,38 +288,49 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) GOTO(out_md, err); } - err = obd_statfs(obd, &osfs, + err = obd_statfs(NULL, sbi->ll_md_exp, osfs, cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS), 0); if (err) GOTO(out_md_fid, err); + /* This needs to be after statfs to ensure connect has finished. + * Note that "data" does NOT contain the valid connect reply. + * If connecting to a 1.8 server there will be no LMV device, so + * we can access the MDC export directly and exp_connect_flags will + * be non-zero, but if accessing an upgraded 2.1 server it will + * have the correct flags filled in. + * XXX: fill in the LMV exp_connect_flags from MDC(s). */ + valid = sbi->ll_md_exp->exp_connect_flags & CLIENT_CONNECT_MDT_REQD; + if (sbi->ll_md_exp->exp_connect_flags != 0 && + valid != CLIENT_CONNECT_MDT_REQD) { + char *buf; + + OBD_ALLOC_WAIT(buf, CFS_PAGE_SIZE); + obd_connect_flags2str(buf, CFS_PAGE_SIZE, + valid ^ CLIENT_CONNECT_MDT_REQD, ","); + LCONSOLE_ERROR_MSG(0x170, "Server %s does not support " + "feature(s) needed for correct operation " + "of this client (%s). Please upgrade " + "server or downgrade client.\n", + sbi->ll_md_exp->exp_obd->obd_name, buf); + OBD_FREE(buf, CFS_PAGE_SIZE); + GOTO(out_md, err = -EPROTO); + } + size = sizeof(*data); - err = obd_get_info(sbi->ll_md_exp, sizeof(KEY_CONN_DATA), + err = obd_get_info(NULL, sbi->ll_md_exp, sizeof(KEY_CONN_DATA), KEY_CONN_DATA, &size, data, NULL); if (err) { CERROR("Get connect data failed: %d \n", err); GOTO(out_md, err); } - LASSERT(osfs.os_bsize); - sb->s_blocksize = osfs.os_bsize; - sb->s_blocksize_bits = log2(osfs.os_bsize); + LASSERT(osfs->os_bsize); + sb->s_blocksize = osfs->os_bsize; + sb->s_blocksize_bits = log2(osfs->os_bsize); sb->s_magic = LL_SUPER_MAGIC; - - /* for bug 11559. in $LINUX/fs/read_write.c, function do_sendfile(): - * retval = in_file->f_op->sendfile(...); - * if (*ppos > max) - * retval = -EOVERFLOW; - * - * it will check if *ppos is greater than max. However, max equals to - * s_maxbytes, which is a negative integer in a x86_64 box since loff_t - * has been defined as a signed long long integer in linux kernel. */ -#if BITS_PER_LONG == 64 - sb->s_maxbytes = PAGE_CACHE_MAXBYTES >> 1; -#else - sb->s_maxbytes = PAGE_CACHE_MAXBYTES; -#endif - sbi->ll_namelen = osfs.os_namelen; + sb->s_maxbytes = MAX_LFS_FILESIZE; + sbi->ll_namelen = osfs->os_namelen; sbi->ll_max_rw_chunk = LL_DEFAULT_MAX_RW_CHUNK; if ((sbi->ll_flags & LL_SBI_USER_XATTR) && @@ -330,6 +376,19 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) sbi->ll_flags |= LL_SBI_OSS_CAPA; } + if (data->ocd_connect_flags & OBD_CONNECT_64BITHASH) + sbi->ll_flags |= LL_SBI_64BIT_HASH; + + if (data->ocd_connect_flags & OBD_CONNECT_BRW_SIZE) + sbi->ll_md_brw_size = data->ocd_brw_size; + else + sbi->ll_md_brw_size = CFS_PAGE_SIZE; + + if (data->ocd_connect_flags & OBD_CONNECT_LAYOUTLOCK) { + LCONSOLE_INFO("Layout lock feature supported.\n"); + sbi->ll_flags |= LL_SBI_LAYOUT_LOCK; + } + obd = class_name2obd(dt); if (!obd) { CERROR("DT %s: not setup or attached\n", dt); @@ -342,7 +401,10 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) OBD_CONNECT_SRVLOCK | OBD_CONNECT_TRUNCLOCK| OBD_CONNECT_AT | OBD_CONNECT_RMT_CLIENT | OBD_CONNECT_OSS_CAPA | OBD_CONNECT_VBR| - OBD_CONNECT_FULL20; + OBD_CONNECT_FULL20 | OBD_CONNECT_64BITHASH | + OBD_CONNECT_MAXBYTES | + OBD_CONNECT_EINPROGRESS | + OBD_CONNECT_JOBSTATS; if (sbi->ll_flags & LL_SBI_SOM_PREVIEW) data->ocd_connect_flags |= OBD_CONNECT_SOM; @@ -354,11 +416,10 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) * 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 - /* send the list of supported checksum types */ - data->ocd_cksum_types = OBD_CKSUM_ALL; + 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(); } #ifdef HAVE_LRU_RESIZE_SUPPORT @@ -373,7 +434,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) obd->obd_upcall.onu_owner = &sbi->ll_lco; obd->obd_upcall.onu_upcall = cl_ocd_update; - data->ocd_brw_size = PTLRPC_MAX_BRW_PAGES << CFS_PAGE_SHIFT; + + data->ocd_brw_size = PTLRPC_MAX_BRW_SIZE; err = obd_connect(NULL, &sbi->ll_dt_exp, obd, &sbi->ll_sb_uuid, data, NULL); if (err == -EBUSY) { @@ -394,11 +456,11 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) GOTO(out_dt, err); } - cfs_mutex_down(&sbi->ll_lco.lco_lock); + cfs_mutex_lock(&sbi->ll_lco.lco_lock); sbi->ll_lco.lco_flags = data->ocd_connect_flags; sbi->ll_lco.lco_md_exp = sbi->ll_md_exp; sbi->ll_lco.lco_dt_exp = sbi->ll_dt_exp; - cfs_mutex_up(&sbi->ll_lco.lco_lock); + cfs_mutex_unlock(&sbi->ll_lco.lco_lock); fid_zero(&sbi->ll_root_fid); err = md_getstatus(sbi->ll_md_exp, &sbi->ll_root_fid, &oc); @@ -413,7 +475,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; -#if THREAD_SIZE >= 8192 +#if THREAD_SIZE >= 8192 /*b=17630*/ sb->s_export_op = &lustre_export_operations; #endif @@ -426,7 +488,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) valid |= OBD_MD_FLACL; OBD_ALLOC_PTR(op_data); - if (op_data == NULL) + if (op_data == NULL) GOTO(out_lock_cn_cb, err = -ENOMEM); op_data->op_fid1 = sbi->ll_root_fid; @@ -442,7 +504,6 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) CERROR("md_getattr failed for root: rc = %d\n", err); GOTO(out_lock_cn_cb, err); } - memset(&lmd, 0, sizeof(lmd)); err = md_get_lustre_md(sbi->ll_md_exp, request, sbi->ll_dt_exp, sbi->ll_md_exp, &lmd); if (err) { @@ -452,7 +513,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) } LASSERT(fid_is_sane(&sbi->ll_root_fid)); - root = ll_iget(sb, cl_fid_build_ino(&sbi->ll_root_fid), &lmd); + root = ll_iget(sb, cl_fid_build_ino(&sbi->ll_root_fid, 0), &lmd); md_free_lustre_md(sbi->ll_md_exp, &lmd); ptlrpc_req_finished(request); @@ -485,16 +546,23 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) #endif checksum = sbi->ll_flags & LL_SBI_CHECKSUM; - err = obd_set_info_async(sbi->ll_dt_exp, sizeof(KEY_CHECKSUM), + err = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_CHECKSUM), KEY_CHECKSUM, sizeof(checksum), &checksum, NULL); cl_sb_init(sb); - sb->s_root = d_alloc_root(root); - if (data != NULL) - OBD_FREE(data, sizeof(*data)); + err = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_LRU_SET), + KEY_LRU_SET, sizeof(sbi->ll_lru), + &sbi->ll_lru, NULL); - sb->s_root->d_op = &ll_d_root_ops; + sb->s_root = d_alloc_root(root); +#ifdef HAVE_DCACHE_LOCK + sb->s_root->d_op = &ll_d_root_ops; +#else + /* kernel >= 2.6.38 store dentry operations in sb->s_d_op. */ + d_set_d_op(sb->s_root, &ll_d_root_ops); + sb->s_d_op = &ll_d_ops; +#endif sbi->ll_sdev_orig = sb->s_dev; @@ -507,6 +575,11 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) if (uuid != NULL) sb->s_dev = get_uuid2int(uuid->uuid, strlen(uuid->uuid)); + if (data != NULL) + OBD_FREE_PTR(data); + if (osfs != NULL) + OBD_FREE_PTR(osfs); + RETURN(err); out_root: if (root) @@ -524,6 +597,8 @@ out_md: out: if (data != NULL) OBD_FREE_PTR(data); + if (osfs != NULL) + OBD_FREE_PTR(osfs); lprocfs_unregister_mountpoint(sbi); return err; } @@ -534,7 +609,7 @@ int ll_get_max_mdsize(struct ll_sb_info *sbi, int *lmmsize) *lmmsize = obd_size_diskmd(sbi->ll_dt_exp, NULL); size = sizeof(int); - rc = obd_get_info(sbi->ll_md_exp, sizeof(KEY_MAX_EASIZE), + rc = obd_get_info(NULL, sbi->ll_md_exp, sizeof(KEY_MAX_EASIZE), KEY_MAX_EASIZE, &size, lmmsize, NULL); if (rc) CERROR("Get max mdsize error rc %d \n", rc); @@ -571,7 +646,7 @@ void lustre_dump_dentry(struct dentry *dentry, int recur) " flags=0x%x, fsdata=%p, %d subdirs\n", dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_parent->d_name.len, dentry->d_parent->d_name.name, - dentry->d_parent, dentry->d_inode, atomic_read(&dentry->d_count), + dentry->d_parent, dentry->d_inode, d_refcount(dentry), dentry->d_flags, dentry->d_fsdata, subdirs); if (dentry->d_inode != NULL) ll_dump_inode(dentry->d_inode); @@ -579,10 +654,10 @@ void lustre_dump_dentry(struct dentry *dentry, int recur) if (recur == 0) return; - list_for_each(tmp, &dentry->d_subdirs) { - struct dentry *d = list_entry(tmp, struct dentry, d_child); - lustre_dump_dentry(d, recur - 1); - } + list_for_each(tmp, &dentry->d_subdirs) { + struct dentry *d = list_entry(tmp, struct dentry, d_u.d_child); + lustre_dump_dentry(d, recur - 1); + } } void client_common_put_super(struct super_block *sb) @@ -713,7 +788,7 @@ static int ll_options(char *options, int *flags) *flags &= ~tmp; goto next; } -#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2,5,50,0) +#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 5, 50, 0) tmp = ll_set_opt("acl", s1, LL_SBI_ACL); if (tmp) { /* Ignore deprecated mount option. The client will @@ -737,6 +812,16 @@ static int ll_options(char *options, int *flags) *flags |= tmp; goto next; } + tmp = ll_set_opt("user_fid2path", s1, LL_SBI_USER_FID2PATH); + if (tmp) { + *flags |= tmp; + goto next; + } + tmp = ll_set_opt("nouser_fid2path", s1, LL_SBI_USER_FID2PATH); + if (tmp) { + *flags &= ~tmp; + goto next; + } tmp = ll_set_opt("checksum", s1, LL_SBI_CHECKSUM); if (tmp) { @@ -778,7 +863,16 @@ static int ll_options(char *options, int *flags) *flags |= tmp; goto next; } - + tmp = ll_set_opt("verbose", s1, LL_SBI_VERBOSE); + if (tmp) { + *flags |= tmp; + goto next; + } + tmp = ll_set_opt("noverbose", s1, LL_SBI_VERBOSE); + if (tmp) { + *flags &= ~tmp; + goto next; + } LCONSOLE_ERROR_MSG(0x152, "Unknown option '%s', won't mount.\n", s1); RETURN(-EINVAL); @@ -796,48 +890,96 @@ next: void ll_lli_init(struct ll_inode_info *lli) { lli->lli_inode_magic = LLI_INODE_MAGIC; - cfs_sema_init(&lli->lli_size_sem, 1); - cfs_sema_init(&lli->lli_write_sem, 1); - cfs_sema_init(&lli->lli_trunc_sem, 1); lli->lli_flags = 0; - lli->lli_maxbytes = PAGE_CACHE_MAXBYTES; + lli->lli_ioepoch = 0; + lli->lli_maxbytes = MAX_LFS_FILESIZE; cfs_spin_lock_init(&lli->lli_lock); + lli->lli_posix_acl = NULL; + lli->lli_remote_perms = NULL; + cfs_mutex_init(&lli->lli_rmtperm_mutex); + /* Do not set lli_fid, it has been initialized already. */ + fid_zero(&lli->lli_pfid); CFS_INIT_LIST_HEAD(&lli->lli_close_list); - lli->lli_inode_magic = LLI_INODE_MAGIC; - cfs_sema_init(&lli->lli_och_sem, 1); - lli->lli_mds_read_och = lli->lli_mds_write_och = NULL; + CFS_INIT_LIST_HEAD(&lli->lli_oss_capas); + cfs_atomic_set(&lli->lli_open_count, 0); + lli->lli_mds_capa = NULL; + lli->lli_rmtperm_time = 0; + lli->lli_pending_och = NULL; + lli->lli_mds_read_och = NULL; + lli->lli_mds_write_och = NULL; lli->lli_mds_exec_och = NULL; - lli->lli_open_fd_read_count = lli->lli_open_fd_write_count = 0; + lli->lli_open_fd_read_count = 0; + lli->lli_open_fd_write_count = 0; lli->lli_open_fd_exec_count = 0; - CFS_INIT_LIST_HEAD(&lli->lli_dead_list); - lli->lli_remote_perms = NULL; - lli->lli_rmtperm_utime = 0; - cfs_sema_init(&lli->lli_rmtperm_sem, 1); - CFS_INIT_LIST_HEAD(&lli->lli_oss_capas); - cfs_spin_lock_init(&lli->lli_sa_lock); - CFS_INIT_LIST_HEAD(&lli->lli_sa_dentry); + cfs_mutex_init(&lli->lli_och_mutex); + cfs_spin_lock_init(&lli->lli_agl_lock); + lli->lli_has_smd = false; + lli->lli_clob = NULL; + + LASSERT(lli->lli_vfs_inode.i_mode != 0); + if (S_ISDIR(lli->lli_vfs_inode.i_mode)) { + cfs_mutex_init(&lli->lli_readdir_mutex); + lli->lli_opendir_key = NULL; + lli->lli_sai = NULL; + lli->lli_def_acl = NULL; + cfs_spin_lock_init(&lli->lli_sa_lock); + lli->lli_opendir_pid = 0; + } else { + cfs_sema_init(&lli->lli_size_sem, 1); + lli->lli_size_sem_owner = NULL; + lli->lli_symlink_name = NULL; + cfs_init_rwsem(&lli->lli_trunc_sem); + cfs_mutex_init(&lli->lli_write_mutex); + cfs_init_rwsem(&lli->lli_glimpse_sem); + lli->lli_glimpse_time = 0; + CFS_INIT_LIST_HEAD(&lli->lli_agl_list); + lli->lli_agl_index = 0; + lli->lli_async_rc = 0; + } + cfs_mutex_init(&lli->lli_layout_mutex); +} + +static inline int ll_bdi_register(struct backing_dev_info *bdi) +{ +#ifdef HAVE_BDI_REGISTER + static atomic_t ll_bdi_num = ATOMIC_INIT(0); + +#ifdef HAVE_BDI_NAME + bdi->name = "lustre"; +#endif + return bdi_register(bdi, NULL, "lustre-%d", + atomic_inc_return(&ll_bdi_num)); +#else + return 0; +#endif } -int ll_fill_super(struct super_block *sb) +int ll_fill_super(struct super_block *sb, struct vfsmount *mnt) { - struct lustre_profile *lprof; + struct lustre_profile *lprof = NULL; struct lustre_sb_info *lsi = s2lsi(sb); struct ll_sb_info *sbi; char *dt = NULL, *md = NULL; char *profilenm = get_profile_name(sb); - struct config_llog_instance cfg = {0, }; - char ll_instance[sizeof(sb) * 2 + 1]; + 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 err; ENTRY; CDEBUG(D_VFSTRACE, "VFS Op: sb %p\n", sb); + OBD_ALLOC_PTR(cfg); + if (cfg == NULL) + RETURN(-ENOMEM); + cfs_module_get(); /* client additional sb info */ lsi->lsi_llsbi = sbi = ll_init_sbi(); if (!sbi) { cfs_module_put(THIS_MODULE); + OBD_FREE_PTR(cfg); RETURN(-ENOMEM); } @@ -845,15 +987,27 @@ int ll_fill_super(struct super_block *sb) if (err) GOTO(out_free, err); + err = bdi_init(&lsi->lsi_bdi); + if (err) + GOTO(out_free, err); + lsi->lsi_flags |= LSI_BDI_INITIALIZED; + lsi->lsi_bdi.capabilities = BDI_CAP_MAP_COPY; + err = ll_bdi_register(&lsi->lsi_bdi); + if (err) + GOTO(out_free, err); + +#ifdef HAVE_SB_BDI + sb->s_bdi = &lsi->lsi_bdi; +#endif + /* 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.*/ - sprintf(ll_instance, "%p", sb); - cfg.cfg_instance = ll_instance; - cfg.cfg_uuid = lsi->lsi_llsbi->ll_sb_uuid; - + cfg->cfg_instance = sb; + cfg->cfg_uuid = lsi->lsi_llsbi->ll_sb_uuid; + cfg->cfg_callback = class_config_llog_handler; /* set up client obds */ - err = lustre_process_log(sb, profilenm, &cfg); + err = lustre_process_log(sb, profilenm, cfg); if (err < 0) { CERROR("Unable to process log: %d\n", err); GOTO(out_free, err); @@ -870,31 +1024,30 @@ int ll_fill_super(struct super_block *sb) CDEBUG(D_CONFIG, "Found profile %s: mdc=%s osc=%s\n", profilenm, lprof->lp_md, lprof->lp_dt); - OBD_ALLOC(dt, strlen(lprof->lp_dt) + - strlen(ll_instance) + 2); + OBD_ALLOC(dt, strlen(lprof->lp_dt) + instlen + 2); if (!dt) GOTO(out_free, err = -ENOMEM); - sprintf(dt, "%s-%s", lprof->lp_dt, ll_instance); + sprintf(dt, "%s-%p", lprof->lp_dt, cfg->cfg_instance); - OBD_ALLOC(md, strlen(lprof->lp_md) + - strlen(ll_instance) + 2); + OBD_ALLOC(md, strlen(lprof->lp_md) + instlen + 2); if (!md) GOTO(out_free, err = -ENOMEM); - sprintf(md, "%s-%s", lprof->lp_md, ll_instance); + sprintf(md, "%s-%p", lprof->lp_md, cfg->cfg_instance); /* connections, registrations, sb setup */ - err = client_common_fill_super(sb, md, dt); + err = client_common_fill_super(sb, md, dt, mnt); out_free: if (md) - OBD_FREE(md, strlen(md) + 1); + OBD_FREE(md, strlen(lprof->lp_md) + instlen + 2); if (dt) - OBD_FREE(dt, strlen(dt) + 1); + OBD_FREE(dt, strlen(lprof->lp_dt) + instlen + 2); if (err) ll_put_super(sb); - else - LCONSOLE_WARN("Client %s has started\n", profilenm); + else if (sbi->ll_flags & LL_SBI_VERBOSE) + LCONSOLE_WARN("Mounted %s\n", profilenm); + OBD_FREE_PTR(cfg); RETURN(err); } /* ll_fill_super */ @@ -904,7 +1057,6 @@ void lu_context_keys_dump(void); void ll_put_super(struct super_block *sb) { struct config_llog_instance cfg; - char ll_instance[sizeof(sb) * 2 + 1]; struct obd_device *obd; struct lustre_sb_info *lsi = s2lsi(sb); struct ll_sb_info *sbi = ll_s2sbi(sb); @@ -916,9 +1068,8 @@ void ll_put_super(struct super_block *sb) ll_print_capa_stat(sbi); - sprintf(ll_instance, "%p", sb); - cfg.cfg_instance = ll_instance; - lustre_end_log(sb, NULL, &cfg); + cfg.cfg_instance = sb; + lustre_end_log(sb, profilenm, &cfg); if (sbi->ll_md_exp) { obd = class_exp2obd(sbi->ll_md_exp); @@ -946,9 +1097,17 @@ void ll_put_super(struct super_block *sb) class_manual_cleanup(obd); } + if (sbi->ll_flags & LL_SBI_VERBOSE) + LCONSOLE_WARN("Unmounted %s\n", profilenm ? profilenm : ""); + if (profilenm) class_del_profile(profilenm); + if (lsi->lsi_flags & LSI_BDI_INITIALIZED) { + bdi_destroy(&lsi->lsi_bdi); + lsi->lsi_flags &= ~LSI_BDI_INITIALIZED; + } + ll_free_sbi(sb); lsi->lsi_llsbi = NULL; @@ -956,8 +1115,6 @@ void ll_put_super(struct super_block *sb) cl_env_cache_purge(~0); - LCONSOLE_WARN("client %s umount complete\n", ll_instance); - cfs_module_put(THIS_MODULE); EXIT; @@ -974,11 +1131,10 @@ struct inode *ll_inode_from_lock(struct ldlm_lock *lock) inode = igrab(lock->l_ast_data); } else { inode = lock->l_ast_data; - ldlm_lock_debug(NULL, inode->i_state & I_FREEING ? - D_INFO : D_WARNING, - lock, __FILE__, __func__, __LINE__, - "l_ast_data %p is bogus: magic %08x", - lock->l_ast_data, lli->lli_inode_magic); + LDLM_DEBUG_LIMIT(inode->i_state & I_FREEING ? D_INFO : + D_WARNING, lock, "l_ast_data %p is " + "bogus: magic %08x", lock->l_ast_data, + lli->lli_inode_magic); inode = NULL; } } @@ -1009,8 +1165,8 @@ void ll_clear_inode(struct inode *inode) if (S_ISDIR(inode->i_mode)) { /* these should have been cleared in ll_file_release */ - LASSERT(lli->lli_sai == NULL); LASSERT(lli->lli_opendir_key == NULL); + LASSERT(lli->lli_sai == NULL); LASSERT(lli->lli_opendir_pid == 0); } @@ -1029,7 +1185,7 @@ void ll_clear_inode(struct inode *inode) if (lli->lli_mds_read_och) ll_md_real_close(inode, FMODE_READ); - if (lli->lli_symlink_name) { + if (S_ISLNK(inode->i_mode) && lli->lli_symlink_name) { OBD_FREE(lli->lli_symlink_name, strlen(lli->lli_symlink_name) + 1); lli->lli_symlink_name = NULL; @@ -1053,28 +1209,27 @@ void ll_clear_inode(struct inode *inode) lli->lli_inode_magic = LLI_INODE_DEAD; ll_clear_inode_capas(inode); + if (!S_ISDIR(inode->i_mode)) + LASSERT(cfs_list_empty(&lli->lli_agl_list)); + /* * XXX This has to be done before lsm is freed below, because * cl_object still uses inode lsm. */ cl_inode_fini(inode); + lli->lli_has_smd = false; - if (lli->lli_smd) { - obd_free_memmd(sbi->ll_dt_exp, &lli->lli_smd); - lli->lli_smd = NULL; - } - - - EXIT; + EXIT; } -int ll_md_setattr(struct inode *inode, struct md_op_data *op_data, +int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data, struct md_open_data **mod) { struct lustre_md md; + struct inode *inode = dentry->d_inode; struct ll_sb_info *sbi = ll_i2sbi(inode); struct ptlrpc_request *request = NULL; - int rc; + int rc, ia_valid; ENTRY; op_data = ll_prep_md_op_data(op_data, inode, NULL, NULL, 0, 0, @@ -1084,20 +1239,24 @@ int ll_md_setattr(struct inode *inode, struct md_op_data *op_data, rc = md_setattr(sbi->ll_md_exp, op_data, NULL, 0, NULL, 0, &request, mod); - if (rc) { - ptlrpc_req_finished(request); - if (rc == -ENOENT) { - inode->i_nlink = 0; - /* Unlinked special device node? Or just a race? - * Pretend we done everything. */ - if (!S_ISREG(inode->i_mode) && - !S_ISDIR(inode->i_mode)) - rc = inode_setattr(inode, &op_data->op_attr); - } else if (rc != -EPERM && rc != -EACCES && rc != -ETXTBSY) { - CERROR("md_setattr fails: rc = %d\n", rc); - } - RETURN(rc); - } + if (rc) { + ptlrpc_req_finished(request); + if (rc == -ENOENT) { + clear_nlink(inode); + /* Unlinked special device node? Or just a race? + * Pretend we done everything. */ + if (!S_ISREG(inode->i_mode) && + !S_ISDIR(inode->i_mode)) { + ia_valid = op_data->op_attr.ia_valid; + op_data->op_attr.ia_valid &= ~TIMES_SET_FLAGS; + rc = simple_setattr(dentry, &op_data->op_attr); + op_data->op_attr.ia_valid = ia_valid; + } + } else if (rc != -EPERM && rc != -EACCES && rc != -ETXTBSY) { + CERROR("md_setattr fails: rc = %d\n", rc); + } + RETURN(rc); + } rc = md_get_lustre_md(sbi->ll_md_exp, request, sbi->ll_dt_exp, sbi->ll_md_exp, &md); @@ -1106,12 +1265,16 @@ int ll_md_setattr(struct inode *inode, struct md_op_data *op_data, RETURN(rc); } - /* We call inode_setattr to adjust timestamps. + /* We want to adjust timestamps. * If there is at least some data in file, we cleared ATTR_SIZE - * above to avoid invoking vmtruncate, otherwise it is important - * to call vmtruncate in inode_setattr to update inode->i_size + * to avoid update size, otherwise it is important to do.(SOM case) * (bug 6196) */ - rc = inode_setattr(inode, &op_data->op_attr); + ia_valid = op_data->op_attr.ia_valid; + /* Since we set ATTR_*_SET flags above, and already done permission + * check, So don't let inode_change_ok() check it again. */ + op_data->op_attr.ia_valid &= ~TIMES_SET_FLAGS; + rc = simple_setattr(dentry, &op_data->op_attr); + op_data->op_attr.ia_valid = ia_valid; /* Extract epoch data if obtained. */ op_data->op_handle = md.body->handle; @@ -1175,6 +1338,50 @@ static int ll_setattr_ost(struct inode *inode, struct iattr *attr) return rc; } +#ifndef HAVE_VFS_INODE_NEWSIZE_OK +/** + * inode_newsize_ok - may this inode be truncated to a given size + * @inode: the inode to be truncated + * @offset: the new size to assign to the inode + * @Returns: 0 on success, -ve errno on failure + * + * inode_newsize_ok will check filesystem limits and ulimits to check that the + * new inode size is within limits. inode_newsize_ok will also send SIGXFSZ + * when necessary. Caller must not proceed with inode size change if failure is + * returned. @inode must be a file (not directory), with appropriate + * permissions to allow truncate (inode_newsize_ok does NOT check these + * conditions). + * + * inode_newsize_ok must be called with i_mutex held. + */ +int inode_newsize_ok(const struct inode *inode, loff_t offset) +{ + if (inode->i_size < offset) { + unsigned long limit; + + limit = rlimit(RLIMIT_FSIZE); + if (limit != RLIM_INFINITY && offset > limit) + goto out_sig; + if (offset > inode->i_sb->s_maxbytes) + goto out_big; + } else { + /* + * truncation of in-use swapfiles is disallowed - it would + * cause subsequent swapout to scribble on the now-freed + * blocks. + */ + if (IS_SWAPFILE(inode)) + return -ETXTBSY; + } + + return 0; +out_sig: + send_sig(SIGXFSZ, current, 0); +out_big: + return -EFBIG; +} +#endif + /* If this inode has objects allocated to it (lsm != NULL), then the OST * object(s) determine the file size and mtime. Otherwise, the MDS will * keep these values until such a time that objects are allocated for it. @@ -1188,24 +1395,35 @@ static int ll_setattr_ost(struct inode *inode, struct iattr *attr) * I don't believe it is possible to get e.g. ATTR_MTIME_SET and ATTR_SIZE * at the same time. */ -int ll_setattr_raw(struct inode *inode, struct iattr *attr) +int ll_setattr_raw(struct dentry *dentry, struct iattr *attr) { + struct lov_stripe_md *lsm; + struct inode *inode = dentry->d_inode; struct ll_inode_info *lli = ll_i2info(inode); - struct lov_stripe_md *lsm = lli->lli_smd; struct md_op_data *op_data = NULL; struct md_open_data *mod = NULL; int ia_valid = attr->ia_valid; int rc = 0, rc1 = 0; ENTRY; - CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu valid %x\n", inode->i_ino, - attr->ia_valid); - ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_SETATTR, 1); + CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu (%p) to %llu, valid %x\n", + inode->i_ino, + inode,i_size_read(inode), + attr->ia_valid); if (ia_valid & ATTR_SIZE) { + /* Check new size against VFS/VM file size limit and rlimit */ + rc = inode_newsize_ok(inode, attr->ia_size); + if (rc) + RETURN(rc); + + /* The maximum Lustre file size is variable, based on the + * OST maximum object size and number of stripes. This + * needs another check in addition to the VFS check above. */ if (attr->ia_size > ll_file_maxbytes(inode)) { - CDEBUG(D_INODE, "file too large %llu > "LPU64"\n", - attr->ia_size, ll_file_maxbytes(inode)); + CDEBUG(D_INODE,"file "DFID" too large %llu > "LPU64"\n", + PFID(&lli->lli_fid), attr->ia_size, + ll_file_maxbytes(inode)); RETURN(-EFBIG); } @@ -1213,7 +1431,7 @@ int ll_setattr_raw(struct inode *inode, struct iattr *attr) } /* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */ - if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { + if (ia_valid & TIMES_SET_FLAGS) { if (cfs_curproc_fsuid() != inode->i_uid && !cfs_capable(CFS_CAP_FOWNER)) RETURN(-EPERM); @@ -1238,11 +1456,6 @@ int ll_setattr_raw(struct inode *inode, struct iattr *attr) LTIME_S(attr->ia_mtime), LTIME_S(attr->ia_ctime), cfs_time_current_sec()); - /* NB: ATTR_SIZE will only be set after this point if the size - * resides on the MDS, ie, this file has no objects. */ - if (lsm) - attr->ia_valid &= ~ATTR_SIZE; - /* We always do an MDS RPC, even if we're only changing the size; * only the MDS knows whether truncate() should fail with -ETXTBUSY */ @@ -1250,13 +1463,24 @@ int ll_setattr_raw(struct inode *inode, struct iattr *attr) if (op_data == NULL) RETURN(-ENOMEM); - UNLOCK_INODE_MUTEX(inode); - if (ia_valid & ATTR_SIZE) - UP_WRITE_I_ALLOC_SEM(inode); - cfs_down(&lli->lli_trunc_sem); - LOCK_INODE_MUTEX(inode); - if (ia_valid & ATTR_SIZE) - DOWN_WRITE_I_ALLOC_SEM(inode); + if (!S_ISDIR(inode->i_mode)) { + if (ia_valid & ATTR_SIZE) + inode_dio_write_done(inode); + mutex_unlock(&inode->i_mutex); + cfs_down_write(&lli->lli_trunc_sem); + mutex_lock(&inode->i_mutex); + if (ia_valid & ATTR_SIZE) + inode_dio_wait(inode); + } + + /* We need a steady stripe configuration for setattr to avoid + * confusion. */ + lsm = ccc_inode_lsm_get(inode); + + /* NB: ATTR_SIZE will only be set after this point if the size + * resides on the MDS, ie, this file has no objects. */ + if (lsm != NULL) + attr->ia_valid &= ~ATTR_SIZE; memcpy(&op_data->op_attr, attr, sizeof(*attr)); @@ -1265,56 +1489,74 @@ int ll_setattr_raw(struct inode *inode, struct iattr *attr) (ia_valid & (ATTR_SIZE | ATTR_MTIME | ATTR_MTIME_SET))) op_data->op_flags = MF_EPOCH_OPEN; - rc = ll_md_setattr(inode, op_data, &mod); + rc = ll_md_setattr(dentry, op_data, &mod); if (rc) GOTO(out, rc); ll_ioepoch_open(lli, op_data->op_ioepoch); - if (!lsm || !S_ISREG(inode->i_mode)) { + if (lsm == NULL || !S_ISREG(inode->i_mode)) { CDEBUG(D_INODE, "no lsm: not setting attrs on OST\n"); GOTO(out, rc = 0); } if (ia_valid & ATTR_SIZE) attr->ia_valid |= ATTR_SIZE; - if ((ia_valid & ATTR_SIZE) || - (ia_valid | ATTR_ATIME | ATTR_ATIME_SET) || - (ia_valid | ATTR_MTIME | ATTR_MTIME_SET)) - /* on truncate and utimes send attributes to osts, setting - * mtime/atime to 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 */ + if (ia_valid & (ATTR_SIZE | + ATTR_ATIME | ATTR_ATIME_SET | + ATTR_MTIME | ATTR_MTIME_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 = ll_setattr_ost(inode, attr); EXIT; out: + ccc_inode_lsm_put(inode, lsm); if (op_data) { - if (op_data->op_ioepoch) + if (op_data->op_ioepoch) { rc1 = ll_setattr_done_writing(inode, op_data, mod); + if (!rc) + rc = rc1; + } ll_finish_md_op_data(op_data); } - cfs_up(&lli->lli_trunc_sem); - return rc ? rc : rc1; + if (!S_ISDIR(inode->i_mode)) + cfs_up_write(&lli->lli_trunc_sem); + + ll_stats_ops_tally(ll_i2sbi(inode), (ia_valid & ATTR_SIZE) ? + LPROC_LL_TRUNC : LPROC_LL_SETATTR, 1); + + return rc; } int ll_setattr(struct dentry *de, struct iattr *attr) { + int mode = de->d_inode->i_mode; + if ((attr->ia_valid & (ATTR_CTIME|ATTR_SIZE|ATTR_MODE)) == - (ATTR_CTIME|ATTR_SIZE|ATTR_MODE)) + (ATTR_CTIME|ATTR_SIZE|ATTR_MODE)) attr->ia_valid |= MDS_OPEN_OWNEROVERRIDE; - if ((de->d_inode->i_mode & S_ISUID) && + if (((attr->ia_valid & (ATTR_MODE|ATTR_FORCE|ATTR_SIZE)) == + (ATTR_SIZE|ATTR_MODE)) && + (((mode & S_ISUID) && !(attr->ia_mode & S_ISUID)) || + (((mode & (S_ISGID|S_IXGRP)) == (S_ISGID|S_IXGRP)) && + !(attr->ia_mode & S_ISGID)))) + attr->ia_valid |= ATTR_FORCE; + + if ((mode & S_ISUID) && !(attr->ia_mode & S_ISUID) && !(attr->ia_valid & ATTR_KILL_SUID)) attr->ia_valid |= ATTR_KILL_SUID; - if (((de->d_inode->i_mode & (S_ISGID|S_IXGRP)) == (S_ISGID|S_IXGRP)) && + if (((mode & (S_ISGID|S_IXGRP)) == (S_ISGID|S_IXGRP)) && !(attr->ia_mode & S_ISGID) && !(attr->ia_valid & ATTR_KILL_SGID)) attr->ia_valid |= ATTR_KILL_SGID; - return ll_setattr_raw(de->d_inode, attr); + return ll_setattr_raw(de, attr); } int ll_statfs_internal(struct super_block *sb, struct obd_statfs *osfs, @@ -1325,7 +1567,7 @@ int ll_statfs_internal(struct super_block *sb, struct obd_statfs *osfs, int rc; ENTRY; - rc = obd_statfs(class_exp2obd(sbi->ll_md_exp), osfs, max_age, flags); + rc = obd_statfs(NULL, sbi->ll_md_exp, osfs, max_age, flags); if (rc) { CERROR("md_statfs fails: rc = %d\n", rc); RETURN(rc); @@ -1339,8 +1581,7 @@ int ll_statfs_internal(struct super_block *sb, struct obd_statfs *osfs, if (sbi->ll_flags & LL_SBI_LAZYSTATFS) flags |= OBD_STATFS_NODELAY; - rc = obd_statfs_rqset(class_exp2obd(sbi->ll_dt_exp), - &obd_osfs, max_age, flags); + rc = obd_statfs_rqset(sbi->ll_dt_exp, &obd_osfs, max_age, flags); if (rc) { CERROR("obd_statfs fails: rc = %d\n", rc); RETURN(rc); @@ -1367,16 +1608,11 @@ int ll_statfs_internal(struct super_block *sb, struct obd_statfs *osfs, RETURN(rc); } -#ifndef HAVE_STATFS_DENTRY_PARAM -int ll_statfs(struct super_block *sb, struct kstatfs *sfs) -{ -#else int ll_statfs(struct dentry *de, struct kstatfs *sfs) { - struct super_block *sb = de->d_sb; -#endif - struct obd_statfs osfs; - int rc; + struct super_block *sb = de->d_sb; + struct obd_statfs osfs; + int rc; CDEBUG(D_VFSTRACE, "VFS Op: at "LPU64" jiffies\n", get_jiffies_64()); ll_stats_ops_tally(ll_s2sbi(sb), LPROC_LL_STAFS, 1); @@ -1411,34 +1647,24 @@ int ll_statfs(struct dentry *de, struct kstatfs *sfs) return 0; } -void ll_inode_size_lock(struct inode *inode, int lock_lsm) +void ll_inode_size_lock(struct inode *inode) { struct ll_inode_info *lli; - struct lov_stripe_md *lsm; + + LASSERT(!S_ISDIR(inode->i_mode)); lli = ll_i2info(inode); LASSERT(lli->lli_size_sem_owner != current); cfs_down(&lli->lli_size_sem); LASSERT(lli->lli_size_sem_owner == NULL); lli->lli_size_sem_owner = current; - lsm = lli->lli_smd; - LASSERTF(lsm != NULL || lock_lsm == 0, "lsm %p, lock_lsm %d\n", - lsm, lock_lsm); - if (lock_lsm) - lov_stripe_lock(lsm); } -void ll_inode_size_unlock(struct inode *inode, int unlock_lsm) +void ll_inode_size_unlock(struct inode *inode) { struct ll_inode_info *lli; - struct lov_stripe_md *lsm; lli = ll_i2info(inode); - lsm = lli->lli_smd; - LASSERTF(lsm != NULL || unlock_lsm == 0, "lsm %p, lock_lsm %d\n", - lsm, unlock_lsm); - if (unlock_lsm) - lov_stripe_unlock(lsm); LASSERT(lli->lli_size_sem_owner == current); lli->lli_size_sem_owner = NULL; cfs_up(&lli->lli_size_sem); @@ -1446,50 +1672,31 @@ void ll_inode_size_unlock(struct inode *inode, int unlock_lsm) void ll_update_inode(struct inode *inode, struct lustre_md *md) { - struct ll_inode_info *lli = ll_i2info(inode); - struct mdt_body *body = md->body; - struct lov_stripe_md *lsm = md->lsm; - struct ll_sb_info *sbi = ll_i2sbi(inode); - - LASSERT ((lsm != NULL) == ((body->valid & OBD_MD_FLEASIZE) != 0)); - if (lsm != NULL) { - cfs_down(&lli->lli_och_sem); - if (lli->lli_smd == NULL) { - if (lsm->lsm_magic != LOV_MAGIC_V1 && - lsm->lsm_magic != LOV_MAGIC_V3) { - dump_lsm(D_ERROR, lsm); - LBUG(); - } - CDEBUG(D_INODE, "adding lsm %p to inode %lu/%u(%p)\n", - lsm, inode->i_ino, inode->i_generation, inode); - /* cl_inode_init must go before lli_smd or a race is - * possible where client thinks the file has stripes, - * but lov raid0 is not setup yet and parallel e.g. - * glimpse would try to use uninitialized lov */ - cl_inode_init(inode, md); - lli->lli_smd = lsm; - cfs_up(&lli->lli_och_sem); - lli->lli_maxbytes = lsm->lsm_maxbytes; - if (lli->lli_maxbytes > PAGE_CACHE_MAXBYTES) - lli->lli_maxbytes = PAGE_CACHE_MAXBYTES; - } else { - cfs_up(&lli->lli_och_sem); - LASSERT(lli->lli_smd->lsm_magic == lsm->lsm_magic && - lli->lli_smd->lsm_stripe_count == - lsm->lsm_stripe_count); - if (lov_stripe_md_cmp(lli->lli_smd, lsm)) { - CERROR("lsm mismatch for inode %ld\n", - inode->i_ino); - CERROR("lli_smd:\n"); - dump_lsm(D_ERROR, lli->lli_smd); - CERROR("lsm:\n"); - dump_lsm(D_ERROR, lsm); - LBUG(); - } - } - if (lli->lli_smd != lsm) - obd_free_memmd(ll_i2dtexp(inode), &lsm); - } + struct ll_inode_info *lli = ll_i2info(inode); + struct mdt_body *body = md->body; + struct lov_stripe_md *lsm = md->lsm; + struct ll_sb_info *sbi = ll_i2sbi(inode); + + LASSERT ((lsm != NULL) == ((body->valid & OBD_MD_FLEASIZE) != 0)); + if (lsm != NULL) { + LASSERT(S_ISREG(inode->i_mode)); + cfs_mutex_lock(&lli->lli_och_mutex); + CDEBUG(D_INODE, "adding lsm %p to inode %lu/%u(%p)\n", + lsm, inode->i_ino, inode->i_generation, inode); + /* cl_file_inode_init must go before lli_has_smd or a race + * is possible where client thinks the file has stripes, + * but lov raid0 is not setup yet and parallel e.g. + * glimpse would try to use uninitialized lov */ + if (cl_file_inode_init(inode, md) == 0) + lli->lli_has_smd = true; + cfs_mutex_unlock(&lli->lli_och_mutex); + + lli->lli_maxbytes = lsm->lsm_maxbytes; + if (lli->lli_maxbytes > MAX_LFS_FILESIZE) + lli->lli_maxbytes = MAX_LFS_FILESIZE; + if (md->lsm != NULL) + obd_free_memmd(ll_i2dtexp(inode), &md->lsm); + } if (sbi->ll_flags & LL_SBI_RMT_CLIENT) { if (body->valid & OBD_MD_FLRMTPERM) @@ -1504,7 +1711,7 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md) cfs_spin_unlock(&lli->lli_lock); } #endif - inode->i_ino = cl_fid_build_ino(&body->fid1); + inode->i_ino = cl_fid_build_ino(&body->fid1, 0); inode->i_generation = cl_fid_build_gen(&body->fid1); if (body->valid & OBD_MD_FLATIME) { @@ -1536,19 +1743,16 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md) } else { inode->i_blkbits = inode->i_sb->s_blocksize_bits; } -#ifdef HAVE_INODE_BLKSIZE - inode->i_blksize = 1<i_blkbits; -#endif - if (body->valid & OBD_MD_FLUID) - inode->i_uid = body->uid; - if (body->valid & OBD_MD_FLGID) - inode->i_gid = body->gid; - if (body->valid & OBD_MD_FLFLAGS) - inode->i_flags = ll_ext_to_inode_flags(body->flags); - if (body->valid & OBD_MD_FLNLINK) - inode->i_nlink = body->nlink; - if (body->valid & OBD_MD_FLRDEV) - inode->i_rdev = old_decode_dev(body->rdev); + if (body->valid & OBD_MD_FLUID) + inode->i_uid = body->uid; + if (body->valid & OBD_MD_FLGID) + inode->i_gid = body->gid; + if (body->valid & OBD_MD_FLFLAGS) + inode->i_flags = ll_ext_to_inode_flags(body->flags); + if (body->valid & OBD_MD_FLNLINK) + set_nlink(inode, body->nlink); + if (body->valid & OBD_MD_FLRDEV) + inode->i_rdev = old_decode_dev(body->rdev); if (body->valid & OBD_MD_FLID) { /* FID shouldn't be changed! */ @@ -1566,7 +1770,7 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md) if (body->valid & OBD_MD_FLSIZE) { if (exp_connect_som(ll_i2mdexp(inode)) && - S_ISREG(inode->i_mode) && lli->lli_smd) { + S_ISREG(inode->i_mode) && lli->lli_has_smd) { struct lustre_handle lockh; ldlm_mode_t mode; @@ -1580,14 +1784,14 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md) if (lli->lli_flags & (LLIF_DONE_WRITING | LLIF_EPOCH_PENDING | LLIF_SOM_DIRTY)) { - CERROR("ino %lu flags %lu still has " + CERROR("ino %lu flags %u still has " "size authority! do not trust " "the size got from MDS\n", inode->i_ino, lli->lli_flags); } else { /* Use old size assignment to avoid * deadlock bz14138 & bz14326 */ - inode->i_size = body->size; + i_size_write(inode, body->size); lli->lli_flags |= LLIF_MDS_SIZE_LOCK; } ldlm_lock_decref(&lockh, mode); @@ -1595,7 +1799,7 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md) } else { /* Use old size assignment to avoid * deadlock bz14138 & bz14326 */ - inode->i_size = body->size; + i_size_write(inode, body->size); CDEBUG(D_VFSTRACE, "inode=%lu, updating i_size %llu\n", inode->i_ino, (unsigned long long)body->size); @@ -1615,27 +1819,16 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md) } } -static struct backing_dev_info ll_backing_dev_info = { - .ra_pages = 0, /* No readahead */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)) - .capabilities = 0, /* Does contribute to dirty memory */ -#else - .memory_backed = 0, /* Does contribute to dirty memory */ -#endif -}; - void ll_read_inode2(struct inode *inode, void *opaque) { struct lustre_md *md = opaque; struct ll_inode_info *lli = ll_i2info(inode); ENTRY; - CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", - inode->i_ino, inode->i_generation, inode); - - ll_lli_init(lli); + CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n", + PFID(&lli->lli_fid), inode); - LASSERT(!lli->lli_smd); + LASSERT(!lli->lli_has_smd); /* 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 @@ -1649,16 +1842,19 @@ void ll_read_inode2(struct inode *inode, void *opaque) /* OIDEBUG(inode); */ + /* initializing backing dev info. */ + inode->i_mapping->backing_dev_info = &s2lsi(inode->i_sb)->lsi_bdi; + + if (S_ISREG(inode->i_mode)) { struct ll_sb_info *sbi = ll_i2sbi(inode); inode->i_op = &ll_file_inode_operations; inode->i_fop = sbi->ll_fop; - inode->i_mapping->a_ops = &ll_aops; + inode->i_mapping->a_ops = (struct address_space_operations *)&ll_aops; EXIT; } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &ll_dir_inode_operations; inode->i_fop = &ll_dir_operations; - inode->i_mapping->a_ops = &ll_dir_aops; EXIT; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &ll_fast_symlink_inode_operations; @@ -1666,11 +1862,8 @@ void ll_read_inode2(struct inode *inode, void *opaque) } else { inode->i_op = &ll_special_inode_operations; - init_special_inode(inode, inode->i_mode, - kdev_t_to_nr(inode->i_rdev)); - - /* initializing backing dev info. */ - inode->i_mapping->backing_dev_info = &ll_backing_dev_info; + init_special_inode(inode, inode->i_mode, + inode->i_rdev); EXIT; } @@ -1678,16 +1871,40 @@ void ll_read_inode2(struct inode *inode, void *opaque) void ll_delete_inode(struct inode *inode) { - struct ll_sb_info *sbi = ll_i2sbi(inode); - int rc; - ENTRY; + struct cl_inode_info *lli = cl_i2info(inode); + struct ll_sb_info *sbi = ll_i2sbi(inode); + int rc; + ENTRY; + + rc = obd_fid_delete(sbi->ll_md_exp, ll_inode2fid(inode)); + if (rc) + CERROR("fid_delete() failed, rc %d\n", rc); + + if (S_ISREG(inode->i_mode) && lli->lli_clob != NULL) + /* discard all dirty pages before truncating them, required by + * osc_extent implementation at LU-1030. */ + cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, CL_FSYNC_DISCARD); - rc = obd_fid_delete(sbi->ll_md_exp, ll_inode2fid(inode)); - if (rc) { - CERROR("fid_delete() failed, rc %d\n", rc); - } truncate_inode_pages(&inode->i_data, 0); + + /* Workaround for LU-118 */ + if (inode->i_data.nrpages) { + TREE_READ_LOCK_IRQ(&inode->i_data); + TREE_READ_UNLOCK_IRQ(&inode->i_data); + LASSERTF(inode->i_data.nrpages == 0, + "inode=%lu/%u(%p) nrpages=%lu, see " + "http://jira.whamcloud.com/browse/LU-118\n", + inode->i_ino, inode->i_generation, inode, + inode->i_data.nrpages); + } + /* Workaround end */ + +#ifdef HAVE_SBOPS_EVICT_INODE + ll_clear_inode(inode); + end_writeback(inode); +#else clear_inode(inode); +#endif EXIT; } @@ -1708,8 +1925,8 @@ int ll_iocontrol(struct inode *inode, struct file *file, op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0, LUSTRE_OPC_ANY, NULL); - if (op_data == NULL) - RETURN(-ENOMEM); + if (IS_ERR(op_data)) + RETURN(PTR_ERR(op_data)); op_data->op_valid = OBD_MD_FLFLAGS; rc = md_getattr(sbi->ll_md_exp, op_data, &req); @@ -1728,18 +1945,13 @@ int ll_iocontrol(struct inode *inode, struct file *file, RETURN(put_user(flags, (int *)arg)); } case FSFILT_IOC_SETFLAGS: { - struct lov_stripe_md *lsm = ll_i2info(inode)->lli_smd; + struct lov_stripe_md *lsm; struct obd_info oinfo = { { { 0 } } }; struct md_op_data *op_data; if (get_user(flags, (int *)arg)) RETURN(-EFAULT); - oinfo.oi_md = lsm; - OBDO_ALLOC(oinfo.oi_oa); - if (!oinfo.oi_oa) - RETURN(-ENOMEM); - op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0, LUSTRE_OPC_ANY, NULL); if (IS_ERR(op_data)) @@ -1751,37 +1963,37 @@ int ll_iocontrol(struct inode *inode, struct file *file, NULL, 0, NULL, 0, &req, NULL); ll_finish_md_op_data(op_data); ptlrpc_req_finished(req); - if (rc) { - OBDO_FREE(oinfo.oi_oa); - RETURN(rc); - } + if (rc) + RETURN(rc); - if (lsm == NULL) { - OBDO_FREE(oinfo.oi_oa); - GOTO(update_cache, rc); - } + inode->i_flags = ll_ext_to_inode_flags(flags); + + lsm = ccc_inode_lsm_get(inode); + if (lsm == NULL) + RETURN(0); + OBDO_ALLOC(oinfo.oi_oa); + if (!oinfo.oi_oa) { + ccc_inode_lsm_put(inode, lsm); + RETURN(-ENOMEM); + } + oinfo.oi_md = lsm; oinfo.oi_oa->o_id = lsm->lsm_object_id; oinfo.oi_oa->o_seq = lsm->lsm_object_seq; oinfo.oi_oa->o_flags = flags; oinfo.oi_oa->o_valid = OBD_MD_FLID | OBD_MD_FLFLAGS | OBD_MD_FLGROUP; oinfo.oi_capa = ll_mdscapa_get(inode); - obdo_from_inode(oinfo.oi_oa, inode, - &ll_i2info(inode)->lli_fid, 0); + obdo_set_parent_fid(oinfo.oi_oa, &ll_i2info(inode)->lli_fid); rc = obd_setattr_rqset(sbi->ll_dt_exp, &oinfo, NULL); capa_put(oinfo.oi_capa); OBDO_FREE(oinfo.oi_oa); - if (rc) { - if (rc != -EPERM && rc != -EACCES) - CERROR("osc_setattr_async fails: rc = %d\n",rc); - RETURN(rc); - } + ccc_inode_lsm_put(inode, lsm); - EXIT; -update_cache: - inode->i_flags = ll_ext_to_inode_flags(flags); - return 0; + if (rc && rc != -EPERM && rc != -EACCES) + CERROR("osc_setattr_async fails: rc = %d\n", rc); + + RETURN(rc); } default: RETURN(-ENOSYS); @@ -1796,10 +2008,10 @@ int ll_flush_ctx(struct inode *inode) CDEBUG(D_SEC, "flush context for user %d\n", cfs_curproc_uid()); - obd_set_info_async(sbi->ll_md_exp, + obd_set_info_async(NULL, sbi->ll_md_exp, sizeof(KEY_FLUSH_CTX), KEY_FLUSH_CTX, 0, NULL, NULL); - obd_set_info_async(sbi->ll_dt_exp, + obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_FLUSH_CTX), KEY_FLUSH_CTX, 0, NULL, NULL); return 0; @@ -1814,7 +2026,6 @@ void ll_umount_begin(struct vfsmount *vfsmnt, int flags) void ll_umount_begin(struct super_block *sb) { #endif - struct lustre_sb_info *lsi = s2lsi(sb); struct ll_sb_info *sbi = ll_s2sbi(sb); struct obd_device *obd; struct obd_ioctl_data *ioc_data; @@ -1827,9 +2038,6 @@ void ll_umount_begin(struct super_block *sb) } #endif - /* Tell the MGC we got umount -f */ - lsi->lsi_flags |= LSI_UMOUNT_FORCE; - CDEBUG(D_VFSTRACE, "VFS Op: superblock %p count %d active %d\n", sb, sb->s_count, atomic_read(&sb->s_active)); @@ -1885,18 +2093,20 @@ void ll_umount_begin(struct super_block *sb) 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(sbi->ll_md_exp, + 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) { - CERROR("Failed to change the read-only flag during " - "remount: %d\n", err); + LCONSOLE_WARN("Failed to remount %s %s (%d)\n", + profilenm, read_only ? + "read-only" : "read-write", err); return err; } @@ -1904,6 +2114,10 @@ int ll_remount_fs(struct super_block *sb, int *flags, char *data) sb->s_flags |= MS_RDONLY; else sb->s_flags &= ~MS_RDONLY; + + if (sbi->ll_flags & LL_SBI_VERBOSE) + LCONSOLE_WARN("Remounted %s %s\n", profilenm, + read_only ? "read-only" : "read-write"); } return 0; } @@ -1912,15 +2126,14 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, struct super_block *sb) { - struct ll_sb_info *sbi = NULL; - struct lustre_md md; + struct ll_sb_info *sbi = NULL; + struct lustre_md md; + __u64 ibits; int rc; ENTRY; LASSERT(*inode || sb); sbi = sb ? ll_s2sbi(sb) : ll_i2sbi(*inode); - memset(&md, 0, sizeof(struct lustre_md)); - rc = md_get_lustre_md(sbi->ll_md_exp, req, sbi->ll_dt_exp, sbi->ll_md_exp, &md); if (rc) @@ -1937,7 +2150,7 @@ int ll_prep_inode(struct inode **inode, */ LASSERT(fid_is_sane(&md.body->fid1)); - *inode = ll_iget(sb, cl_fid_build_ino(&md.body->fid1), &md); + *inode = ll_iget(sb, cl_fid_build_ino(&md.body->fid1, 0), &md); if (*inode == NULL || IS_ERR(*inode)) { if (md.lsm) obd_free_memmd(sbi->ll_dt_exp, &md.lsm); @@ -1954,9 +2167,18 @@ int ll_prep_inode(struct inode **inode, } } + /* sanity check for LAYOUT lock. */ + ibits = MDS_INODELOCK_LAYOUT; + if (S_ISREG(md.body->mode) && sbi->ll_flags & LL_SBI_LAYOUT_LOCK && + md.lsm != NULL && !ll_have_md_lock(*inode, &ibits, LCK_MINMODE)) { + CERROR("%s: inode "DFID" (%p) layout lock not granted.\n", + ll_get_fsname(sb, NULL, 0), + PFID(ll_inode2fid(*inode)), *inode); + } + out: - md_free_lustre_md(sbi->ll_md_exp, &md); - RETURN(rc); + md_free_lustre_md(sbi->ll_md_exp, &md); + RETURN(rc); } int ll_obd_statfs(struct inode *inode, void *arg) @@ -1966,6 +2188,7 @@ int ll_obd_statfs(struct inode *inode, void *arg) char *buf = NULL; struct obd_ioctl_data *data = NULL; __u32 type; + __u32 flags; int len = 0, rc; if (!inode || !(sbi = ll_i2sbi(inode))) @@ -1987,14 +2210,15 @@ int ll_obd_statfs(struct inode *inode, void *arg) GOTO(out_statfs, rc = -EINVAL); memcpy(&type, data->ioc_inlbuf1, sizeof(__u32)); - if (type == LL_STATFS_MDC) + if (type & LL_STATFS_LMV) exp = sbi->ll_md_exp; - else if (type == LL_STATFS_LOV) + else if (type & LL_STATFS_LOV) exp = sbi->ll_dt_exp; else GOTO(out_statfs, rc = -ENODEV); - rc = obd_iocontrol(IOC_OBD_STATFS, exp, len, buf, NULL); + flags = (type & LL_STATFS_NODELAY) ? OBD_STATFS_NODELAY : 0; + rc = obd_iocontrol(IOC_OBD_STATFS, exp, len, buf, &flags); if (rc) GOTO(out_statfs, rc); out_statfs: @@ -2073,6 +2297,20 @@ struct md_op_data * ll_prep_md_op_data(struct md_op_data *op_data, op_data->op_mds = 0; op_data->op_data = data; + /* If the file is being opened after mknod() (normally due to NFS) + * try to use the default stripe data from parent directory for + * allocating OST objects. Try to pass the parent FID to MDS. */ + if (opc == LUSTRE_OPC_CREATE && i1 == i2 && S_ISREG(i2->i_mode) && + !ll_i2info(i2)->lli_has_smd) { + struct ll_inode_info *lli = ll_i2info(i2); + + cfs_spin_lock(&lli->lli_lock); + if (likely(!lli->lli_has_smd && !fid_is_zero(&lli->lli_pfid))) + op_data->op_fid1 = lli->lli_pfid; + cfs_spin_unlock(&lli->lli_lock); + /** We ignore parent's capability temporary. */ + } + return op_data; } @@ -2105,5 +2343,112 @@ int ll_show_options(struct seq_file *seq, struct vfsmount *vfs) if (sbi->ll_flags & LL_SBI_LAZYSTATFS) seq_puts(seq, ",lazystatfs"); + if (sbi->ll_flags & LL_SBI_USER_FID2PATH) + seq_puts(seq, ",user_fid2path"); + RETURN(0); } + +/** + * Get obd name by cmd, and copy out to user space + */ +int ll_get_obd_name(struct inode *inode, unsigned int cmd, unsigned long arg) +{ + struct ll_sb_info *sbi = ll_i2sbi(inode); + struct obd_device *obd; + ENTRY; + + if (cmd == OBD_IOC_GETDTNAME) + obd = class_exp2obd(sbi->ll_dt_exp); + else if (cmd == OBD_IOC_GETMDNAME) + obd = class_exp2obd(sbi->ll_md_exp); + else + RETURN(-EINVAL); + + if (!obd) + RETURN(-ENOENT); + + if (cfs_copy_to_user((void *)arg, obd->obd_name, + strlen(obd->obd_name) + 1)) + RETURN(-EFAULT); + + 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; + +#ifdef HAVE_FS_STRUCT_USE_PATH + struct path p; + + p.dentry = dentry; + p.mnt = current->fs->root.mnt; + path_get(&p); + path = d_path(&p, buf, bufsize); + path_put(&p); +#else + path = d_path(dentry, current->fs->rootmnt, buf, bufsize); +#endif + + return path; +} + +void ll_dirty_page_discard_warn(cfs_page_t *page, int ioret) +{ + char *buf, *path = NULL; + struct dentry *dentry = NULL; + struct ccc_object *obj = cl_inode2ccc(page->mapping->host); + + buf = (char *)__get_free_page(GFP_KERNEL); + if (buf != NULL) { + dentry = d_find_alias(page->mapping->host); + if (dentry != NULL) + path = ll_d_path(dentry, buf, PAGE_SIZE); + } + + CWARN("%s: dirty page discard: %s/fid: "DFID"/%s may get corrupted " + "(rc %d)\n", ll_get_fsname(page->mapping->host->i_sb, NULL, 0), + s2lsi(page->mapping->host->i_sb)->lsi_lmd->lmd_dev, + PFID(&obj->cob_header.coh_lu.loh_fid), + (path && !IS_ERR(path)) ? path : "", ioret); + + if (dentry != NULL) + dput(dentry); + + if (buf != NULL) + free_page((unsigned long)buf); +}