/** * Parses \<numaddr_range\> token of the syntax. * * \retval 1 if \a str parses to \<number\> | \<expr_list\> * \retval 0 otherwise */ static int num_parse(char *str, int len, cfs_list_t *list, unsigned min, unsigned max) { __u32 num; struct lstr src; struct numaddr_range *numaddr; src.ls_str = str; src.ls_len = len; LIBCFS_ALLOC(numaddr, sizeof(struct numaddr_range)); if (numaddr == NULL) return 0; cfs_list_add_tail(&numaddr->nar_link, list); CFS_INIT_LIST_HEAD(&numaddr->nar_range_exprs); if (libcfs_str2num_check(src.ls_str, src.ls_len, &num, min, max)) { /* <number> */ struct range_expr *expr; LIBCFS_ALLOC(expr, sizeof(struct range_expr)); if (expr == NULL) return 0; expr->re_lo = expr->re_hi = num; expr->re_stride = 1; cfs_list_add_tail(&expr->re_link, &numaddr->nar_range_exprs); return 1; } return parse_expr_list(&src, &numaddr->nar_range_exprs, min, max); }
static int lfsck_namespace_post(const struct lu_env *env, struct lfsck_component *com, int result, bool init) { struct lfsck_instance *lfsck = com->lc_lfsck; struct lfsck_namespace *ns = com->lc_file_ram; int rc; down_write(&com->lc_sem); spin_lock(&lfsck->li_lock); if (!init) ns->ln_pos_last_checkpoint = lfsck->li_pos_current; if (result > 0) { ns->ln_status = LS_SCANNING_PHASE2; ns->ln_flags |= LF_SCANNED_ONCE; ns->ln_flags &= ~LF_UPGRADE; cfs_list_del_init(&com->lc_link); cfs_list_del_init(&com->lc_link_dir); cfs_list_add_tail(&com->lc_link, &lfsck->li_list_double_scan); } else if (result == 0) { ns->ln_status = lfsck->li_status; if (ns->ln_status == 0) ns->ln_status = LS_STOPPED; if (ns->ln_status != LS_PAUSED) { cfs_list_del_init(&com->lc_link); cfs_list_del_init(&com->lc_link_dir); cfs_list_add_tail(&com->lc_link, &lfsck->li_list_idle); } } else { ns->ln_status = LS_FAILED; cfs_list_del_init(&com->lc_link); cfs_list_del_init(&com->lc_link_dir); cfs_list_add_tail(&com->lc_link, &lfsck->li_list_idle); } spin_unlock(&lfsck->li_lock); if (!init) { ns->ln_run_time_phase1 += cfs_duration_sec(cfs_time_current() + HALF_SEC - lfsck->li_time_last_checkpoint); ns->ln_time_last_checkpoint = cfs_time_current_sec(); ns->ln_items_checked += com->lc_new_checked; com->lc_new_checked = 0; } rc = lfsck_namespace_store(env, com, false); up_write(&com->lc_sem); return rc; }
/* * Workitem scheduled with (serial == 1) is strictly serialised not only with * itself, but also with others scheduled this way. * * Now there's only one static serialised queue, but in the future more might * be added, and even dynamic creation of serialised queues might be supported. */ void cfs_wi_schedule(cfs_workitem_t *wi) { cfs_wi_sched_t *sched = cfs_wi_to_sched(wi); LASSERT (!cfs_in_interrupt()); /* because we use plain spinlock */ LASSERT (!sched->ws_shuttingdown); cfs_wi_sched_lock(sched); if (!wi->wi_scheduled) { LASSERT (cfs_list_empty(&wi->wi_list)); wi->wi_scheduled = 1; if (!wi->wi_running) { cfs_list_add_tail(&wi->wi_list, &sched->ws_runq); #ifdef __KERNEL__ cfs_waitq_signal(&sched->ws_waitq); #endif } else { cfs_list_add(&wi->wi_list, &sched->ws_rerunq); } } LASSERT (!cfs_list_empty(&wi->wi_list)); cfs_wi_sched_unlock(sched); return; }
/** * Nf_parse_addrlist method for networks using numeric addresses. * * Examples of such networks are gm and elan. * * \retval 0 if \a str parsed to numeric address * \retval errno otherwise */ static int libcfs_num_parse(char *str, int len, cfs_list_t *list) { struct cfs_expr_list *el; int rc; rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el); if (rc == 0) cfs_list_add_tail(&el->el_link, list); return rc; }
int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand) { int rc = 0; down_write(&ioctl_list_sem); if (!cfs_list_empty(&hand->item)) rc = -EBUSY; else cfs_list_add_tail(&hand->item, &ioctl_list); up_write(&ioctl_list_sem); return rc; }
/** * Finds or creates struct nidrange. * * Checks if \a src is a valid network name, looks for corresponding * nidrange on the ist of nidranges (\a nidlist), creates new struct * nidrange if it is not found. * * \retval pointer to struct nidrange matching network specified via \a src * \retval NULL if \a src does not match any network */ static struct nidrange * add_nidrange(const struct lstr *src, cfs_list_t *nidlist) { struct netstrfns *nf; struct nidrange *nr; int endlen; unsigned netnum; if (src->ls_len >= LNET_NIDSTR_SIZE) return NULL; nf = libcfs_namenum2netstrfns(src->ls_str); if (nf == NULL) return NULL; endlen = src->ls_len - strlen(nf->nf_name); if (endlen == 0) /* network name only, e.g. "elan" or "tcp" */ netnum = 0; else { /* e.g. "elan25" or "tcp23", refuse to parse if * network name is not appended with decimal or * hexadecimal number */ if (!libcfs_str2num_check(src->ls_str + strlen(nf->nf_name), endlen, &netnum, 0, MAX_NUMERIC_VALUE)) return NULL; } cfs_list_for_each_entry(nr, nidlist, nr_link) { if (nr->nr_netstrfns != nf) continue; if (nr->nr_netnum != netnum) continue; return nr; } LIBCFS_ALLOC(nr, sizeof(struct nidrange)); if (nr == NULL) return NULL; cfs_list_add_tail(&nr->nr_link, nidlist); CFS_INIT_LIST_HEAD(&nr->nr_addrranges); nr->nr_netstrfns = nf; nr->nr_all = 0; nr->nr_netnum = netnum; return nr; }
/* return a page that has 'len' bytes left at the end */ static struct cfs_trace_page * cfs_trace_get_tage_try(struct cfs_trace_cpu_data *tcd, unsigned long len) { struct cfs_trace_page *tage; if (tcd->tcd_cur_pages > 0) { __LASSERT(!cfs_list_empty(&tcd->tcd_pages)); tage = cfs_tage_from_list(tcd->tcd_pages.prev); if (tage->used + len <= CFS_PAGE_SIZE) return tage; } if (tcd->tcd_cur_pages < tcd->tcd_max_pages) { if (tcd->tcd_cur_stock_pages > 0) { tage = cfs_tage_from_list(tcd->tcd_stock_pages.prev); -- tcd->tcd_cur_stock_pages; cfs_list_del_init(&tage->linkage); } else { tage = cfs_tage_alloc(CFS_ALLOC_ATOMIC); if (tage == NULL) { if (printk_ratelimit()) printk(CFS_KERN_WARNING "cannot allocate a tage (%ld)\n", tcd->tcd_cur_pages); return NULL; } } tage->used = 0; tage->cpu = cfs_smp_processor_id(); tage->type = tcd->tcd_type; cfs_list_add_tail(&tage->linkage, &tcd->tcd_pages); tcd->tcd_cur_pages++; if (tcd->tcd_cur_pages > 8 && thread_running) { struct tracefiled_ctl *tctl = &trace_tctl; /* * wake up tracefiled to process some pages. */ cfs_waitq_signal(&tctl->tctl_waitq); } return tage; } return NULL; }
int cfs_trace_refill_stock(struct cfs_trace_cpu_data *tcd, int gfp, cfs_list_t *stock) { int i; /* * XXX nikita: do NOT call portals_debug_msg() (CDEBUG/ENTRY/EXIT) * from here: this will lead to infinite recursion. */ for (i = 0; i + tcd->tcd_cur_stock_pages < TCD_STOCK_PAGES ; ++ i) { struct cfs_trace_page *tage; tage = cfs_tage_alloc(gfp); if (tage == NULL) break; cfs_list_add_tail(&tage->linkage, stock); } return i; }
/** * Parses \<addrrange\> token on the syntax. * * Allocates struct addrrange and links to \a nidrange via * (nidrange::nr_addrranges) * * \retval 1 if \a src parses to '*' | \<ipaddr_range\> | \<numaddr_range\> * \retval 0 otherwise */ static int parse_addrange(const struct lstr *src, struct nidrange *nidrange) { struct addrrange *addrrange; if (src->ls_len == 1 && src->ls_str[0] == '*') { nidrange->nr_all = 1; return 1; } LIBCFS_ALLOC(addrrange, sizeof(struct addrrange)); if (addrrange == NULL) return 0; cfs_list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges); CFS_INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges); return nidrange->nr_netstrfns->nf_parse_addrlist(src->ls_str, src->ls_len, &addrrange->ar_numaddr_ranges); }
/** Queues DONE_WRITING if * - done writing is allowed; * - inode has no no dirty pages; */ void ll_queue_done_writing(struct inode *inode, unsigned long flags) { struct ll_inode_info *lli = ll_i2info(inode); struct ccc_object *club = cl2ccc(ll_i2info(inode)->lli_clob); ENTRY; spin_lock(&lli->lli_lock); lli->lli_flags |= flags; if ((lli->lli_flags & LLIF_DONE_WRITING) && cfs_list_empty(&club->cob_pending_list)) { struct ll_close_queue *lcq = ll_i2sbi(inode)->ll_lcq; if (lli->lli_flags & LLIF_MDS_SIZE_LOCK) CWARN("ino %lu/%u(flags %u) som valid it just after " "recovery\n", inode->i_ino, inode->i_generation, lli->lli_flags); /* DONE_WRITING is allowed and inode has no dirty page. */ spin_lock(&lcq->lcq_lock); LASSERT(cfs_list_empty(&lli->lli_close_list)); CDEBUG(D_INODE, "adding inode %lu/%u to close list\n", inode->i_ino, inode->i_generation); cfs_list_add_tail(&lli->lli_close_list, &lcq->lcq_head); /* Avoid a concurrent insertion into the close thread queue: * an inode is already in the close thread, open(), write(), * close() happen, epoch is closed as the inode is marked as * LLIF_EPOCH_PENDING. When pages are written inode should not * be inserted into the queue again, clear this flag to avoid * it. */ lli->lli_flags &= ~LLIF_DONE_WRITING; cfs_waitq_signal(&lcq->lcq_waitq); spin_unlock(&lcq->lcq_lock); } spin_unlock(&lli->lli_lock); EXIT; }
/** * Parses \<expr_list\> token of the syntax. * * \retval 1 if \a str parses to '[' \<range_expr\> [ ',' \<range_expr\>] ']' * \retval 0 otherwise */ static int parse_expr_list(struct lstr *str, cfs_list_t *list, unsigned min, unsigned max) { struct lstr res; struct range_expr *range; if (str->ls_str[0] != '[' || str->ls_str[str->ls_len - 1] != ']') return 0; str->ls_str ++; str->ls_len -= 2; while (str->ls_str) { if (gettok(str, ',', &res) == 0) return 0; range = parse_range_expr(&res, min, max); if (range == NULL) return 0; cfs_list_add_tail(&range->re_link, list); } return 1; }
static int l_filldir(void *__buf, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { struct l_linux_dirent *dirent; struct l_readdir_callback *buf = (struct l_readdir_callback *)__buf; dirent = buf->lrc_dirent; if (dirent) dirent->lld_off = offset; OBD_ALLOC(dirent, sizeof(*dirent)); if (!dirent) return -ENOMEM; cfs_list_add_tail(&dirent->lld_list, buf->lrc_list); buf->lrc_dirent = dirent; dirent->lld_ino = ino; LASSERT(sizeof(dirent->lld_name) >= namlen + 1); memcpy(dirent->lld_name, name, namlen); return 0; }
int kptllnd_active_rdma(kptl_rx_t *rx, lnet_msg_t *lntmsg, int type, unsigned int niov, struct iovec *iov, lnet_kiov_t *kiov, unsigned int offset, int nob) { kptl_tx_t *tx; ptl_err_t ptlrc; kptl_msg_t *rxmsg = rx->rx_msg; kptl_peer_t *peer = rx->rx_peer; unsigned long flags; ptl_handle_md_t mdh; LASSERT (type == TX_TYPE_PUT_RESPONSE || type == TX_TYPE_GET_RESPONSE); tx = kptllnd_get_idle_tx(type); if (tx == NULL) { CERROR ("Can't do %s rdma to %s: can't allocate descriptor\n", type == TX_TYPE_PUT_RESPONSE ? "GET" : "PUT", libcfs_id2str(peer->peer_id)); return -ENOMEM; } kptllnd_set_tx_peer(tx, peer); kptllnd_init_rdma_md(tx, niov, iov, kiov, offset, nob); ptlrc = PtlMDBind(kptllnd_data.kptl_nih, tx->tx_rdma_md, PTL_UNLINK, &mdh); if (ptlrc != PTL_OK) { CERROR("PtlMDBind(%s) failed: %s(%d)\n", libcfs_id2str(peer->peer_id), kptllnd_errtype2str(ptlrc), ptlrc); tx->tx_status = -EIO; kptllnd_tx_decref(tx); return -EIO; } cfs_spin_lock_irqsave(&peer->peer_lock, flags); tx->tx_lnet_msg = lntmsg; /* lnet_finalize() will be called when tx is torn down, so I must * return success from here on... */ tx->tx_deadline = jiffies + (*kptllnd_tunables.kptl_timeout * CFS_HZ); tx->tx_rdma_mdh = mdh; tx->tx_active = 1; cfs_list_add_tail(&tx->tx_list, &peer->peer_activeq); /* peer has now got my ref on 'tx' */ cfs_spin_unlock_irqrestore(&peer->peer_lock, flags); tx->tx_tposted = jiffies; if (type == TX_TYPE_GET_RESPONSE) ptlrc = PtlPut(mdh, tx->tx_acked ? PTL_ACK_REQ : PTL_NOACK_REQ, rx->rx_initiator, *kptllnd_tunables.kptl_portal, 0, /* acl cookie */ rxmsg->ptlm_u.rdma.kptlrm_matchbits, 0, /* offset */ (lntmsg != NULL) ? /* header data */ PTLLND_RDMA_OK : PTLLND_RDMA_FAIL); else ptlrc = PtlGet(mdh, rx->rx_initiator, *kptllnd_tunables.kptl_portal, 0, /* acl cookie */ rxmsg->ptlm_u.rdma.kptlrm_matchbits, 0); /* offset */ if (ptlrc != PTL_OK) { CERROR("Ptl%s failed: %s(%d)\n", (type == TX_TYPE_GET_RESPONSE) ? "Put" : "Get", kptllnd_errtype2str(ptlrc), ptlrc); kptllnd_peer_close(peer, -EIO); /* Everything (including this RDMA) queued on the peer will * be completed with failure */ kptllnd_schedule_ptltrace_dump(); } return 0; }
/* All actions that we need after sending hello on passive conn: * 1) Cope with 1st easy case: conn is already linked to a peer * 2) Cope with 2nd easy case: remove zombie conn * 3) Resolve race: * a) find the peer * b) link the conn to the peer if conn[idx] is empty * c) if the conn[idx] isn't empty and is in READY state, * remove the conn as duplicated * d) if the conn[idx] isn't empty and isn't in READY state, * override conn[idx] with the conn */ int usocklnd_passiveconn_hellosent(usock_conn_t *conn) { usock_conn_t *conn2; usock_peer_t *peer; cfs_list_t tx_list; cfs_list_t zcack_list; int idx; int rc = 0; /* almost nothing to do if conn is already linked to peer hash table */ if (conn->uc_peer != NULL) goto passive_hellosent_done; /* conn->uc_peer == NULL, so the conn isn't accessible via * peer hash list, so nobody can touch the conn but us */ if (conn->uc_ni == NULL) /* remove zombie conn */ goto passive_hellosent_connkill; /* all code below is race resolution, because normally * passive conn is linked to peer just after receiving hello */ CFS_INIT_LIST_HEAD (&tx_list); CFS_INIT_LIST_HEAD (&zcack_list); /* conn is passive and isn't linked to any peer, so its tx and zc_ack lists have to be empty */ LASSERT (cfs_list_empty(&conn->uc_tx_list) && cfs_list_empty(&conn->uc_zcack_list) && conn->uc_sending == 0); rc = usocklnd_find_or_create_peer(conn->uc_ni, conn->uc_peerid, &peer); if (rc) return rc; idx = usocklnd_type2idx(conn->uc_type); /* try to link conn to peer */ pthread_mutex_lock(&peer->up_lock); if (peer->up_conns[idx] == NULL) { usocklnd_link_conn_to_peer(conn, peer, idx); usocklnd_conn_addref(conn); conn->uc_peer = peer; usocklnd_peer_addref(peer); } else { conn2 = peer->up_conns[idx]; pthread_mutex_lock(&conn2->uc_lock); if (conn2->uc_state == UC_READY) { /* conn2 is in READY state, so conn is "duplicated" */ pthread_mutex_unlock(&conn2->uc_lock); pthread_mutex_unlock(&peer->up_lock); usocklnd_peer_decref(peer); goto passive_hellosent_connkill; } /* uc_state != UC_READY => switch conn and conn2 */ /* Relink txs and zc_acks from conn2 to conn. * We're sure that nobody but us can access to conn, * nevertheless we use mutex (if we're wrong yet, * deadlock is easy to see that corrupted list */ cfs_list_add(&tx_list, &conn2->uc_tx_list); cfs_list_del_init(&conn2->uc_tx_list); cfs_list_add(&zcack_list, &conn2->uc_zcack_list); cfs_list_del_init(&conn2->uc_zcack_list); pthread_mutex_lock(&conn->uc_lock); cfs_list_add_tail(&conn->uc_tx_list, &tx_list); cfs_list_del_init(&tx_list); cfs_list_add_tail(&conn->uc_zcack_list, &zcack_list); cfs_list_del_init(&zcack_list); conn->uc_peer = peer; pthread_mutex_unlock(&conn->uc_lock); conn2->uc_peer = NULL; /* make conn2 zombie */ pthread_mutex_unlock(&conn2->uc_lock); usocklnd_conn_decref(conn2); usocklnd_link_conn_to_peer(conn, peer, idx); usocklnd_conn_addref(conn); conn->uc_peer = peer; } lnet_ni_decref(conn->uc_ni); conn->uc_ni = NULL; pthread_mutex_unlock(&peer->up_lock); usocklnd_peer_decref(peer); passive_hellosent_done: /* safely transit to UC_READY state */ /* rc == 0 */ pthread_mutex_lock(&conn->uc_lock); if (conn->uc_state != UC_DEAD) { usocklnd_rx_ksmhdr_state_transition(conn); /* we're ready to recive incoming packets and maybe already have smth. to transmit */ LASSERT (conn->uc_sending == 0); if ( cfs_list_empty(&conn->uc_tx_list) && cfs_list_empty(&conn->uc_zcack_list) ) { conn->uc_tx_flag = 0; rc = usocklnd_add_pollrequest(conn, POLL_SET_REQUEST, POLLIN); } else { conn->uc_tx_deadline = cfs_time_shift(usock_tuns.ut_timeout); conn->uc_tx_flag = 1; rc = usocklnd_add_pollrequest(conn, POLL_SET_REQUEST, POLLIN | POLLOUT); } if (rc == 0) conn->uc_state = UC_READY; } pthread_mutex_unlock(&conn->uc_lock); return rc; passive_hellosent_connkill: usocklnd_conn_kill(conn); return 0; }
static int lfsck_namespace_double_scan_main(void *args) { struct lfsck_thread_args *lta = args; const struct lu_env *env = <a->lta_env; struct lfsck_component *com = lta->lta_com; struct lfsck_instance *lfsck = com->lc_lfsck; struct ptlrpc_thread *thread = &lfsck->li_thread; struct lfsck_bookmark *bk = &lfsck->li_bookmark_ram; struct lfsck_namespace *ns = com->lc_file_ram; struct dt_object *obj = com->lc_obj; const struct dt_it_ops *iops = &obj->do_index_ops->dio_it; struct dt_object *target; struct dt_it *di; struct dt_key *key; struct lu_fid fid; int rc; __u8 flags = 0; ENTRY; com->lc_new_checked = 0; com->lc_new_scanned = 0; com->lc_time_last_checkpoint = cfs_time_current(); com->lc_time_next_checkpoint = com->lc_time_last_checkpoint + cfs_time_seconds(LFSCK_CHECKPOINT_INTERVAL); di = iops->init(env, obj, 0, BYPASS_CAPA); if (IS_ERR(di)) GOTO(out, rc = PTR_ERR(di)); fid_cpu_to_be(&fid, &ns->ln_fid_latest_scanned_phase2); rc = iops->get(env, di, (const struct dt_key *)&fid); if (rc < 0) GOTO(fini, rc); /* Skip the start one, which either has been processed or non-exist. */ rc = iops->next(env, di); if (rc != 0) GOTO(put, rc); if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_NO_DOUBLESCAN)) GOTO(put, rc = 0); do { if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_DELAY3) && cfs_fail_val > 0) { struct l_wait_info lwi; lwi = LWI_TIMEOUT(cfs_time_seconds(cfs_fail_val), NULL, NULL); l_wait_event(thread->t_ctl_waitq, !thread_is_running(thread), &lwi); } key = iops->key(env, di); fid_be_to_cpu(&fid, (const struct lu_fid *)key); target = lfsck_object_find(env, lfsck, &fid); down_write(&com->lc_sem); if (target == NULL) { rc = 0; goto checkpoint; } else if (IS_ERR(target)) { rc = PTR_ERR(target); goto checkpoint; } /* XXX: Currently, skip remote object, the consistency for * remote object will be processed in LFSCK phase III. */ if (dt_object_exists(target) && !dt_object_remote(target)) { rc = iops->rec(env, di, (struct dt_rec *)&flags, 0); if (rc == 0) rc = lfsck_namespace_double_scan_one(env, com, target, flags); } lfsck_object_put(env, target); checkpoint: com->lc_new_checked++; com->lc_new_scanned++; ns->ln_fid_latest_scanned_phase2 = fid; if (rc > 0) ns->ln_objs_repaired_phase2++; else if (rc < 0) ns->ln_objs_failed_phase2++; up_write(&com->lc_sem); if ((rc == 0) || ((rc > 0) && !(bk->lb_param & LPF_DRYRUN))) { lfsck_namespace_delete(env, com, &fid); } else if (rc < 0) { flags |= LLF_REPAIR_FAILED; lfsck_namespace_update(env, com, &fid, flags, true); } if (rc < 0 && bk->lb_param & LPF_FAILOUT) GOTO(put, rc); if (unlikely(cfs_time_beforeq(com->lc_time_next_checkpoint, cfs_time_current())) && com->lc_new_checked != 0) { down_write(&com->lc_sem); ns->ln_run_time_phase2 += cfs_duration_sec(cfs_time_current() + HALF_SEC - com->lc_time_last_checkpoint); ns->ln_time_last_checkpoint = cfs_time_current_sec(); ns->ln_objs_checked_phase2 += com->lc_new_checked; com->lc_new_checked = 0; rc = lfsck_namespace_store(env, com, false); up_write(&com->lc_sem); if (rc != 0) GOTO(put, rc); com->lc_time_last_checkpoint = cfs_time_current(); com->lc_time_next_checkpoint = com->lc_time_last_checkpoint + cfs_time_seconds(LFSCK_CHECKPOINT_INTERVAL); } lfsck_control_speed_by_self(com); if (unlikely(!thread_is_running(thread))) GOTO(put, rc = 0); rc = iops->next(env, di); } while (rc == 0); GOTO(put, rc); put: iops->put(env, di); fini: iops->fini(env, di); out: down_write(&com->lc_sem); ns->ln_run_time_phase2 += cfs_duration_sec(cfs_time_current() + HALF_SEC - lfsck->li_time_last_checkpoint); ns->ln_time_last_checkpoint = cfs_time_current_sec(); ns->ln_objs_checked_phase2 += com->lc_new_checked; com->lc_new_checked = 0; if (rc > 0) { com->lc_journal = 0; ns->ln_status = LS_COMPLETED; if (!(bk->lb_param & LPF_DRYRUN)) ns->ln_flags &= ~(LF_SCANNED_ONCE | LF_INCONSISTENT); ns->ln_time_last_complete = ns->ln_time_last_checkpoint; ns->ln_success_count++; } else if (rc == 0) { ns->ln_status = lfsck->li_status; if (ns->ln_status == 0) ns->ln_status = LS_STOPPED; } else { ns->ln_status = LS_FAILED; } if (ns->ln_status != LS_PAUSED) { spin_lock(&lfsck->li_lock); cfs_list_del_init(&com->lc_link); cfs_list_add_tail(&com->lc_link, &lfsck->li_list_idle); spin_unlock(&lfsck->li_lock); } rc = lfsck_namespace_store(env, com, false); up_write(&com->lc_sem); if (atomic_dec_and_test(&lfsck->li_double_scan_count)) wake_up_all(&thread->t_ctl_waitq); lfsck_thread_args_fini(lta); return rc; }
/** * An implementation of cl_io_operations::cio_io_submit() method for osc * layer. Iterates over pages in the in-queue, prepares each for io by calling * cl_page_prep() and then either submits them through osc_io_submit_page() * or, if page is already submitted, changes osc flags through * osc_set_async_flags(). */ static int osc_io_submit(const struct lu_env *env, const struct cl_io_slice *ios, enum cl_req_type crt, struct cl_2queue *queue) { struct cl_page *page; struct cl_page *tmp; struct client_obd *cli = NULL; struct osc_object *osc = NULL; /* to keep gcc happy */ struct osc_page *opg; struct cl_io *io; CFS_LIST_HEAD (list); struct cl_page_list *qin = &queue->c2_qin; struct cl_page_list *qout = &queue->c2_qout; int queued = 0; int result = 0; int cmd; int brw_flags; int max_pages; LASSERT(qin->pl_nr > 0); CDEBUG(D_CACHE, "%d %d\n", qin->pl_nr, crt); osc = cl2osc(ios->cis_obj); cli = osc_cli(osc); max_pages = cli->cl_max_pages_per_rpc; cmd = crt == CRT_WRITE ? OBD_BRW_WRITE : OBD_BRW_READ; brw_flags = osc_io_srvlock(cl2osc_io(env, ios)) ? OBD_BRW_SRVLOCK : 0; /* * NOTE: here @page is a top-level page. This is done to avoid * creation of sub-page-list. */ cl_page_list_for_each_safe(page, tmp, qin) { struct osc_async_page *oap; /* Top level IO. */ io = page->cp_owner; LASSERT(io != NULL); opg = osc_cl_page_osc(page, osc); oap = &opg->ops_oap; LASSERT(osc == oap->oap_obj); if (!cfs_list_empty(&oap->oap_pending_item) || !cfs_list_empty(&oap->oap_rpc_item)) { CDEBUG(D_CACHE, "Busy oap %p page %p for submit.\n", oap, opg); result = -EBUSY; break; } result = cl_page_prep(env, io, page, crt); if (result != 0) { LASSERT(result < 0); if (result != -EALREADY) break; /* * Handle -EALREADY error: for read case, the page is * already in UPTODATE state; for write, the page * is not dirty. */ result = 0; continue; } cl_page_list_move(qout, qin, page); spin_lock(&oap->oap_lock); oap->oap_async_flags = ASYNC_URGENT|ASYNC_READY; oap->oap_async_flags |= ASYNC_COUNT_STABLE; spin_unlock(&oap->oap_lock); osc_page_submit(env, opg, crt, brw_flags); cfs_list_add_tail(&oap->oap_pending_item, &list); if (++queued == max_pages) { queued = 0; result = osc_queue_sync_pages(env, osc, &list, cmd, brw_flags); if (result < 0) break; } } if (queued > 0) result = osc_queue_sync_pages(env, osc, &list, cmd, brw_flags); CDEBUG(D_INFO, "%d/%d %d\n", qin->pl_nr, qout->pl_nr, result); return qout->pl_nr > 0 ? 0 : result; }
static int lfsck_namespace_prep(const struct lu_env *env, struct lfsck_component *com, struct lfsck_start_param *lsp) { struct lfsck_instance *lfsck = com->lc_lfsck; struct lfsck_namespace *ns = com->lc_file_ram; struct lfsck_position *pos = &com->lc_pos_start; if (ns->ln_status == LS_COMPLETED) { int rc; rc = lfsck_namespace_reset(env, com, false); if (rc != 0) return rc; } down_write(&com->lc_sem); ns->ln_time_latest_start = cfs_time_current_sec(); spin_lock(&lfsck->li_lock); if (ns->ln_flags & LF_SCANNED_ONCE) { if (!lfsck->li_drop_dryrun || lfsck_pos_is_zero(&ns->ln_pos_first_inconsistent)) { ns->ln_status = LS_SCANNING_PHASE2; cfs_list_del_init(&com->lc_link); cfs_list_add_tail(&com->lc_link, &lfsck->li_list_double_scan); if (!cfs_list_empty(&com->lc_link_dir)) cfs_list_del_init(&com->lc_link_dir); lfsck_pos_set_zero(pos); } else { ns->ln_status = LS_SCANNING_PHASE1; ns->ln_run_time_phase1 = 0; ns->ln_run_time_phase2 = 0; ns->ln_items_checked = 0; ns->ln_items_repaired = 0; ns->ln_items_failed = 0; ns->ln_dirs_checked = 0; ns->ln_mlinked_checked = 0; ns->ln_objs_checked_phase2 = 0; ns->ln_objs_repaired_phase2 = 0; ns->ln_objs_failed_phase2 = 0; ns->ln_objs_nlink_repaired = 0; ns->ln_objs_lost_found = 0; fid_zero(&ns->ln_fid_latest_scanned_phase2); if (cfs_list_empty(&com->lc_link_dir)) cfs_list_add_tail(&com->lc_link_dir, &lfsck->li_list_dir); *pos = ns->ln_pos_first_inconsistent; } } else { ns->ln_status = LS_SCANNING_PHASE1; if (cfs_list_empty(&com->lc_link_dir)) cfs_list_add_tail(&com->lc_link_dir, &lfsck->li_list_dir); if (!lfsck->li_drop_dryrun || lfsck_pos_is_zero(&ns->ln_pos_first_inconsistent)) { *pos = ns->ln_pos_last_checkpoint; pos->lp_oit_cookie++; } else { *pos = ns->ln_pos_first_inconsistent; } } spin_unlock(&lfsck->li_lock); up_write(&com->lc_sem); return 0; }
int lfsck_namespace_setup(const struct lu_env *env, struct lfsck_instance *lfsck) { struct lfsck_component *com; struct lfsck_namespace *ns; struct dt_object *root = NULL; struct dt_object *obj; int rc; ENTRY; LASSERT(lfsck->li_master); OBD_ALLOC_PTR(com); if (com == NULL) RETURN(-ENOMEM); CFS_INIT_LIST_HEAD(&com->lc_link); CFS_INIT_LIST_HEAD(&com->lc_link_dir); init_rwsem(&com->lc_sem); atomic_set(&com->lc_ref, 1); com->lc_lfsck = lfsck; com->lc_type = LT_NAMESPACE; com->lc_ops = &lfsck_namespace_ops; com->lc_file_size = sizeof(struct lfsck_namespace); OBD_ALLOC(com->lc_file_ram, com->lc_file_size); if (com->lc_file_ram == NULL) GOTO(out, rc = -ENOMEM); OBD_ALLOC(com->lc_file_disk, com->lc_file_size); if (com->lc_file_disk == NULL) GOTO(out, rc = -ENOMEM); root = dt_locate(env, lfsck->li_bottom, &lfsck->li_local_root_fid); if (IS_ERR(root)) GOTO(out, rc = PTR_ERR(root)); if (unlikely(!dt_try_as_dir(env, root))) GOTO(out, rc = -ENOTDIR); obj = local_index_find_or_create(env, lfsck->li_los, root, lfsck_namespace_name, S_IFREG | S_IRUGO | S_IWUSR, &dt_lfsck_features); if (IS_ERR(obj)) GOTO(out, rc = PTR_ERR(obj)); com->lc_obj = obj; rc = obj->do_ops->do_index_try(env, obj, &dt_lfsck_features); if (rc != 0) GOTO(out, rc); rc = lfsck_namespace_load(env, com); if (rc > 0) rc = lfsck_namespace_reset(env, com, true); else if (rc == -ENODATA) rc = lfsck_namespace_init(env, com); if (rc != 0) GOTO(out, rc); ns = com->lc_file_ram; switch (ns->ln_status) { case LS_INIT: case LS_COMPLETED: case LS_FAILED: case LS_STOPPED: spin_lock(&lfsck->li_lock); cfs_list_add_tail(&com->lc_link, &lfsck->li_list_idle); spin_unlock(&lfsck->li_lock); break; default: CERROR("%s: unknown lfsck_namespace status: rc = %u\n", lfsck_lfsck2name(lfsck), ns->ln_status); /* fall through */ case LS_SCANNING_PHASE1: case LS_SCANNING_PHASE2: /* No need to store the status to disk right now. * If the system crashed before the status stored, * it will be loaded back when next time. */ ns->ln_status = LS_CRASHED; /* fall through */ case LS_PAUSED: case LS_CRASHED: spin_lock(&lfsck->li_lock); cfs_list_add_tail(&com->lc_link, &lfsck->li_list_scan); cfs_list_add_tail(&com->lc_link_dir, &lfsck->li_list_dir); spin_unlock(&lfsck->li_lock); break; } GOTO(out, rc = 0); out: if (root != NULL && !IS_ERR(root)) lu_object_put(env, &root->do_lu); if (rc != 0) lfsck_component_cleanup(env, com); return rc; }