void rozofs_ll_lookup_nb(fuse_req_t req, fuse_ino_t parent, const char *name) { ientry_t *ie = 0; ientry_t *nie = 0; epgw_lookup_arg_t arg; int ret; void *buffer_p = NULL; int trc_idx; mattr_obj_t mattr_obj; struct fuse_entry_param fep; struct stat stbuf; int allocated = 0; int len_name; fuse_ino_t child = 0; // int local_lookup_success = 0; uint32_t lookup_flags=0; int extra_length = 0; fuse_ino_t ino = 0; int trace_flag = 0; /* ** Update the IO statistics */ rozofs_thr_cnt_update(rozofs_thr_counter[ROZOFSMOUNT_COUNTER_LOOKUP], 1); extra_length = rozofs_check_extra_inode_in_lookup((char*)name, &len_name); if (extra_length !=0) { uint8_t *pdata_p; uint32_t *lookup_flags_p = (uint32_t*)&name[len_name+1]; lookup_flags =*lookup_flags_p; if (extra_length > 4) { pdata_p = (uint8_t*)&name[len_name+1]; pdata_p+=sizeof(uint32_t); fuse_ino_t *inode_p = (fuse_ino_t*)pdata_p; child = *inode_p; ino = child; } } trace_flag = lookup_flags; if (ino != 0) {trace_flag |=(1<<31);} trc_idx = rozofs_trc_req_name_flags(srv_rozofs_ll_lookup,parent,(char*)name,(int)(trace_flag)); /* ** allocate a context for saving the fuse parameters */ buffer_p = rozofs_fuse_alloc_saved_context(); if (buffer_p == NULL) { severe("out of fuse saved context"); errno = ENOMEM; goto error; } SAVE_FUSE_PARAM(buffer_p,req); SAVE_FUSE_PARAM(buffer_p,parent); SAVE_FUSE_STRING(buffer_p,name); SAVE_FUSE_PARAM(buffer_p,trc_idx); SAVE_FUSE_PARAM(buffer_p,ino); SAVE_FUSE_PARAM(buffer_p,lookup_flags); DEBUG("lookup (%lu,%s)\n", (unsigned long int) parent, name); START_PROFILING_NB(buffer_p,rozofs_ll_lookup); len_name=strlen(name); if (len_name > ROZOFS_FILENAME_MAX) { errno = ENAMETOOLONG; goto error; } /* ** Check the case of NFS that attempt to revalidate an inode that has been flushed from the cache */ if ((strcmp(name,"..")== 0) || (strcmp(name,".")==0)) { fid_t lookup_fid; rozofs_inode_t *inode_p = (rozofs_inode_t*)lookup_fid; inode_p->fid[0]=0; inode_p->s.eid= exportclt.eid; inode_p->fid[1]=parent; arg.arg_gw.eid = exportclt.eid; memcpy(arg.arg_gw.parent,lookup_fid, sizeof (uuid_t)); arg.arg_gw.name = (char*)name; /* ** Queue the request and attempt to check if there is already the same ** request queued */ if (rozofs_lookup_insert_queue(buffer_p,parent,name,req,trc_idx,lookup_flags)== 1) { /* ** There is already a pending request, so nothing to send to the export */ gprofiler->rozofs_ll_lookup_agg[P_COUNT]++; rozofs_fuse_release_saved_context(buffer_p); return; } ret = rozofs_expgateway_send_routing_common(arg.arg_gw.eid,lookup_fid,EXPORT_PROGRAM, EXPORT_VERSION, EP_LOOKUP,(xdrproc_t) xdr_epgw_lookup_arg_t,(void *)&arg, rozofs_ll_lookup_cbk,buffer_p); if (ret < 0) goto error; /* ** no error just waiting for the answer */ return; } if (!(ie = get_ientry_by_inode(parent))) { errno = ENOENT; goto error; } /* ** check for direct access */ if (strncmp(name,"@rozofs@",8) == 0) { ret = rozofs_parse_object_name((char*)(name+8),&mattr_obj); if (ret == 0) { /* ** successful parsing-> attempt to create a fake ientry */ //errno = ENOENT; goto lookup_objectmode; } } /* ** Queue the request and attempt to check if there is already the same ** request queued */ if (rozofs_lookup_insert_queue(buffer_p,parent,name,req,trc_idx,lookup_flags)== 1) { /* ** There is already a pending request, so nothing to send to the export */ gprofiler->rozofs_ll_lookup_agg[P_COUNT]++; rozofs_fuse_release_saved_context(buffer_p); return; } /* ** check if the lookup is a lookup revalidate. In such a case, the VFS provides* ** the inode. So if the i-node attributes are fine, we do not worry */ if ((child != 0) && ((lookup_flags & 0x100) == 0)) { uint64_t attr_us = rozofs_tmr_get_attr_us(rozofs_is_directory_inode(ino)); nie = get_ientry_by_inode(child); if (nie != NULL) { if ( /* check regular file */ ((((nie->timestamp+attr_us) > rozofs_get_ticker_us()) || (rozofs_mode == 1))&&(S_ISREG(nie->attrs.attrs.mode))) || /* check directory */ (((nie->pending_getattr_cnt>0)||((nie->timestamp+attr_us) > rozofs_get_ticker_us()))&&(S_ISDIR(nie->attrs.attrs.mode))) ) { /* ** check if parent and child are either deleted/deleted or active/active */ int trash_state = 0; if (rozofs_inode_is_del_pending(ie->attrs.attrs.fid)) trash_state = 1; if (rozofs_inode_is_del_pending(nie->attrs.attrs.fid)) trash_state |= 1<<1; switch (trash_state) { case 2: if (rozofs_inode_is_trash(nie->attrs.attrs.fid) == 0) { errno = ENOENT; goto error; } mattr_to_stat(&nie->attrs, &stbuf,exportclt.bsize); stbuf.st_ino = child; /* ** set nlinks to reflect . & .. */ stbuf.st_nlink =2; goto success; break; case 0: case 3: mattr_to_stat(&nie->attrs, &stbuf,exportclt.bsize); stbuf.st_ino = child; goto success; break; default: errno = ENOENT; goto error; break; } } } } /* ** fill up the structure that will be used for creating the xdr message */ arg.arg_gw.eid = exportclt.eid; memcpy(arg.arg_gw.parent,ie->fid, sizeof (uuid_t)); arg.arg_gw.name = (char*)name; /* ** now initiates the transaction towards the remote end */ /* ** In case the EXPORT LBG is down ans we know this ientry, let's respond to ** the requester with the current available information */ #if 1 if ((common_config.client_fast_reconnect) && (child != 0)) { expgw_tx_routing_ctx_t routing_ctx; if (expgw_get_export_routing_lbg_info(arg.arg_gw.eid,ie->fid,&routing_ctx) != 0) { goto error; } if (north_lbg_get_state(routing_ctx.lbg_id[0]) != NORTH_LBG_UP) { if (!(nie = get_ientry_by_inode(child))) { errno = ENOENT; goto error; } mattr_to_stat(&nie->attrs, &stbuf,exportclt.bsize); stbuf.st_ino = child; goto success; } } #endif #if 1 ret = rozofs_expgateway_send_routing_common(arg.arg_gw.eid,ie->fid,EXPORT_PROGRAM, EXPORT_VERSION, EP_LOOKUP,(xdrproc_t) xdr_epgw_lookup_arg_t,(void *)&arg, rozofs_ll_lookup_cbk,buffer_p); #else ret = rozofs_export_send_common(&exportclt,EXPORT_PROGRAM, EXPORT_VERSION, EP_LOOKUP,(xdrproc_t) xdr_epgw_lookup_arg_t,(void *)&arg, rozofs_ll_lookup_cbk,buffer_p); #endif if (ret < 0) { /* ** In case of fast reconnect mode let's respond with the previously knows ** parameters instead of failing */ if (common_config.client_fast_reconnect) { if (child != 0) { if (!(nie = get_ientry_by_inode(child))) { errno = ENOENT; goto error; } mattr_to_stat(&nie->attrs, &stbuf,exportclt.bsize); stbuf.st_ino = child; goto success; } } goto error; } /* ** no error just waiting for the answer */ return; error: fuse_reply_err(req, errno); /* ** remove the context from the lookup queue */ if (buffer_p != NULL) ruc_objRemove(buffer_p); /* ** release the buffer if has been allocated */ rozofs_trc_rsp(srv_rozofs_ll_lookup,parent,NULL,1,trc_idx); out: STOP_PROFILING_NB(buffer_p,rozofs_ll_lookup); if (buffer_p != NULL) rozofs_fuse_release_saved_context(buffer_p); return; /** * case of the object mode */ lookup_objectmode: if (!(nie = get_ientry_by_fid(mattr_obj.fid))) { nie = alloc_ientry(mattr_obj.fid); allocated=1; } /** * update the timestamp in the ientry context */ nie->timestamp = rozofs_get_ticker_us(); if (allocated) { /* ** update the attributes in the ientry */ memcpy(nie->attrs.attrs.fid, mattr_obj.fid, sizeof(fid_t)); nie->attrs.attrs.cid = mattr_obj.cid; memcpy(nie->attrs.attrs.sids, mattr_obj.sids, sizeof(sid_t)*ROZOFS_SAFE_MAX); nie->attrs.attrs.size = mattr_obj.size; nie->attrs.attrs.nlink = 1; nie->attrs.attrs.mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO ; nie->attrs.attrs.uid = 0; nie->attrs.attrs.gid = 0; nie->nlookup = 0; } mattr_to_stat(&nie->attrs, &stbuf,exportclt.bsize); stbuf.st_ino = nie->inode; // info("FDL %d mode %d uid %d gid %d",allocated,nie->attrs.attrs.mode,nie->attrs.attrs.uid,nie->attrs.attrs.gid); success: memset(&fep, 0, sizeof (fep)); fep.ino =stbuf.st_ino; fep.attr_timeout = rozofs_tmr_get_attr(rozofs_is_directory_inode(nie->inode)); fep.entry_timeout = rozofs_tmr_get_entry(rozofs_is_directory_inode(nie->inode)); memcpy(&fep.attr, &stbuf, sizeof (struct stat)); nie->nlookup++; rozofs_inode_t * finode = (rozofs_inode_t *) nie->attrs.attrs.fid; fep.generation = finode->fid[0]; rz_fuse_reply_entry(req, &fep); rozofs_trc_rsp(srv_rozofs_ll_lookup,(nie==NULL)?0:nie->inode,(nie==NULL)?NULL:nie->attrs.attrs.fid,0,trc_idx); goto out; }
int export_unlink_multiple(export_t * e, fid_t parent, char *name, fid_t fid,mattr_t * pattrs,lv2_entry_t *plv2) { int status = -1; lv2_entry_t *lv2=NULL; fid_t child_fid; uint32_t child_type; uint16_t nlink = 0; int fdp = -1; int ret; rozofs_inode_t *fake_inode_p; rmfentry_disk_t trash_entry; int root_dirent_mask = 0; int unknown_fid = 0; int deleted_fid_count = 0; char filename[1024]; char *basename; int filecount; char *filename_p; int k; /* ** search for rozofs key in the filename */ if (strncmp(name,".@rozofs-mf@",12) == 0) { ret = rozofs_parse_object_name((char*)(name+12),&basename,&filecount); if (ret < 0) { errno = ENOTSUP; goto error; } } /* ** load the root_idx bitmap of the old parent */ export_dir_load_root_idx_bitmap(e,parent,plv2); /* ** set global variables associated with the export */ fdp = export_open_parent_directory(e,parent); if (get_mdirentry(plv2->dirent_root_idx_p,fdp, parent, name, child_fid, &child_type,&root_dirent_mask) != 0) goto out; if (S_ISDIR(child_type)) { errno = EISDIR; goto out; } /* ** do a loop on the file count */ for (k = 0; k < filecount ; k++) { sprintf(filename,"%s.%d",basename,k); filename_p = filename; // Delete the mdirentry if exist ret =del_mdirentry(plv2->dirent_root_idx_p,fdp, parent, name, child_fid, &child_type,root_dirent_mask); if (ret != 0) { if (errno != ENOENT) goto out; /* ** check the next entry */ continue; } // Get mattrs of child to delete if (!(lv2 = export_lookup_fid(e->trk_tb_p,e->lv2_cache, child_fid))) { unknown_fid++; /* ** check the next entry */ continue; } deleted_fid_count++; // Compute hash value for this fid uint32_t hash = 0; uint8_t *c = 0; for (c = lv2->attributes.s.attrs.fid; c != lv2->attributes.s.attrs.fid + 16; c++) hash = *c + (hash << 6) + (hash << 16) - hash; hash %= RM_MAX_BUCKETS; /* ** prepare the trash entry */ trash_entry.size = lv2->attributes.s.attrs.size; memcpy(trash_entry.fid, lv2->attributes.s.attrs.fid, sizeof (fid_t)); trash_entry.cid = lv2->attributes.s.attrs.cid; memcpy(trash_entry.initial_dist_set, lv2->attributes.s.attrs.sids, sizeof (sid_t) * ROZOFS_SAFE_MAX); memcpy(trash_entry.current_dist_set, lv2->attributes.s.attrs.sids, sizeof (sid_t) * ROZOFS_SAFE_MAX); fake_inode_p = (rozofs_inode_t *)parent; ret = exp_trash_entry_create(e->trk_tb_p,fake_inode_p->s.usr_id,&trash_entry); if (ret < 0) { /* ** error while inserting entry in trash file */ severe("error on trash insertion name %s error %s",name,strerror(errno)); } /* ** delete the metadata associated with the file */ ret = exp_delete_file(e,lv2); /* * In case of geo replication, insert a delete request from the 2 sites */ if (e->volume->georep) { /* ** update the geo replication: set start=end=0 to indicate a deletion */ geo_rep_insert_fid(e->geo_replication_tb[0], lv2->attributes.s.attrs.fid, 0/*start*/,0/*end*/, e->layout, lv2->attributes.s.attrs.cid, lv2->attributes.s.attrs.sids); /* ** update the geo replication: set start=end=0 to indicate a deletion */ geo_rep_insert_fid(e->geo_replication_tb[1], lv2->attributes.s.attrs.fid, 0/*start*/,0/*end*/, e->layout, lv2->attributes.s.attrs.cid, lv2->attributes.s.attrs.sids); } /* ** Preparation of the rmfentry */ rmfentry_t *rmfe = xmalloc(sizeof (rmfentry_t)); export_rm_bins_pending_count++; memcpy(rmfe->fid, trash_entry.fid, sizeof (fid_t)); rmfe->cid = trash_entry.cid; memcpy(rmfe->initial_dist_set, trash_entry.initial_dist_set, sizeof (sid_t) * ROZOFS_SAFE_MAX); memcpy(rmfe->current_dist_set, trash_entry.current_dist_set, sizeof (sid_t) * ROZOFS_SAFE_MAX); memcpy(rmfe->trash_inode,trash_entry.trash_inode,sizeof(fid_t)); list_init(&rmfe->list); /* Acquire lock on bucket trash list */ if ((errno = pthread_rwlock_wrlock (&e->trash_buckets[hash].rm_lock)) != 0) { severe("pthread_rwlock_wrlock failed: %s", strerror(errno)); // Best effort } /* ** Check size of file */ if (lv2->attributes.s.attrs.size >= RM_FILE_SIZE_TRESHOLD) { // Add to front of list list_push_front(&e->trash_buckets[hash].rmfiles, &rmfe->list); } else { // Add to back of list list_push_back(&e->trash_buckets[hash].rmfiles, &rmfe->list); } if ((errno = pthread_rwlock_unlock (&e->trash_buckets[hash].rm_lock)) != 0) { severe("pthread_rwlock_unlock failed: %s", strerror(errno)); // Best effort } // Update the nb. of blocks if (export_update_blocks(e, -(((int64_t) lv2->attributes.s.attrs.size + ROZOFS_BSIZE_BYTES(e->bsize) - 1) / ROZOFS_BSIZE_BYTES(e->bsize))) != 0) { severe("export_update_blocks failed: %s", strerror(errno)); // Best effort } // Remove from the cache (will be closed and freed) lv2_cache_del(e->lv2_cache, child_fid); } /* ** al the subfile have been deleted so Update export files */ if (export_update_files(e, 0-deleted_fid_count) != 0) goto out; // Update parent plv2->attributes.s.attrs.mtime = plv2->attributes.s.attrs.ctime = time(NULL); plv2->attributes.s.attrs.children--; // Write attributes of parents if (export_lv2_write_attributes(e->trk_tb_p,plv2) != 0) goto out; /* ** return the parent attributes */ memcpy(pattrs, &plv2->attributes.s.attrs, sizeof (mattr_t)); status = 0; out: /* ** check if parent root idx bitmap must be updated */ if (plv2 != NULL) export_dir_flush_root_idx_bitmap(e,parent,plv2->dirent_root_idx_p); if(fdp != -1) close(fdp); return status; }