static int seq_client_proc_write_width(struct file *file, const char *buffer, unsigned long count, void *data) { struct lu_client_seq *seq = (struct lu_client_seq *)data; int rc, val; ENTRY; LASSERT(seq != NULL); cfs_down(&seq->lcs_sem); rc = lprocfs_write_helper(buffer, count, &val); if (rc) { cfs_up(&seq->lcs_sem); RETURN(rc); } if (val <= LUSTRE_SEQ_MAX_WIDTH && val > 0) { seq->lcs_width = val; if (rc == 0) { CDEBUG(D_INFO, "%s: Sequence size: "LPU64"\n", seq->lcs_name, seq->lcs_width); } } cfs_up(&seq->lcs_sem); RETURN(count); }
static int seq_server_proc_write_width(struct file *file, const char *buffer, unsigned long count, void *data) { struct lu_server_seq *seq = (struct lu_server_seq *)data; int rc, val; ENTRY; LASSERT(seq != NULL); cfs_down(&seq->lss_sem); rc = lprocfs_write_helper(buffer, count, &val); if (rc) RETURN(rc); seq->lss_width = val; if (rc == 0) { CDEBUG(D_INFO, "%s: Width: "LPU64"\n", seq->lss_name, seq->lss_width); } cfs_up(&seq->lss_sem); RETURN(count); }
static int target_quotacheck_thread(void *data) { struct quotacheck_thread_args *qta = data; struct obd_export *exp; struct obd_device *obd; struct obd_quotactl *oqctl; struct lvfs_run_ctxt saved; int rc; cfs_daemonize_ctxt("quotacheck"); exp = qta->qta_exp; obd = qta->qta_obd; oqctl = &qta->qta_oqctl; push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); rc = fsfilt_quotacheck(obd, qta->qta_sb, oqctl); if (rc) CERROR("%s: fsfilt_quotacheck: %d\n", obd->obd_name, rc); pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); rc = target_quotacheck_callback(exp, oqctl); class_export_put(exp); cfs_up(qta->qta_sem); OBD_FREE_PTR(qta); return rc; }
int osd_compat_seq_init(struct osd_device *osd, int seq) { struct osd_compat_objid_seq *grp; struct osd_compat_objid *map; struct dentry *d; int rc = 0; char name[32]; int i; ENTRY; map = osd->od_ost_map; LASSERT(map); LASSERT(map->root); grp = &map->groups[seq]; if (grp->groot != NULL) RETURN(0); cfs_down(&grp->dir_init_sem); sprintf(name, "%d", seq); d = simple_mkdir(map->root, osd->od_mnt, name, 0755, 1); if (IS_ERR(d)) { rc = PTR_ERR(d); GOTO(out, rc); } else if (d->d_inode == NULL) { rc = -EFAULT; dput(d); GOTO(out, rc); } LASSERT(grp->dirs == NULL); OBD_ALLOC(grp->dirs, sizeof(d) * map->subdir_count); if (grp->dirs == NULL) { dput(d); GOTO(out, rc = -ENOMEM); } grp->groot = d; for (i = 0; i < map->subdir_count; i++) { sprintf(name, "d%d", i); d = simple_mkdir(grp->groot, osd->od_mnt, name, 0755, 1); if (IS_ERR(d)) { rc = PTR_ERR(d); break; } else if (d->d_inode == NULL) { rc = -EFAULT; dput(d); break; } grp->dirs[i] = d; } if (rc) osd_compat_seq_fini(osd, seq); out: cfs_up(&grp->dir_init_sem); RETURN(rc); }
void lc_watchdog_delete(struct lc_watchdog *lcw) { int dead; ENTRY; LASSERT(lcw != NULL); cfs_timer_disarm(&lcw->lcw_timer); lcw_update_time(lcw, "stopped"); cfs_spin_lock_bh(&lcw->lcw_lock); cfs_spin_lock_bh(&lcw_pending_timers_lock); if (unlikely(!cfs_list_empty(&lcw->lcw_list))) { cfs_list_del_init(&lcw->lcw_list); lcw->lcw_refcount--; /* -1 ref for pending list */ } lcw->lcw_refcount--; /* -1 ref for owner */ dead = lcw->lcw_refcount == 0; cfs_spin_unlock_bh(&lcw_pending_timers_lock); cfs_spin_unlock_bh(&lcw->lcw_lock); if (dead) LIBCFS_FREE(lcw, sizeof(*lcw)); cfs_down(&lcw_refcount_sem); if (--lcw_refcount == 0) lcw_dispatch_stop(); cfs_up(&lcw_refcount_sem); EXIT; }
void mdt_cleanup_idmap(struct mdt_export_data *med) { cfs_down(&med->med_idmap_sem); if (med->med_idmap != NULL) { lustre_idmap_fini(med->med_idmap); med->med_idmap = NULL; } cfs_up(&med->med_idmap_sem); }
static int enc_pools_add_pages(int npages) { static CFS_DECLARE_MUTEX(sem_add_pages); cfs_page_t ***pools; int npools, alloced = 0; int i, j, rc = -ENOMEM; if (npages < PTLRPC_MAX_BRW_PAGES) npages = PTLRPC_MAX_BRW_PAGES; cfs_down(&sem_add_pages); if (npages + page_pools.epp_total_pages > page_pools.epp_max_pages) npages = page_pools.epp_max_pages - page_pools.epp_total_pages; LASSERT(npages > 0); page_pools.epp_st_grows++; npools = npages_to_npools(npages); OBD_ALLOC(pools, npools * sizeof(*pools)); if (pools == NULL) goto out; for (i = 0; i < npools; i++) { OBD_ALLOC(pools[i], CFS_PAGE_SIZE); if (pools[i] == NULL) goto out_pools; for (j = 0; j < PAGES_PER_POOL && alloced < npages; j++) { pools[i][j] = cfs_alloc_page(CFS_ALLOC_IO | CFS_ALLOC_HIGH); if (pools[i][j] == NULL) goto out_pools; alloced++; } } LASSERT(alloced == npages); enc_pools_insert(pools, npools, npages); CDEBUG(D_SEC, "added %d pages into pools\n", npages); rc = 0; out_pools: enc_pools_cleanup(pools, npools); OBD_FREE(pools, npools * sizeof(*pools)); out: if (rc) { page_pools.epp_st_grow_fails++; CERROR("Failed to allocate %d enc pages\n", npages); } cfs_up(&sem_add_pages); return rc; }
/* * generic_quota_on is very lazy and tolerant about current quota settings * @global means to turn on quotas on each OST additionally to local quotas; * should not be called from filter_quota_ctl on MDS nodes (as it starts * admin quotas on MDS nodes). */ int generic_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl, int global) { struct obd_device_target *obt = &obd->u.obt; struct lvfs_run_ctxt saved; int id, is_master, rc = 0, local; /* means we need a local quotaon */ cfs_down(&obt->obt_quotachecking); push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); id = UGQUOTA2LQC(oqctl->qc_type); local = (obt->obt_qctxt.lqc_flags & id) != id; oqctl->qc_cmd = Q_QUOTAON; oqctl->qc_id = obt->obt_qfmt; is_master = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME); if (is_master) { cfs_down_write(&obd->u.mds.mds_qonoff_sem); if (local) { /* turn on cluster wide quota */ rc = mds_admin_quota_on(obd, oqctl); if (rc && rc != -ENOENT) CERROR("%s: %s admin quotaon failed. rc=%d\n", obd->obd_name, global ? "global":"local", rc); } } if (rc == 0) { if (local) { rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl); if (rc) { if (rc != -ENOENT) CERROR("%s: %s quotaon failed with" " rc=%d\n", obd->obd_name, global ? "global" : "local", rc); } else { obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(oqctl->qc_type); build_lqs(obd); } } if (rc == 0 && global && is_master) rc = obd_quotactl(obd->u.mds.mds_lov_exp, oqctl); } if (is_master) cfs_up_write(&obd->u.mds.mds_qonoff_sem); pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); cfs_up(&obt->obt_quotachecking); return rc; }
static int seq_client_proc_read_fid(char *page, char **start, off_t off, int count, int *eof, void *data) { struct lu_client_seq *seq = (struct lu_client_seq *)data; int rc; ENTRY; LASSERT(seq != NULL); cfs_down(&seq->lcs_sem); rc = snprintf(page, count, DFID"\n", PFID(&seq->lcs_fid)); cfs_up(&seq->lcs_sem); RETURN(rc); }
static int seq_server_proc_read_width(char *page, char **start, off_t off, int count, int *eof, void *data) { struct lu_server_seq *seq = (struct lu_server_seq *)data; int rc; ENTRY; LASSERT(seq != NULL); cfs_down(&seq->lss_sem); rc = snprintf(page, count, LPU64"\n", seq->lss_width); cfs_up(&seq->lss_sem); RETURN(rc); }
static int seq_client_proc_read_space(char *page, char **start, off_t off, int count, int *eof, void *data) { struct lu_client_seq *seq = (struct lu_client_seq *)data; int rc; ENTRY; LASSERT(seq != NULL); cfs_down(&seq->lcs_sem); rc = seq_proc_read_common(page, start, off, count, eof, data, &seq->lcs_space); cfs_up(&seq->lcs_sem); RETURN(rc); }
/* * Server side procfs stuff. */ static int seq_server_proc_write_space(struct file *file, const char *buffer, unsigned long count, void *data) { struct lu_server_seq *seq = (struct lu_server_seq *)data; int rc; ENTRY; LASSERT(seq != NULL); cfs_down(&seq->lss_sem); rc = seq_proc_write_common(file, buffer, count, data, &seq->lss_space); if (rc == 0) { CDEBUG(D_INFO, "%s: Space: "DRANGE"\n", seq->lss_name, PRANGE(&seq->lss_space)); } cfs_up(&seq->lss_sem); RETURN(count); }
int mdt_init_idmap(struct mdt_thread_info *info) { struct ptlrpc_request *req = mdt_info_req(info); struct mdt_export_data *med = mdt_req2med(req); struct obd_export *exp = req->rq_export; char *client = libcfs_nid2str(req->rq_peer.nid); struct obd_device *obd = exp->exp_obd; int rc = 0; ENTRY; if (exp_connect_rmtclient(exp)) { cfs_down(&med->med_idmap_sem); if (!med->med_idmap) med->med_idmap = lustre_idmap_init(); cfs_up(&med->med_idmap_sem); if (IS_ERR(med->med_idmap)) { long err = PTR_ERR(med->med_idmap); med->med_idmap = NULL; CERROR("client %s -> target %s " "failed to init idmap [%ld]!\n", client, obd->obd_name, err); RETURN(err); } else if (!med->med_idmap) { CERROR("client %s -> target %s " "failed to init(2) idmap!\n", client, obd->obd_name); RETURN(-ENOMEM); } CDEBUG(D_SEC, "client %s -> target %s is remote.\n", client, obd->obd_name); /* NB, MDS_CONNECT establish root idmap too! */ rc = mdt_handle_idmap(info); } RETURN(rc); }
struct lc_watchdog *lc_watchdog_add(int timeout, void (*callback)(pid_t, void *), void *data) { struct lc_watchdog *lcw = NULL; ENTRY; LIBCFS_ALLOC(lcw, sizeof(*lcw)); if (lcw == NULL) { CDEBUG(D_INFO, "Could not allocate new lc_watchdog\n"); RETURN(ERR_PTR(-ENOMEM)); } cfs_spin_lock_init(&lcw->lcw_lock); lcw->lcw_refcount = 1; /* refcount for owner */ lcw->lcw_task = cfs_current(); lcw->lcw_pid = cfs_curproc_pid(); lcw->lcw_callback = (callback != NULL) ? callback : lc_watchdog_dumplog; lcw->lcw_data = data; lcw->lcw_state = LC_WATCHDOG_DISABLED; CFS_INIT_LIST_HEAD(&lcw->lcw_list); cfs_timer_init(&lcw->lcw_timer, lcw_cb, lcw); cfs_down(&lcw_refcount_sem); if (++lcw_refcount == 1) lcw_dispatch_start(); cfs_up(&lcw_refcount_sem); /* Keep this working in case we enable them by default */ if (lcw->lcw_state == LC_WATCHDOG_ENABLED) { lcw->lcw_last_touched = cfs_time_current(); cfs_timer_arm(&lcw->lcw_timer, cfs_time_seconds(timeout) + cfs_time_current()); } RETURN(lcw); }
int target_quota_check(struct obd_device *obd, struct obd_export *exp, struct obd_quotactl *oqctl) { struct obd_device_target *obt = &obd->u.obt; struct quotacheck_thread_args *qta; int rc = 0; ENTRY; OBD_ALLOC_PTR(qta); if (!qta) RETURN(ENOMEM); cfs_down(&obt->obt_quotachecking); qta->qta_exp = exp; qta->qta_obd = obd; qta->qta_oqctl = *oqctl; qta->qta_oqctl.qc_id = obt->obt_qfmt; /* override qfmt version */ qta->qta_sb = obt->obt_sb; qta->qta_sem = &obt->obt_quotachecking; /* quotaoff firstly */ oqctl->qc_cmd = Q_QUOTAOFF; if (!strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME)) { rc = do_mds_quota_off(obd, oqctl); if (rc && rc != -EALREADY) { CERROR("off quota on MDS failed: %d\n", rc); GOTO(out, rc); } /* quota master */ rc = init_admin_quotafiles(obd, &qta->qta_oqctl); if (rc) { CERROR("init_admin_quotafiles failed: %d\n", rc); GOTO(out, rc); } } else { struct lvfs_run_ctxt saved; struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt; push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl); pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); if (!rc) { qctxt->lqc_flags &= ~UGQUOTA2LQC(oqctl->qc_type); } else if (!quota_is_off(qctxt, oqctl)) { CERROR("off quota on OSS failed: %d\n", rc); GOTO(out, rc); } } /* we get ref for exp because target_quotacheck_callback() will use this * export later b=18126 */ class_export_get(exp); rc = cfs_kernel_thread(target_quotacheck_thread, qta, CLONE_VM|CLONE_FILES); if (rc >= 0) { /* target_quotacheck_thread will drop the ref on exp and release * obt_quotachecking */ CDEBUG(D_INFO, "%s: target_quotacheck_thread: %d\n", obd->obd_name, rc); RETURN(0); } else { CERROR("%s: error starting quotacheck_thread: %d\n", obd->obd_name, rc); class_export_put(exp); EXIT; } out: cfs_up(&obt->obt_quotachecking); OBD_FREE_PTR(qta); return rc; }
int filter_quota_ctl(struct obd_device *unused, struct obd_export *exp, struct obd_quotactl *oqctl) { struct obd_device *obd = exp->exp_obd; struct obd_device_target *obt = &obd->u.obt; struct lvfs_run_ctxt saved; struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt; struct lustre_qunit_size *lqs; void *handle = NULL; struct timeval work_start; struct timeval work_end; long timediff; int rc = 0; ENTRY; cfs_gettimeofday(&work_start); switch (oqctl->qc_cmd) { case Q_QUOTAON: oqctl->qc_id = obt->obt_qfmt; rc = generic_quota_on(obd, oqctl, 0); break; case Q_FINVALIDATE: case Q_QUOTAOFF: cfs_down(&obt->obt_quotachecking); if (oqctl->qc_cmd == Q_FINVALIDATE && (obt->obt_qctxt.lqc_flags & UGQUOTA2LQC(oqctl->qc_type))) { CWARN("quota[%u] is on yet\n", oqctl->qc_type); cfs_up(&obt->obt_quotachecking); rc = -EBUSY; break; } oqctl->qc_id = obt->obt_qfmt; /* override qfmt version */ case Q_GETOINFO: case Q_GETOQUOTA: case Q_GETQUOTA: /* In recovery scenario, this pending dqacq/dqrel might have * been processed by master successfully before it's dquot * on master enter recovery mode. We must wait for this * dqacq/dqrel done then return the correct limits to master */ if (oqctl->qc_stat == QUOTA_RECOVERING) handle = quota_barrier(&obd->u.obt.obt_qctxt, oqctl, 1); push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl); pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); if (oqctl->qc_stat == QUOTA_RECOVERING) quota_unbarrier(handle); if (oqctl->qc_cmd == Q_QUOTAOFF || oqctl->qc_cmd == Q_FINVALIDATE) { if (oqctl->qc_cmd == Q_QUOTAOFF) { if (!rc) obt->obt_qctxt.lqc_flags &= ~UGQUOTA2LQC(oqctl->qc_type); else if (quota_is_off(qctxt, oqctl)) rc = -EALREADY; CDEBUG(D_QUOTA, "%s: quotaoff type:flags:rc " "%u:%lu:%d\n", obd->obd_name, oqctl->qc_type, qctxt->lqc_flags, rc); } cfs_up(&obt->obt_quotachecking); } break; case Q_SETQUOTA: /* currently, it is only used for nullifying the quota */ handle = quota_barrier(&obd->u.obt.obt_qctxt, oqctl, 1); push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl); if (!rc) { oqctl->qc_cmd = Q_SYNC; fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl); oqctl->qc_cmd = Q_SETQUOTA; } pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); quota_unbarrier(handle); lqs = quota_search_lqs(LQS_KEY(oqctl->qc_type, oqctl->qc_id), qctxt, 0); if (lqs == NULL || IS_ERR(lqs)){ CERROR("fail to create lqs during setquota operation " "for %sid %u\n", oqctl->qc_type ? "g" : "u", oqctl->qc_id); } else { lqs->lqs_flags &= ~QB_SET; lqs_putref(lqs); } break; case Q_INITQUOTA: { unsigned int id[MAXQUOTAS] = { 0, 0 }; /* Initialize quota limit to MIN_QLIMIT */ LASSERT(oqctl->qc_dqblk.dqb_valid == QIF_BLIMITS); LASSERT(oqctl->qc_dqblk.dqb_bsoftlimit == 0); if (!oqctl->qc_dqblk.dqb_bhardlimit) goto adjust; /* There might be a pending dqacq/dqrel (which is going to * clear stale limits on slave). we should wait for it's * completion then initialize limits */ handle = quota_barrier(&obd->u.obt.obt_qctxt, oqctl, 1); LASSERT(oqctl->qc_dqblk.dqb_bhardlimit == MIN_QLIMIT); push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl); /* Update on-disk quota, in case of lose the changed limits * (MIN_QLIMIT) on crash, which cannot be recovered.*/ if (!rc) { oqctl->qc_cmd = Q_SYNC; fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl); oqctl->qc_cmd = Q_INITQUOTA; } pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); quota_unbarrier(handle); if (rc) RETURN(rc); adjust: lqs = quota_search_lqs(LQS_KEY(oqctl->qc_type, oqctl->qc_id), qctxt, 1); if (lqs == NULL || IS_ERR(lqs)){ CERROR("fail to create lqs during setquota operation " "for %sid %u\n", oqctl->qc_type ? "g" : "u", oqctl->qc_id); break; } else { lqs->lqs_flags |= QB_SET; lqs_putref(lqs); } /* Trigger qunit pre-acquire */ if (oqctl->qc_type == USRQUOTA) id[USRQUOTA] = oqctl->qc_id; else id[GRPQUOTA] = oqctl->qc_id; rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt, id, 1, 0, NULL); if (rc == -EDQUOT || rc == -EBUSY) { CDEBUG(D_QUOTA, "rc: %d.\n", rc); rc = 0; } break; } default: CERROR("%s: unsupported filter_quotactl command: %d\n", obd->obd_name, oqctl->qc_cmd); RETURN(-EFAULT); } cfs_gettimeofday(&work_end); timediff = cfs_timeval_sub(&work_end, &work_start, NULL); lprocfs_counter_add(qctxt->lqc_stats, LQUOTA_QUOTA_CTL, timediff); RETURN(rc); }
int ll_revalidate_it(struct dentry *de, int lookup_flags, struct lookup_intent *it) { struct md_op_data *op_data; struct ptlrpc_request *req = NULL; struct lookup_intent lookup_it = { .it_op = IT_LOOKUP }; struct obd_export *exp; struct inode *parent = de->d_parent->d_inode; int rc, first = 0; ENTRY; CDEBUG(D_VFSTRACE, "VFS Op:name=%s,intent=%s\n", de->d_name.name, LL_IT2STR(it)); if (de->d_inode == NULL) { /* We can only use negative dentries if this is stat or lookup, for opens and stuff we do need to query server. */ /* If there is IT_CREAT in intent op set, then we must throw away this negative dentry and actually do the request to kernel to create whatever needs to be created (if possible)*/ if (it && (it->it_op & IT_CREAT)) RETURN(0); if (de->d_flags & DCACHE_LUSTRE_INVALID) RETURN(0); rc = ll_have_md_lock(parent, MDS_INODELOCK_UPDATE, LCK_MINMODE); GOTO(out_sa, rc); } /* Never execute intents for mount points. * Attributes will be fixed up in ll_inode_revalidate_it */ if (d_mountpoint(de)) GOTO(out_sa, rc = 1); /* need to get attributes in case root got changed from other client */ if (de == de->d_sb->s_root) { rc = __ll_inode_revalidate_it(de, it, MDS_INODELOCK_LOOKUP); if (rc == 0) rc = 1; GOTO(out_sa, rc); } exp = ll_i2mdexp(de->d_inode); OBD_FAIL_TIMEOUT(OBD_FAIL_MDC_REVALIDATE_PAUSE, 5); ll_frob_intent(&it, &lookup_it); LASSERT(it); if (it->it_op == IT_LOOKUP && !(de->d_flags & DCACHE_LUSTRE_INVALID)) GOTO(out_sa, rc = 1); op_data = ll_prep_md_op_data(NULL, parent, de->d_inode, de->d_name.name, de->d_name.len, 0, LUSTRE_OPC_ANY, NULL); if (IS_ERR(op_data)) RETURN(PTR_ERR(op_data)); if ((it->it_op == IT_OPEN) && de->d_inode) { struct inode *inode = de->d_inode; struct ll_inode_info *lli = ll_i2info(inode); struct obd_client_handle **och_p; __u64 *och_usecount; /* * We used to check for MDS_INODELOCK_OPEN here, but in fact * just having LOOKUP lock is enough to justify inode is the * same. And if inode is the same and we have suitable * openhandle, then there is no point in doing another OPEN RPC * just to throw away newly received openhandle. There are no * security implications too, if file owner or access mode is * change, LOOKUP lock is revoked. */ if (it->it_flags & FMODE_WRITE) { och_p = &lli->lli_mds_write_och; och_usecount = &lli->lli_open_fd_write_count; } else if (it->it_flags & FMODE_EXEC) { och_p = &lli->lli_mds_exec_och; och_usecount = &lli->lli_open_fd_exec_count; } else { och_p = &lli->lli_mds_read_och; och_usecount = &lli->lli_open_fd_read_count; } /* Check for the proper lock. */ if (!ll_have_md_lock(inode, MDS_INODELOCK_LOOKUP, LCK_MINMODE)) goto do_lock; cfs_down(&lli->lli_och_sem); if (*och_p) { /* Everything is open already, do nothing */ /*(*och_usecount)++; Do not let them steal our open handle from under us */ /* XXX The code above was my original idea, but in case we have the handle, but we cannot use it due to later checks (e.g. O_CREAT|O_EXCL flags set), nobody would decrement counter increased here. So we just hope the lock won't be invalidated in between. But if it would be, we'll reopen the open request to MDS later during file open path */ cfs_up(&lli->lli_och_sem); ll_finish_md_op_data(op_data); RETURN(1); } else { cfs_up(&lli->lli_och_sem); } } if (it->it_op == IT_GETATTR) { first = ll_statahead_enter(parent, &de, 0); if (first == 1) { ll_statahead_exit(parent, de, 1); ll_finish_md_op_data(op_data); GOTO(out, rc = 1); } } do_lock: it->it_create_mode &= ~current->fs->umask; it->it_create_mode |= M_CHECK_STALE; rc = md_intent_lock(exp, op_data, NULL, 0, it, lookup_flags, &req, ll_md_blocking_ast, 0); it->it_create_mode &= ~M_CHECK_STALE; ll_finish_md_op_data(op_data); if (it->it_op == IT_GETATTR && !first) /* If there are too many locks on client-side, then some * locks taken by statahead maybe dropped automatically * before the real "revalidate" using them. */ ll_statahead_exit(parent, de, req == NULL ? rc : 0); else if (first == -EEXIST) ll_statahead_mark(parent, de); /* If req is NULL, then md_intent_lock only tried to do a lock match; * if all was well, it will return 1 if it found locks, 0 otherwise. */ if (req == NULL && rc >= 0) { if (!rc) goto do_lookup; GOTO(out, rc); } if (rc < 0) { if (rc != -ESTALE) { CDEBUG(D_INFO, "ll_intent_lock: rc %d : it->it_status " "%d\n", rc, it->d.lustre.it_status); } GOTO(out, rc = 0); } revalidate_finish: rc = ll_revalidate_it_finish(req, it, de); if (rc != 0) { if (rc != -ESTALE && rc != -ENOENT) ll_intent_release(it); GOTO(out, rc = 0); } if ((it->it_op & IT_OPEN) && de->d_inode && !S_ISREG(de->d_inode->i_mode) && !S_ISDIR(de->d_inode->i_mode)) { ll_release_openhandle(de, it); } rc = 1; /* unfortunately ll_intent_lock may cause a callback and revoke our * dentry */ cfs_spin_lock(&ll_lookup_lock); spin_lock(&dcache_lock); lock_dentry(de); __d_drop(de); unlock_dentry(de); d_rehash_cond(de, 0); spin_unlock(&dcache_lock); cfs_spin_unlock(&ll_lookup_lock); out: /* We do not free request as it may be reused during following lookup * (see comment in mdc/mdc_locks.c::mdc_intent_lock()), request will * be freed in ll_lookup_it or in ll_intent_release. But if * request was not completed, we need to free it. (bug 5154, 9903) */ if (req != NULL && !it_disposition(it, DISP_ENQ_COMPLETE)) ptlrpc_req_finished(req); if (rc == 0) { ll_unhash_aliases(de->d_inode); /* done in ll_unhash_aliases() dentry->d_flags |= DCACHE_LUSTRE_INVALID; */ } else { CDEBUG(D_DENTRY, "revalidated dentry %.*s (%p) parent %p " "inode %p refc %d\n", de->d_name.len, de->d_name.name, de, de->d_parent, de->d_inode, atomic_read(&de->d_count)); if (first != 1) { if (de->d_flags & DCACHE_LUSTRE_INVALID) { lock_dentry(de); de->d_flags &= ~DCACHE_LUSTRE_INVALID; unlock_dentry(de); } ll_lookup_finish_locks(it, de); } } RETURN(rc); /* * This part is here to combat evil-evil race in real_lookup on 2.6 * kernels. The race details are: We enter do_lookup() looking for some * name, there is nothing in dcache for this name yet and d_lookup() * returns NULL. We proceed to real_lookup(), and while we do this, * another process does open on the same file we looking up (most simple * reproducer), open succeeds and the dentry is added. Now back to * us. In real_lookup() we do d_lookup() again and suddenly find the * dentry, so we call d_revalidate on it, but there is no lock, so * without this code we would return 0, but unpatched real_lookup just * returns -ENOENT in such a case instead of retrying the lookup. Once * this is dealt with in real_lookup(), all of this ugly mess can go and * we can just check locks in ->d_revalidate without doing any RPCs * ever. */ do_lookup: if (it != &lookup_it) { /* MDS_INODELOCK_UPDATE needed for IT_GETATTR case. */ if (it->it_op == IT_GETATTR) lookup_it.it_op = IT_GETATTR; ll_lookup_finish_locks(it, de); it = &lookup_it; } /* Do real lookup here. */ op_data = ll_prep_md_op_data(NULL, parent, NULL, de->d_name.name, de->d_name.len, 0, (it->it_op & IT_CREAT ? LUSTRE_OPC_CREATE : LUSTRE_OPC_ANY), NULL); if (IS_ERR(op_data)) RETURN(PTR_ERR(op_data)); rc = md_intent_lock(exp, op_data, NULL, 0, it, 0, &req, ll_md_blocking_ast, 0); if (rc >= 0) { struct mdt_body *mdt_body; struct lu_fid fid = {.f_seq = 0, .f_oid = 0, .f_ver = 0}; mdt_body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); if (de->d_inode) fid = *ll_inode2fid(de->d_inode); /* see if we got same inode, if not - return error */ if (lu_fid_eq(&fid, &mdt_body->fid1)) { ll_finish_md_op_data(op_data); op_data = NULL; goto revalidate_finish; } ll_intent_release(it); } ll_finish_md_op_data(op_data); GOTO(out, rc = 0); out_sa: /* * For rc == 1 case, should not return directly to prevent losing * statahead windows; for rc == 0 case, the "lookup" will be done later. */ if (it && it->it_op == IT_GETATTR && rc == 1) { first = ll_statahead_enter(parent, &de, 0); if (first >= 0) ll_statahead_exit(parent, de, 1); else if (first == -EEXIST) ll_statahead_mark(parent, de); } return rc; } #if 0 static void ll_pin(struct dentry *de, struct vfsmount *mnt, int flag) { struct inode *inode= de->d_inode; struct ll_sb_info *sbi = ll_i2sbi(inode); struct ll_dentry_data *ldd = ll_d2d(de); struct obd_client_handle *handle; struct obd_capa *oc; int rc = 0; ENTRY; LASSERT(ldd); cfs_lock_kernel(); /* Strictly speaking this introduces an additional race: the * increments should wait until the rpc has returned. * However, given that at present the function is void, this * issue is moot. */ if (flag == 1 && (++ldd->lld_mnt_count) > 1) { cfs_unlock_kernel(); EXIT; return; } if (flag == 0 && (++ldd->lld_cwd_count) > 1) { cfs_unlock_kernel(); EXIT; return; } cfs_unlock_kernel(); handle = (flag) ? &ldd->lld_mnt_och : &ldd->lld_cwd_och; oc = ll_mdscapa_get(inode); rc = obd_pin(sbi->ll_md_exp, ll_inode2fid(inode), oc, handle, flag); capa_put(oc); if (rc) { cfs_lock_kernel(); memset(handle, 0, sizeof(*handle)); if (flag == 0) ldd->lld_cwd_count--; else ldd->lld_mnt_count--; cfs_unlock_kernel(); } EXIT; return; } static void ll_unpin(struct dentry *de, struct vfsmount *mnt, int flag) { struct ll_sb_info *sbi = ll_i2sbi(de->d_inode); struct ll_dentry_data *ldd = ll_d2d(de); struct obd_client_handle handle; int count, rc = 0; ENTRY; LASSERT(ldd); cfs_lock_kernel(); /* Strictly speaking this introduces an additional race: the * increments should wait until the rpc has returned. * However, given that at present the function is void, this * issue is moot. */ handle = (flag) ? ldd->lld_mnt_och : ldd->lld_cwd_och; if (handle.och_magic != OBD_CLIENT_HANDLE_MAGIC) { /* the "pin" failed */ cfs_unlock_kernel(); EXIT; return; } if (flag) count = --ldd->lld_mnt_count; else count = --ldd->lld_cwd_count; cfs_unlock_kernel(); if (count != 0) { EXIT; return; } rc = obd_unpin(sbi->ll_md_exp, &handle, flag); EXIT; return; } #endif #ifdef HAVE_VFS_INTENT_PATCHES int ll_revalidate_nd(struct dentry *dentry, struct nameidata *nd) { int rc; ENTRY; if (nd && nd->flags & LOOKUP_LAST && !(nd->flags & LOOKUP_LINK_NOTLAST)) rc = ll_revalidate_it(dentry, nd->flags, &nd->intent); else rc = ll_revalidate_it(dentry, 0, NULL); RETURN(rc); }