/** * Check if such a link exists in linkEA. * * \param ldata link data the search to be done on * \param lname name in the parent's directory entry pointing to this object * \param pfid parent fid the link to be found for * * \retval 0 success * \retval -ENOENT link does not exist * \retval -ve on error */ int linkea_links_find(struct linkea_data *ldata, const struct lu_name *lname, const struct lu_fid *pfid) { struct lu_name tmpname; struct lu_fid tmpfid; int count; LASSERT(ldata->ld_leh != NULL); /* link #0, if leh_reccount == 0 we skip the loop and return -ENOENT */ if (likely(ldata->ld_leh->leh_reccount > 0)) ldata->ld_lee = (struct link_ea_entry *)(ldata->ld_leh + 1); for (count = 0; count < ldata->ld_leh->leh_reccount; count++) { linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen, &tmpname, &tmpfid); if (tmpname.ln_namelen == lname->ln_namelen && lu_fid_eq(&tmpfid, pfid) && (strncmp(tmpname.ln_name, lname->ln_name, tmpname.ln_namelen) == 0)) break; ldata->ld_lee = (struct link_ea_entry *)((char *)ldata->ld_lee + ldata->ld_reclen); } if (count == ldata->ld_leh->leh_reccount) { CDEBUG(D_INODE, "Old link_ea name '%.*s' not found\n", lname->ln_namelen, lname->ln_name); ldata->ld_lee = NULL; ldata->ld_reclen = 0; return -ENOENT; } return 0; }
/** * \retval ve: removed entries */ static int lfsck_linkea_entry_unpack(struct lfsck_instance *lfsck, struct linkea_data *ldata, struct lu_name *cname, struct lu_fid *pfid) { struct link_ea_entry *oldlee; int oldlen; int removed = 0; linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen, cname, pfid); oldlee = ldata->ld_lee; oldlen = ldata->ld_reclen; linkea_next_entry(ldata); while (ldata->ld_lee != NULL) { ldata->ld_reclen = (ldata->ld_lee->lee_reclen[0] << 8) | ldata->ld_lee->lee_reclen[1]; if (unlikely(ldata->ld_reclen == oldlen && memcmp(ldata->ld_lee, oldlee, oldlen) == 0)) { linkea_del_buf(ldata, cname); removed++; } else { linkea_next_entry(ldata); } } ldata->ld_lee = oldlee; ldata->ld_reclen = oldlen; return removed; }
/** * Mark the linkEA as overflow with current timestamp, * and remove the last linkEA entry. * * Return the new linkEA size. */ int linkea_overflow_shrink(struct linkea_data *ldata) { struct link_ea_header *leh; struct lu_name tname; struct lu_fid tfid; int count; leh = ldata->ld_leh = ldata->ld_buf->lb_buf; if (leh->leh_magic == __swab32(LINK_EA_MAGIC)) { leh->leh_magic = LINK_EA_MAGIC; leh->leh_reccount = __swab32(leh->leh_reccount); leh->leh_overflow_time = __swab32(leh->leh_overflow_time); leh->leh_padding = __swab32(leh->leh_padding); } LASSERT(leh->leh_reccount > 0); leh->leh_len = sizeof(struct link_ea_header); leh->leh_reccount--; if (unlikely(leh->leh_reccount == 0)) return 0; leh->leh_overflow_time = cfs_time_current_sec(); if (unlikely(leh->leh_overflow_time == 0)) leh->leh_overflow_time++; ldata->ld_reclen = 0; ldata->ld_lee = (struct link_ea_entry *)(leh + 1); for (count = 0; count < leh->leh_reccount; count++) { linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen, &tname, &tfid); leh->leh_len += ldata->ld_reclen; ldata->ld_lee = (struct link_ea_entry *)((char *)ldata->ld_lee + ldata->ld_reclen); } linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen, &tname, &tfid); CDEBUG(D_INODE, "No enough space to hold the last linkea entry '" DFID": %.*s', shrink it, left %d linkea entries, size %llu\n", PFID(&tfid), tname.ln_namelen, tname.ln_name, leh->leh_reccount, leh->leh_len); return leh->leh_len; }