static void scfs_destroy_inode(struct inode *inode) { struct scfs_sb_info *sbi = SCFS_S(inode->i_sb); struct scfs_inode_info *sii = SCFS_I(inode); if (sii->cinfo_array) scfs_cinfo_free(sii, sii->cinfo_array); if (!list_empty(&sii->cinfo_list)) { SCFS_PRINT_ERROR("cinfo list is not empty!\n"); ASSERT(0); } if (sii->cluster_buffer.c_page) { __free_pages(sii->cluster_buffer.c_page, SCFS_MEMPOOL_ORDER + 1); sii->cluster_buffer.c_buffer = NULL; sii->cluster_buffer.c_page = NULL; } if (sii->cluster_buffer.u_page) { __free_pages(sii->cluster_buffer.u_page, SCFS_MEMPOOL_ORDER + 1); sii->cluster_buffer.u_buffer = NULL; sii->cluster_buffer.u_page = NULL; atomic_sub(1, &sbi->current_file_count); } kmem_cache_free(scfs_inode_info_cache, sii); profile_sub_kmcached(sizeof(struct scfs_inode_info), SCFS_S(inode->i_sb)); }
static struct inode *scfs_alloc_inode(struct super_block *sb) { struct scfs_inode_info *sii; sii = kmem_cache_alloc(scfs_inode_info_cache, GFP_KERNEL); if (!sii) return NULL; profile_add_kmcached(sizeof(struct scfs_inode_info), SCFS_S(sb)); memset(sii, 0, offsetof(struct scfs_inode_info, vfs_inode)); sii->vfs_inode.i_version = 1; if (SCFS_S(sb)->options.flags & SCFS_DATA_COMPRESSABLE) sii->flags |= SCFS_DATA_COMPRESSABLE; mutex_init(&sii->lower_file_mutex); mutex_init(&sii->cinfo_mutex); INIT_LIST_HEAD(&sii->cinfo_list); #ifdef SCFS_MULTI_THREAD_COMPRESSION INIT_LIST_HEAD(&sii->cbm_list); sii->cbm_list_comp_count = 0; sii->cbm_list_write_count = 0; sii->is_inserted_to_sii_list = 0; sii->cbm_list_comp = NULL; #endif return &sii->vfs_inode; }
static int scfs_show_options(struct seq_file *m, struct dentry *root) { struct scfs_sb_info *sbi = SCFS_S(root->d_sb); struct scfs_mount_options *opts = &sbi->options; if (!(opts->flags & SCFS_DATA_COMPRESSABLE)) seq_printf(m, ",nocomp"); if (opts->cluster_size) seq_printf(m, ",cluster_size=%u", opts->cluster_size); if (opts->comp_threshold >= 0) seq_printf(m, ",comp_threshold=%u", opts->comp_threshold); switch (opts->comp_type) { case SCFS_COMP_LZO: seq_printf(m, ",comp_type=lzo"); break; case SCFS_COMP_BZIP2: seq_printf(m, ",comp_type=bzip2"); break; case SCFS_COMP_ZLIB: seq_printf(m, ",comp_type=zlib"); break; case SCFS_COMP_FASTLZO: seq_printf(m, ",comp_type=fastlzo"); break; default: break; } return 0; }
/* need to check parameters in calling vfs_write, * especially data buf */ int scfs_make_header(struct dentry *scfs_dentry, struct inode *scfs_inode) { struct scfs_sb_info *sbi = SCFS_S(scfs_inode->i_sb); struct file *lower_file = SCFS_I(scfs_inode)->lower_file; struct comp_footer cf; loff_t pos = 0; int ret; SCFS_DEBUG_START; if (!lower_file) { SCFS_PRINT_ERROR("lower_file is null\n"); return SCFS_ERR_IO; } cf.footer_size = sizeof(struct comp_footer); cf.cluster_size = sbi->options.cluster_size; cf.original_file_size = 0; cf.comp_type = sbi->options.comp_type; cf.magic = SCFS_MAGIC; ret = scfs_lower_write(lower_file, (char *)&cf, sizeof(struct comp_footer), &pos); mark_inode_dirty_sync(scfs_inode); // why? if (ret < 0) { SCFS_PRINT_ERROR("error in writing header\n"); return ret; } ret = 0; SCFS_DEBUG_END; return ret; }
int scfs_make_header(struct file *lower_file, struct inode *scfs_inode) { struct scfs_sb_info *sbi = SCFS_S(scfs_inode->i_sb); struct comp_footer cf; loff_t pos = 0; int ret; if (!lower_file) { SCFS_PRINT_ERROR("lower_file is null\n"); return -EIO; } cf.footer_size = CF_SIZE; cf.cluster_size = sbi->options.cluster_size; cf.original_file_size = 0; cf.comp_type = sbi->options.comp_type; cf.magic = SCFS_MAGIC; ret = scfs_lower_write(lower_file, (char *)&cf, CF_SIZE, &pos); mark_inode_dirty_sync(scfs_inode); if (ret < 0) { SCFS_PRINT_ERROR("error in writing header\n"); return ret; } ret = 0; return ret; }
static int scfs_readpage(struct file *file, struct page *page) { int ret; #ifdef SCFS_ASYNC_READ_PROFILE struct scfs_sb_info *sbi = SCFS_S(file->f_mapping->host->i_sb); atomic_inc(&sbi->scfs_standby_readpage_count); #endif ret = _scfs_readpage(file, page, -1); #ifdef SCFS_ASYNC_READ_PROFILE atomic_dec(&sbi->scfs_standby_readpage_count); #endif return (ret >= 0 ? 0 : ret); }
/* * scfs_file_release */ static int scfs_file_release(struct inode *inode, struct file *file) { int ret; SCFS_PRINT("f:%s calling fput with lower_file\n", file->f_path.dentry->d_name.name); if (file->f_flags & (O_RDWR | O_WRONLY)) { CLEAR_WROPENED(SCFS_I(inode)); ret = scfs_write_meta(file); if (ret) return ret; } fput(SCFS_F(file)->lower_file); kmem_cache_free(scfs_file_info_cache, SCFS_F(file)); profile_sub_kmcached(sizeof(struct scfs_file_info), SCFS_S(inode->i_sb)); return 0; }
static struct inode *_scfs_get_inode(struct inode *lower_inode, struct super_block *sb) { struct inode *inode; if (lower_inode->i_sb != SCFS_S(sb)->lower_sb) return ERR_PTR(-EXDEV); if (!igrab(lower_inode)) return ERR_PTR(-ESTALE); inode = iget5_locked(sb, (unsigned long)lower_inode->i_ino, scfs_inode_test, scfs_inode_set, lower_inode); if (!inode) { iput(lower_inode); return ERR_PTR(-EACCES); } if (!(inode->i_state & I_NEW)) iput(lower_inode); return inode; }
static int scfs_open(struct inode *inode, struct file *file) { struct scfs_sb_info *sbi = SCFS_S(inode->i_sb); struct scfs_inode_info *sii = SCFS_I(inode); struct scfs_file_info *fi; int ret = 0; struct file *lower_file; if (IS_WROPENED(sii)) { SCFS_PRINT("This file is already opened with 'WRITE' flag\n"); return -EPERM; } fi = kmem_cache_zalloc(scfs_file_info_cache, GFP_KERNEL); if (!fi) return -ENOMEM; profile_add_kmcached(sizeof(struct scfs_file_info), sbi); file->private_data = fi; mutex_lock(&sii->cinfo_mutex); if (IS_INVALID_META(sii)) { SCFS_PRINT("meta is invalid, so we should re-load it\n"); ret = scfs_reload_meta(file); if (ret) { SCFS_PRINT_ERROR("error in re-reading footer, err : %d\n", ret); goto out; } } else if (sii->compressed && !sii->cinfo_array) { /* 1st lower-open is for getting cinfo */ ret = scfs_initialize_lower_file(file->f_dentry, &lower_file, O_RDONLY); if (ret) { SCFS_PRINT_ERROR("err in get_lower_file %s\n", file->f_dentry->d_name.name); goto out; } scfs_set_lower_file(file, lower_file); SCFS_PRINT("info size = %d \n", sii->cinfo_array_size); ret = scfs_load_cinfo(sii, lower_file); if (ret) { SCFS_PRINT_ERROR("err in loading cinfo, ret : %d\n", file->f_dentry->d_name.name); fput(lower_file); goto out; } fput(lower_file); } ret = scfs_initialize_lower_file(file->f_dentry, &lower_file, file->f_flags); if (ret) { SCFS_PRINT_ERROR("err in get_lower_file %s\n", file->f_dentry->d_name.name); goto out; } scfs_set_lower_file(file, lower_file); out: if (!ret) { fsstack_copy_attr_all(inode, scfs_lower_inode(inode)); if (file->f_flags & (O_RDWR | O_WRONLY)) MAKE_WROPENED(sii); } else { scfs_set_lower_file(file, NULL); kmem_cache_free(scfs_file_info_cache, file->private_data); profile_sub_kmcached(sizeof(struct scfs_file_info), sbi); sii->cinfo_array = NULL; } mutex_unlock(&sii->cinfo_mutex); SCFS_PRINT("lower, dentry name : %s, count : %d, ret : %d\n", file->f_dentry->d_name.name, file->f_dentry->d_count, ret); return ret; }
/** * scfs_readpage * * Parameters: * @file: upper file * @page: upper page from SCFS inode mapping, data will be copied in here * * Return: * SCFS_SUCCESS if success, otherwise if error * * Description: * - Read in a page by reading a cluster from the file's lower file. * (Reading in a cluster for just a single page read is inevitable, but this * "amplified read" and decompressing overhead should be amortized when * other pages in that same cluster is accessed later, and only incurs * memcpy from the cached cluster buffer.) * - Recently accessed clusters ("buffer_cache") are cached for later reads. */ static inline int _scfs_readpage(struct file *file, struct page *page, int pref_index) { struct scfs_inode_info *sii = SCFS_I(page->mapping->host); struct scfs_sb_info *sbi = SCFS_S(page->mapping->host->i_sb); struct scfs_cluster_buffer buffer = {NULL, NULL, NULL, NULL, 0}; int ret = 0, compressed = 0; int alloc_membuffer = 1; int allocated_index = -1; int i; char *virt; SCFS_PRINT("f:%s i:%d c:0x%x u:0x%x\n", file->f_path.dentry->d_name.name, page->index, buffer.c_buffer, buffer.u_buffer); ASSERT(sii->cluster_size <= SCFS_CLUSTER_SIZE_MAX); #ifdef SCFS_ASYNC_READ_PROFILE sbi->scfs_readpage_total_count++; #endif #if MAX_BUFFER_CACHE /* search buffer_cache first in case the cluster is left cached */ if (pref_index >= 0 && sbi->buffer_cache[pref_index].inode_number == sii->vfs_inode.i_ino && sbi->buffer_cache[pref_index].cluster_number == PAGE_TO_CLUSTER_INDEX(page, sii) && atomic_read(&sbi->buffer_cache[pref_index].is_used) != 1) { spin_lock(&sbi->buffer_cache_lock); /* this pref_index is used for another page */ if (atomic_read(&sbi->buffer_cache[pref_index].is_used) == 1) { spin_unlock(&sbi->buffer_cache_lock); sbi->buffer_cache_reclaimed_before_used_count++; goto pick_slot; } atomic_set(&sbi->buffer_cache[pref_index].is_used, 1); spin_unlock(&sbi->buffer_cache_lock); virt = kmap_atomic(page); if (sbi->buffer_cache[pref_index].is_compressed) memcpy(virt, page_address(sbi->buffer_cache[pref_index].u_page) + PGOFF_IN_CLUSTER(page, sii) * PAGE_SIZE, PAGE_SIZE); else memcpy(virt, page_address(sbi->buffer_cache[pref_index].c_page) + PGOFF_IN_CLUSTER(page, sii) * PAGE_SIZE, PAGE_SIZE); atomic_set(&sbi->buffer_cache[pref_index].is_used, 0); kunmap_atomic(virt); SetPageUptodate(page); unlock_page(page); SCFS_PRINT("%s<h> %d\n",file->f_path.dentry->d_name.name, page->index); return pref_index + 1; } else if (pref_index >= 0) { sbi->buffer_cache_reclaimed_before_used_count++; goto pick_slot; } /* search buffer_cache first in case the cluster is left cached */ for (i = 0; i < MAX_BUFFER_CACHE; i++) { if (sbi->buffer_cache[i].inode_number == sii->vfs_inode.i_ino && sbi->buffer_cache[i].cluster_number == PAGE_TO_CLUSTER_INDEX(page, sii) && atomic_read(&sbi->buffer_cache[i].is_used) != 1) { spin_lock(&sbi->buffer_cache_lock); if (atomic_read(&sbi->buffer_cache[i].is_used) == 1) { spin_unlock(&sbi->buffer_cache_lock); goto pick_slot; } atomic_set(&sbi->buffer_cache[i].is_used, 1); spin_unlock(&sbi->buffer_cache_lock); virt = kmap_atomic(page); if (sbi->buffer_cache[i].is_compressed) memcpy(virt, page_address(sbi->buffer_cache[i].u_page) + PGOFF_IN_CLUSTER(page, sii) * PAGE_SIZE, PAGE_SIZE); else memcpy(virt, page_address(sbi->buffer_cache[i].c_page) + PGOFF_IN_CLUSTER(page, sii) * PAGE_SIZE, PAGE_SIZE); atomic_set(&sbi->buffer_cache[i].is_used, 0); kunmap_atomic(virt); SetPageUptodate(page); unlock_page(page); SCFS_PRINT("%s<h> %d\n", file->f_path.dentry->d_name.name, page->index); return i + 1; } } pick_slot: /* pick a slot in buffer_cache to use */ if (atomic_read(&sbi->buffer_cache[sbi->read_buffer_index].is_used) != 1) { spin_lock(&sbi->buffer_cache_lock); /* this index is used for another page */ if (atomic_read(&sbi->buffer_cache[sbi->read_buffer_index].is_used) == 1) { spin_unlock(&sbi->buffer_cache_lock); goto pick_slot_full; } atomic_set(&sbi->buffer_cache[sbi->read_buffer_index].is_used, 1); allocated_index = sbi->read_buffer_index++; if (sbi->read_buffer_index >= MAX_BUFFER_CACHE) sbi->read_buffer_index = 0; spin_unlock(&sbi->buffer_cache_lock); buffer.c_page = sbi->buffer_cache[allocated_index].c_page; buffer.u_page = sbi->buffer_cache[allocated_index].u_page; sbi->buffer_cache[allocated_index].inode_number = sii->vfs_inode.i_ino; sbi->buffer_cache[allocated_index].cluster_number = PAGE_TO_CLUSTER_INDEX(page, sii); alloc_membuffer = 0; goto real_io; } pick_slot_full: for (i = 0; i < MAX_BUFFER_CACHE; i++) { if (atomic_read(&sbi->buffer_cache[i].is_used) != 1) { spin_lock(&sbi->buffer_cache_lock); /* this index is used for another page */ if (atomic_read(&sbi->buffer_cache[i].is_used) == 1) { spin_unlock(&sbi->buffer_cache_lock); continue; } atomic_set(&sbi->buffer_cache[i].is_used, 1); sbi->read_buffer_index = i + 1; if (sbi->read_buffer_index >= MAX_BUFFER_CACHE) sbi->read_buffer_index = 0; spin_unlock(&sbi->buffer_cache_lock); buffer.c_page = sbi->buffer_cache[i].c_page; buffer.u_page = sbi->buffer_cache[i].u_page; sbi->buffer_cache[i].inode_number = sii->vfs_inode.i_ino; sbi->buffer_cache[i].cluster_number = PAGE_TO_CLUSTER_INDEX(page, sii); allocated_index = i; alloc_membuffer = 0; break; } } #endif real_io: #ifdef SCFS_ASYNC_READ_PROFILE sbi->scfs_readpage_io_count++; #endif /* sanity check & prepare buffers for scfs_read_cluster */ if (alloc_membuffer == 1 && (buffer.c_page || buffer.c_buffer)) ASSERT(0); if (!buffer.c_page) buffer.c_page = scfs_alloc_mempool_buffer(sbi); if (!buffer.c_page) { SCFS_PRINT_ERROR("c_page malloc failed\n"); ret = -ENOMEM; goto out; } if (!buffer.c_buffer) buffer.c_buffer = page_address(buffer.c_page); if (!buffer.c_buffer) { SCFS_PRINT_ERROR("c_buffer malloc failed\n"); ret = -ENOMEM; goto out; } if (!buffer.u_page) buffer.u_page = scfs_alloc_mempool_buffer(sbi); if (!buffer.u_page) { SCFS_PRINT_ERROR("u_page malloc failed\n"); ret = -ENOMEM; goto out; } if (!buffer.u_buffer) buffer.u_buffer = page_address(buffer.u_page); if (!buffer.u_buffer) { SCFS_PRINT_ERROR("u_buffer malloc failed\n"); ret = -ENOMEM; goto out; } /* read cluster from lower */ ret = scfs_read_cluster(file, page, buffer.c_buffer, &buffer.u_buffer, &compressed); if (ret) { if (ret == -ERANGE) SCFS_PRINT_ERROR("file %s error on readpage, OOB. ret %x\n", file->f_path.dentry->d_name.name, ret); else SCFS_PRINT_ERROR("read cluster failed, " "file %s page->index %u ret %d\n", file->f_path.dentry->d_name.name, page->index, ret); goto out; } #if MAX_BUFFER_CACHE /* don't need to spinlock, we have is_used=1 for this buffer */ if (alloc_membuffer != 1) sbi->buffer_cache[allocated_index].is_compressed = compressed; #endif #ifdef SCFS_REMOVE_NO_COMPRESSED_UPPER_MEMCPY /* fill page cache with the decompressed or original page */ if (compressed) { virt = kmap_atomic(page); memcpy(virt, page_address(buffer.u_page) + PGOFF_IN_CLUSTER(page, sii) * PAGE_SIZE, PAGE_SIZE); kunmap_atomic(virt); } #else /* fill page cache with the decompressed/original data */ virt = kmap_atomic(page); if (compressed) memcpy(virt, page_address(buffer.u_page) + PGOFF_IN_CLUSTER(page, sii) * PAGE_SIZE, PAGE_SIZE); else memcpy(virt, page_address(buffer.c_page) + PGOFF_IN_CLUSTER(page, sii) * PAGE_SIZE, PAGE_SIZE); kunmap_atomic(virt); #endif SetPageUptodate(page); #if MAX_BUFFER_CACHE #ifndef SCFS_REMOVE_NO_COMPRESSED_UPPER_MEMCPY if (alloc_membuffer != 1) { atomic_set(&sbi->buffer_cache[allocated_index].is_used, 0); } #else if (alloc_membuffer != 1 && compressed) { atomic_set(&sbi->buffer_cache[allocated_index].is_used, 0); } else if (alloc_membuffer != 1) { spin_lock(&sbi->buffer_cache_lock); sbi->buffer_cache[allocated_index].inode_number = -1; sbi->buffer_cache[allocated_index].cluster_number = -1; sbi->buffer_cache[allocated_index].is_compressed = -1; atomic_set(&sbi->buffer_cache[allocated_index].is_used, -1); spin_unlock(&sbi->buffer_cache_lock); } #endif #endif out: unlock_page(page); if (alloc_membuffer == 1) { sbi->buffer_cache_overflow_count_smb++; scfs_free_mempool_buffer(buffer.c_page, sbi); scfs_free_mempool_buffer(buffer.u_page, sbi); } SCFS_PRINT("-f:%s i:%d c:0x%x u:0x%x\n", file->f_path.dentry->d_name.name, page->index, buffer.c_buffer, buffer.u_buffer); SCFS_PRINT("%s<r> %d\n",file->f_path.dentry->d_name.name, page->index); if (ret < 0) return ret; else if (alloc_membuffer != 1) return allocated_index + 1; else return 0; }
/** * scfs_readpages * * Parameters: * @file: upper file * @*mapping: address_space struct for the file * @*pages: list of pages to read in * @nr_pages: number of pages to read in * * Return: * SCFS_SUCCESS if success, otherwise if error * * Description: * - Asynchronously read pages for readahead. A scaling number of background threads * will read & decompress them in a slightly deferred but parallelized manner. */ static int scfs_readpages(struct file *file, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { struct scfs_inode_info *sii = SCFS_I(file->f_mapping->host); struct scfs_sb_info *sbi = SCFS_S(file->f_mapping->host->i_sb); struct file *lower_file = NULL; struct page *page; struct scfs_cinfo cinfo; loff_t i_size; pgoff_t start, end; int page_idx, page_idx_readahead = 1024, ret = 0; int readahead_page = 0; int prev_cbi = 0; int prev_cluster = -1, cur_cluster = -1; int cluster_idx = 0; i_size = i_size_read(&sii->vfs_inode); if (!i_size) { SCFS_PRINT("file %s: i_size is zero, " "flags 0x%x sii->clust_info_size %d\n", file->f_path.dentry->d_name.name, sii->flags, sii->cinfo_array_size); return 0; } #ifdef SCFS_ASYNC_READ_PROFILE atomic_add(nr_pages, &sbi->scfs_standby_readpage_count); #endif #ifdef SCFS_NOTIFY_RANDOM_READ lower_file = scfs_lower_file(file); if (!lower_file) { SCFS_PRINT_ERROR("file %s: lower file is null!\n", file->f_path.dentry->d_name.name); return -EINVAL; } /* if the read request was random (enough), hint it to the lower file. * scfs_sequential_page_number is the tunable threshold. * filemap.c will later on refer to this FMODE_RANDOM flag. */ spin_lock(&lower_file->f_lock); if (nr_pages > sbi->scfs_sequential_page_number) lower_file->f_mode &= ~FMODE_RANDOM; else lower_file->f_mode |= FMODE_RANDOM; spin_unlock(&lower_file->f_lock); #endif lower_file = scfs_lower_file(file); page = list_entry(pages->prev, struct page, lru); cluster_idx = page->index / (sii->cluster_size / PAGE_SIZE); if (sii->compressed) { mutex_lock(&sii->cinfo_mutex); ret = get_cluster_info(file, cluster_idx, &cinfo); mutex_unlock(&sii->cinfo_mutex); if (ret) { SCFS_PRINT_ERROR("err in get_cluster_info, ret : %d," "i_size %lld\n", ret, i_size); return ret; } if (!cinfo.size || cinfo.size > sii->cluster_size) { SCFS_PRINT_ERROR("file %s: cinfo is invalid, " "clust %u cinfo.size %u\n", file->f_path.dentry->d_name.name, cluster_idx, cinfo.size); return -EINVAL; } start = (pgoff_t)(cinfo.offset / PAGE_SIZE); } else { start = (pgoff_t)(cluster_idx * sii->cluster_size / PAGE_SIZE); } cluster_idx = (page->index + nr_pages - 1) / (sii->cluster_size / PAGE_SIZE); if (sii->compressed) { mutex_lock(&sii->cinfo_mutex); ret = get_cluster_info(file, cluster_idx, &cinfo); mutex_unlock(&sii->cinfo_mutex); if (ret) { SCFS_PRINT_ERROR("err in get_cluster_info, ret : %d," "i_size %lld\n", ret, i_size); return ret; } if (!cinfo.size || cinfo.size > sii->cluster_size) { SCFS_PRINT_ERROR("file %s: cinfo is invalid, " "clust %u cinfo.size %u\n", file->f_path.dentry->d_name.name, cluster_idx, cinfo.size); return -EINVAL; } end = (pgoff_t)((cinfo.offset + cinfo.size -1) / PAGE_SIZE); } else { end = (pgoff_t)(((cluster_idx + 1) * sii->cluster_size - 1) / PAGE_SIZE); /* check upper inode size */ /* out of range? on compressed file, it is handled returning error, which one is right? */ if (end > (i_size / PAGE_SIZE)) end = (i_size / PAGE_SIZE); } force_page_cache_readahead(lower_file->f_mapping, lower_file, start, (unsigned long)(end - start +1)); for (page_idx = 0; page_idx < nr_pages; page_idx++) { page = list_entry(pages->prev, struct page, lru); list_del(&page->lru); if (PageReadahead(page)) page_idx_readahead = page_idx; ret = add_to_page_cache_lru(page, mapping, page->index, GFP_KERNEL); if (ret) { SCFS_PRINT("adding to page cache failed, " "page %x page->idx %d ret %d\n", page, page->index, ret); page_cache_release(page); continue; } /* memory buffer is full or synchronous read request - call scfs_readpage to read now */ if (sbi->page_buffer_next_filling_index_smb == MAX_PAGE_BUFFER_SIZE_SMB || page_idx < page_idx_readahead) { cur_cluster = PAGE_TO_CLUSTER_INDEX(page, sii); if (prev_cluster == cur_cluster && prev_cbi > 0) prev_cbi = _scfs_readpage(file, page, prev_cbi - 1); else prev_cbi = _scfs_readpage(file, page, -1); prev_cluster = cur_cluster; page_cache_release(page); /* refer line 701 */ } else { spin_lock(&sbi->spinlock_smb); /* Queue is not full so add the page into the queue. Also, here we increase file->f_count to protect the file structs from multi-threaded accesses */ atomic_long_inc(&SCFS_F(file)->lower_file->f_count); atomic_long_inc(&file->f_count); sbi->page_buffer_smb[sbi->page_buffer_next_filling_index_smb] = page; sbi->file_buffer_smb[sbi->page_buffer_next_filling_index_smb++] = file; /* check whether page buffer is full and set page buffer full if needed */ if (((sbi->page_buffer_next_filling_index_smb == MAX_PAGE_BUFFER_SIZE_SMB) && sbi->page_buffer_next_io_index_smb == 0) || (sbi->page_buffer_next_filling_index_smb == sbi->page_buffer_next_io_index_smb)) sbi->page_buffer_next_filling_index_smb = MAX_PAGE_BUFFER_SIZE_SMB; else if (sbi->page_buffer_next_filling_index_smb == MAX_PAGE_BUFFER_SIZE_SMB) sbi->page_buffer_next_filling_index_smb = 0; spin_unlock(&sbi->spinlock_smb); ++readahead_page; } //page_cache_release(page); } if (readahead_page > 0) wakeup_smb_thread(sbi); SCFS_PRINT("<e>\n"); #ifdef SCFS_ASYNC_READ_PROFILE atomic_sub(nr_pages, &sbi->scfs_standby_readpage_count); #endif return 0; }