#define DEBUG_SUBSYSTEM S_LLITE
#include <linux/module.h>
+#include <linux/random.h>
#include <linux/statfs.h>
#include <linux/time.h>
#include <linux/types.h>
+#include <libcfs/linux/linux-uuid.h>
#include <linux/version.h>
#include <linux/mm.h>
#include <linux/user_namespace.h>
#include <linux/security.h>
#include <uapi/linux/lustre/lustre_ioctl.h>
+#ifdef HAVE_UAPI_LINUX_MOUNT_H
+#include <uapi/linux/mount.h>
+#endif
+
#include <lustre_ha.h>
#include <lustre_dlm.h>
#include <lprocfs_status.h>
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->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;
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)
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)
{
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);
}
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_DIR_MIGRATE |
- OBD_CONNECT2_SUM_STATFS;
+ OBD_CONNECT2_ARCHIVE_ID_ARRAY |
+ OBD_CONNECT2_LSOM |
+ OBD_CONNECT2_ASYNC_DISCARD |
+ OBD_CONNECT2_PCC;
#ifdef HAVE_LRU_RESIZE_SUPPORT
if (sbi->ll_flags & LL_SBI_LRU_RESIZE)
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;
* 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);
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;
}
}
- 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);
}
/* 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))
"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 "
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,
(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);
}
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;
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;
}
}
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);
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);
}
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);
/* 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));
+ schedule_timeout(cfs_time_seconds(1 >> 3));
}
}
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_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;
}
mutex_init(&lli->lli_layout_mutex);
memset(lli->lli_jobid, 0, sizeof(lli->lli_jobid));
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;
+ const int instlen = 16 + 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;
ENTRY;
- CDEBUG(D_VFSTRACE, "VFS Op: sb %p\n", sb);
+ /* 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);
try_module_get(THIS_MODULE);
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);
if (err)
- GOTO(out_free, err);
-
- err = super_setup_bdi_name(sb, "lustre-%p", sb);
- if (err)
- GOTO(out_free, err);
+ GOTO(out_free_cfg, 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
+ /* 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(lsi->lsi_lmd->lmd_profile);
- ptr = strrchr(lsi->lsi_lmd->lmd_profile, '-');
+ 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, MAX_STRING_SIZE, "%.*s-%p", len,
- lsi->lsi_lmd->lmd_profile, sb);
+ 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",
- ll_get_fsname(sb, NULL, 0), err);
+ 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);
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);
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);
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)
- ll_debugfs_unregister_super(sb);
-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)
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) {
if (force == 0 && rc != -EINTR)
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) {
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,
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));
}
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
{
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
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 void ll_update_default_lsm_md(struct inode *inode, struct lustre_md *md)
+{
+ 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;
+ 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)));
+ /* 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);
- /* Compare the old and new stripe information */
+ /*
+ * normally dir layout doesn't change, only take read lock to check
+ * that to avoid blocking other MD operations.
+ */
+ if (lli->lli_lsm_md)
+ down_read(&lli->lli_lsm_sem);
+ else
+ down_write(&lli->lli_lsm_sem);
+
+ /*
+ * if dir layout mismatch, check whether version is increased, which
+ * means layout is changed, this happens in dir migration and lfsck.
+ *
+ * foreign LMV should not change.
+ */
if (lli->lli_lsm_md && !lsm_md_eq(lli->lli_lsm_md, lsm)) {
- struct lmv_stripe_md *old_lsm = lli->lli_lsm_md;
- int idx;
- bool layout_changed = lsm->lsm_md_layout_version >
- old_lsm->lsm_md_layout_version;
-
- int mask = layout_changed ? D_INODE : D_ERROR;
-
- CDEBUG(mask,
- "%s: inode@%p "DFID" lmv layout %s magic %#x/%#x "
- "stripe count %d/%d master_mdt %d/%d "
- "hash_type %#x/%#x version %d/%d migrate offset %d/%d "
- "migrate hash %#x/%#x pool %s/%s\n",
- ll_get_fsname(inode->i_sb, NULL, 0), inode,
- PFID(&lli->lli_fid),
- layout_changed ? "changed" : "mismatch",
- 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_migrate_offset,
- old_lsm->lsm_md_migrate_offset,
- lsm->lsm_md_migrate_hash,
- old_lsm->lsm_md_migrate_hash,
- lsm->lsm_md_pool_name,
- old_lsm->lsm_md_pool_name);
-
- for (idx = 0; idx < old_lsm->lsm_md_stripe_count; idx++)
- CDEBUG(mask, "old stripe[%d] "DFID"\n",
- idx, PFID(&old_lsm->lsm_md_oinfo[idx].lmo_fid));
-
- for (idx = 0; idx < lsm->lsm_md_stripe_count; idx++)
- CDEBUG(mask, "new stripe[%d] "DFID"\n",
- idx, PFID(&lsm->lsm_md_oinfo[idx].lmo_fid));
-
- if (!layout_changed)
- RETURN(-EINVAL);
+ if (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);
+ }
+ /* layout changed, switch to write lock */
+ up_read(&lli->lli_lsm_sem);
+ down_write(&lli->lli_lsm_sem);
ll_dir_clear_lsm_md(inode);
}
- /* set the directory layout */
+ /* set directory layout */
if (!lli->lli_lsm_md) {
struct cl_attr *attr;
rc = ll_init_lsm_md(inode, md);
+ up_write(&lli->lli_lsm_sem);
if (rc != 0)
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;
+
+ /*
+ * md_merge_attr() may take long, since lsm is already set,
+ * switch to read lock.
+ */
+ down_read(&lli->lli_lsm_sem);
+
+ if (!lmv_dir_striped(lli->lli_lsm_md))
+ GOTO(unlock, rc);
OBD_ALLOC_PTR(attr);
if (attr == NULL)
- RETURN(-ENOMEM);
+ GOTO(unlock, rc = -ENOMEM);
/* 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);
+ GOTO(unlock, rc);
}
if (md->body->mbo_valid & OBD_MD_FLNLINK)
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));
- }
-
- RETURN(-EIO);
}
+unlock:
+ up_read(&lli->lli_lsm_sem);
- 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));
#ifdef CONFIG_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;
}
struct ll_inode_info *lli = ll_i2info(inode);
struct md_op_data *op_data = NULL;
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);
}
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)
if (attr->ia_valid & (ATTR_SIZE | ATTR_ATIME | ATTR_ATIME_SET |
ATTR_MTIME | ATTR_MTIME_SET | ATTR_CTIME) ||
xvalid & OP_XVALID_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, xvalid, 0);
+ 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.
int ll_statfs_internal(struct ll_sb_info *sbi, struct obd_statfs *osfs,
u32 flags)
{
- 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);
- }
+ 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 (osfs->os_state & OS_STATE_SUM)
GOTO(out, rc);
- if (sbi->ll_flags & LL_SBI_LAZYSTATFS)
- flags |= OBD_STATFS_NODELAY;
+ if (sbi->ll_flags & LL_SBI_LAZYSTATFS)
+ flags |= OBD_STATFS_NODELAY;
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;
+ }
out:
- RETURN(rc);
+ RETURN(rc);
}
int ll_statfs(struct dentry *de, struct kstatfs *sfs)
{
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);
+ ll_stats_ops_tally(ll_s2sbi(sb), LPROC_LL_STATFS, 1);
/* Some amount of caching on the client is allowed */
rc = ll_statfs_internal(ll_s2sbi(sb), &osfs, OBD_STATFS_SUM);
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;
}
/* 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);
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;
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, "
+ /* 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_irq(&mapping->i_pages);
+ nrpages = mapping->nrpages;
+ xa_unlock_irq(&mapping->i_pages);
+ } /* Workaround end */
+
+ LASSERTF(nrpages == 0, "%s: inode="DFID"(%p) nrpages=%lu, "
"see https://jira.whamcloud.com/browse/LU-118\n",
- PFID(ll_inode2fid(inode)), inode, inode->i_data.nrpages);
+ ll_i2sbi(inode)->ll_fsname,
+ PFID(ll_inode2fid(inode)), inode, nrpages);
#ifdef HAVE_SBOPS_EVICT_INODE
ll_clear_inode(inode);
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);
+ 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))
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;
}
/**
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;
}
{
struct ll_sb_info *sbi = NULL;
struct lustre_md md = { NULL };
+ bool default_lmv_deleted = false;
int rc;
+
ENTRY;
LASSERT(*inode || sb);
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);
*/
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);
}
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)
ll_open_cleanup(sb != NULL ? sb : (*inode)->i_sb, req);
return rc;
}
+/*
+ * 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)
+{
+ if (op_data->op_mea2_sem) {
+ up_read(op_data->op_mea2_sem);
+ op_data->op_mea2_sem = NULL;
+ }
+
+ 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);
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);
}
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);
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;
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);
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 {
else
sbi->ll_flags &= ~LL_SBI_NOROOTSQUASH;
}
- up_write(&squash->rsi_sem);
+ spin_unlock(&squash->rsi_lock);
}
/**