/* * A single inode exist for all anon_inode files. Contrary to pipes, * anon_inode inodes has no per-instance data associated, so we can avoid * the allocation of multiple of them. */ static struct inode *anon_inode_mkinode(void) { struct inode *inode = new_inode(anon_inode_mnt->mnt_sb); struct _inode *_inode; if (!inode) return ERR_PTR(-ENOMEM); _inode = tx_cache_get_inode(inode); _inode->i_fop = &anon_inode_fops; /* * Mark the inode dirty from the very beginning, * that way it will never be moved to the dirty * list because mark_inode_dirty() will think * that it already _is_ on the dirty list. */ inode->i_state = I_DIRTY; _inode->i_mode = S_IRUSR | S_IWUSR; _inode->i_uid = current->fsuid; _inode->i_gid = current->fsgid; _inode->i_atime = _inode->i_mtime = _inode->i_ctime = CURRENT_TIME; return inode; }
int abort_dentry(struct txobj_thread_list_node * xnode){ struct dentry * orig = (struct dentry *)xnode->orig_obj; struct _dentry * shadow = (struct _dentry *)xnode->shadow_obj; if(xnode->rw == ACCESS_R){ atomic_dec(&shadow->tx_readcount); atomic_dec(&shadow->tx_refcount); } else { if((shadow->d_flags & DCACHE_SPECULATIVE_CREATE)){ struct _dentry *old_dentry = orig->d_contents; /* Free up the speculatively created inode reference to force deletion */ tx_atomic_dec(&shadow->d_inode->i_count); tx_cache_get_inode(shadow->d_inode)->i_nlink--; free_tx_dentry(shadow); /* Use this as a signal to release_dentry */ old_dentry->d_flags |= DCACHE_SPECULATIVE_CREATE; /* We also need the dentry to be negative */ KSTM_BUG_ON(old_dentry->d_inode != NULL); /* And hack to avoid messing up the parent * dentry's refcount when we put, as we will * rollback the refcount increase elsewhere */ tx_atomic_inc(&old_dentry->d_parent->d_count); } else free_tx_dentry(shadow); } return 0; }
static int oprofilefs_fill_super(struct super_block * sb, void * data, int silent) { struct inode * root_inode; struct _inode * _root_inode; struct dentry * root_dentry; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = OPROFILEFS_MAGIC; sb->s_op = &s_ops; sb->s_time_gran = 1; root_inode = oprofilefs_get_inode(sb, S_IFDIR | 0755); if (!root_inode) return -ENOMEM; _root_inode = tx_cache_get_inode(root_inode); _root_inode->i_op = &simple_dir_inode_operations; _root_inode->i_fop = &simple_dir_operations; root_dentry = d_alloc_root(_root_inode); if (!root_dentry) { iput(root_inode); return -ENOMEM; } sb->s_root = root_dentry; oprofile_create_files(sb, tx_cache_get_dentry(root_dentry)); // FIXME: verify kill_litter_super removes our dentries return 0; }
void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page) { swp_entry_t entry; down_read(&swap_unplug_sem); entry.val = page_private(page); if (PageSwapCache(page)) { struct block_device *bdev = swap_info[swp_type(entry)].bdev; struct backing_dev_info *bdi; /* * If the page is removed from swapcache from under us (with a * racy try_to_unuse/swapoff) we need an additional reference * count to avoid reading garbage from page_private(page) above. * If the WARN_ON triggers during a swapoff it maybe the race * condition and it's harmless. However if it triggers without * swapoff it signals a problem. */ WARN_ON(page_count(page) <= 1); bdi = tx_cache_get_inode(bdev->bd_inode)->i_mapping->backing_dev_info; blk_run_backing_dev(bdi, page); } up_read(&swap_unplug_sem); }
static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode) { struct inode * inode = new_inode(sb); if (inode) { struct _inode *_inode = tx_cache_get_inode(inode); _inode->i_mode = mode; _inode->i_uid = 0; _inode->i_gid = 0; inode->i_blocks = 0; _inode->i_atime = _inode->i_mtime = _inode->i_ctime = CURRENT_TIME; } return inode; }
static struct _dentry * __oprofilefs_create_file(struct super_block * sb, struct _dentry * root, char const * name, const struct file_operations * fops, int perm) { struct dentry * dentry; struct _dentry * _dentry; struct inode * inode; struct _inode * _inode; dentry = d_alloc_name(root, name); if (!dentry) return NULL; inode = oprofilefs_get_inode(sb, S_IFREG | perm); if (!inode) { dput(dentry); return NULL; } _inode = tx_cache_get_inode(inode); _inode->i_fop = fops; _dentry = tx_cache_get_dentry(dentry); d_add(_dentry, _inode); return _dentry; }
struct _dentry * oprofilefs_mkdir(struct super_block * sb, struct _dentry * root, char const * name) { struct dentry * dentry; struct _dentry * _dentry; struct inode * inode; struct _inode * _inode; dentry = d_alloc_name(root, name); if (!dentry) return NULL; inode = oprofilefs_get_inode(sb, S_IFDIR | 0755); if (!inode) { dput(dentry); return NULL; } _inode = tx_cache_get_inode(inode); _inode->i_op = &simple_dir_inode_operations; _inode->i_fop = &simple_dir_operations; _dentry = tx_cache_get_dentry(dentry); d_add(_dentry, _inode); return _dentry; }
static struct file *__dentry_open(struct _dentry *dentry, struct vfsmount *mnt, int flags, struct file *f, int (*open)(struct _inode *, struct file *)) { struct _inode *inode; int error; struct super_block *sb; struct _file *_f = tx_cache_get_file(f); _f->f_flags = flags; _f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; inode = d_get_inode(dentry); sb = inode->i_sb; if (_f->f_mode & FMODE_WRITE) { error = get_write_access(parent(inode)); if (error) goto cleanup_file; } f->f_mapping = inode->i_mapping; _f->f_path.dentry = parent(dentry); _f->f_path.mnt = mnt; _f->f_pos = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &sb->s_files); if (!open && f->f_op) open = f->f_op->open; if (open) { error = open(inode, f); if (error) goto cleanup_all; } _f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, tx_cache_get_inode(f->f_mapping->host)->i_mapping); /* NB: we're sure to have correct a_ops only after f_op->open */ if (_f->f_flags & O_DIRECT) { if (!f->f_mapping->a_ops || ((!f->f_mapping->a_ops->direct_IO) && (!f->f_mapping->a_ops->get_xip_page))) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: fops_put(f->f_op); if (_f->f_mode & FMODE_WRITE) put_write_access(parent(inode)); file_kill(f); _f->f_path.dentry = NULL; _f->f_path.mnt = NULL; cleanup_file: /* Avoid issues if we recycle this object */ if(live_transaction()) early_release(&f->xobj, 1); put_filp(f); dput(parent(dentry)); mntput(mnt); return ERR_PTR(error); }
/* * Code shared between mknod, mkdir, symlink and link */ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, struct _inode *dir, struct dentry *entry, int mode) { struct fuse_entry_out outarg; struct inode *inode; struct _inode *_inode; int err; struct fuse_req *forget_req; forget_req = fuse_get_req(fc); if (IS_ERR(forget_req)) { fuse_put_request(fc, req); return PTR_ERR(forget_req); } req->in.h.nodeid = _get_node_id(dir); req->out.numargs = 1; req->out.args[0].size = sizeof(outarg); req->out.args[0].value = &outarg; request_send(fc, req); err = req->out.h.error; fuse_put_request(fc, req); if (err) goto out_put_forget_req; err = -EIO; if (invalid_nodeid(outarg.nodeid)) goto out_put_forget_req; if ((outarg.attr.mode ^ mode) & S_IFMT) goto out_put_forget_req; inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, &outarg.attr); if (!inode) { fuse_send_forget(fc, forget_req, outarg.nodeid, 1); return -ENOMEM; } fuse_put_request(fc, forget_req); _inode = tx_cache_get_inode(inode); if (S_ISDIR(_inode->i_mode)) { struct dentry *alias; mutex_lock(&fc->inst_mutex); alias = d_find_alias(_inode); if (alias) { /* New directory must have moved since mkdir */ mutex_unlock(&fc->inst_mutex); dput(alias); iput(inode); return -EBUSY; } d_instantiate(entry, _inode); mutex_unlock(&fc->inst_mutex); } else d_instantiate(entry, _inode); fuse_change_timeout(entry, &outarg); fuse_invalidate_attr(dir); return 0; out_put_forget_req: fuse_put_request(fc, forget_req); return err; }
/* * Atomic create+open operation * * If the filesystem doesn't support this, then fall back to separate * 'mknod' + 'open' requests. */ static int fuse_create_open(struct _inode *dir, struct dentry *entry, int mode, struct nameidata *nd) { int err; struct inode *inode; struct _inode *_inode; struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_req *req; struct fuse_req *forget_req; struct fuse_open_in inarg; struct fuse_open_out outopen; struct fuse_entry_out outentry; struct fuse_file *ff; struct file *file; int flags = nd->intent.open.flags - 1; if (fc->no_create) return -ENOSYS; forget_req = fuse_get_req(fc); if (IS_ERR(forget_req)) return PTR_ERR(forget_req); req = fuse_get_req(fc); err = PTR_ERR(req); if (IS_ERR(req)) goto out_put_forget_req; err = -ENOMEM; ff = fuse_file_alloc(); if (!ff) goto out_put_request; flags &= ~O_NOCTTY; memset(&inarg, 0, sizeof(inarg)); inarg.flags = flags; inarg.mode = mode; req->in.h.opcode = FUSE_CREATE; req->in.h.nodeid = _get_node_id(dir); req->in.numargs = 2; req->in.args[0].size = sizeof(inarg); req->in.args[0].value = &inarg; req->in.args[1].size = entry->d_name.len + 1; req->in.args[1].value = entry->d_name.name; req->out.numargs = 2; req->out.args[0].size = sizeof(outentry); req->out.args[0].value = &outentry; req->out.args[1].size = sizeof(outopen); req->out.args[1].value = &outopen; request_send(fc, req); err = req->out.h.error; if (err) { if (err == -ENOSYS) fc->no_create = 1; goto out_free_ff; } err = -EIO; if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) goto out_free_ff; fuse_put_request(fc, req); inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, &outentry.attr); if (!inode) { flags &= ~(O_CREAT | O_EXCL | O_TRUNC); ff->fh = outopen.fh; fuse_sync_release(fc, ff, outentry.nodeid, flags); fuse_send_forget(fc, forget_req, outentry.nodeid, 1); return -ENOMEM; } _inode = tx_cache_get_inode(inode); fuse_put_request(fc, forget_req); d_instantiate(entry, _inode); fuse_change_timeout(entry, &outentry); file = lookup_instantiate_filp(nd, entry, generic_file_open); if (IS_ERR(file)) { ff->fh = outopen.fh; fuse_sync_release(fc, ff, outentry.nodeid, flags); return PTR_ERR(file); } fuse_finish_open(_inode, file, ff, &outopen); return 0; out_free_ff: fuse_file_free(ff); out_put_request: fuse_put_request(fc, req); out_put_forget_req: fuse_put_request(fc, forget_req); return err; }
static struct dentry *fuse_lookup(struct _inode *dir, struct dentry *entry, struct nameidata *nd) { int err; struct fuse_entry_out outarg; struct inode *inode = NULL; struct _inode *_inode = NULL; struct fuse_conn *fc = get_fuse_conn(dir); struct fuse_req *req; struct fuse_req *forget_req; if (entry->d_name.len > FUSE_NAME_MAX) return ERR_PTR(-ENAMETOOLONG); req = fuse_get_req(fc); if (IS_ERR(req)) return ERR_PTR(PTR_ERR(req)); forget_req = fuse_get_req(fc); if (IS_ERR(forget_req)) { fuse_put_request(fc, req); return ERR_PTR(PTR_ERR(forget_req)); } fuse_lookup_init(req, dir, entry, &outarg); request_send(fc, req); err = req->out.h.error; fuse_put_request(fc, req); /* Zero nodeid is same as -ENOENT, but with valid timeout */ if (!err && outarg.nodeid && (invalid_nodeid(outarg.nodeid) || !fuse_valid_type(outarg.attr.mode))) err = -EIO; if (!err && outarg.nodeid) { inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, &outarg.attr); if (!inode) { fuse_send_forget(fc, forget_req, outarg.nodeid, 1); return ERR_PTR(-ENOMEM); } } fuse_put_request(fc, forget_req); if (err && err != -ENOENT) return ERR_PTR(err); _inode = tx_cache_get_inode(inode); if (inode && S_ISDIR(_inode->i_mode)) { mutex_lock(&fc->inst_mutex); err = fuse_d_add_directory(entry, _inode); mutex_unlock(&fc->inst_mutex); if (err) { iput(inode); return ERR_PTR(err); } } else d_add(entry, _inode); entry->d_op = &fuse_dentry_operations; if (!err) fuse_change_timeout(entry, &outarg); else fuse_invalidate_entry_cache(entry); return NULL; }
/** * anon_inode_getfd - creates a new file instance by hooking it up to and * anonymous inode, and a dentry that describe the "class" * of the file * * @pfd: [out] pointer to the file descriptor * @dpinode: [out] pointer to the inode * @pfile: [out] pointer to the file struct * @name: [in] name of the "class" of the new file * @fops [in] file operations for the new file * @priv [in] private data for the new file (will be file's private_data) * * Creates a new file by hooking it on a single inode. This is useful for files * that do not need to have a full-fledged inode in order to operate correctly. * All the files created with anon_inode_getfd() will share a single inode, by * hence saving memory and avoiding code duplication for the file/inode/dentry * setup. */ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, const char *name, const struct file_operations *fops, void *priv) { struct qstr this; struct dentry *dentry; struct _dentry *_dentry; struct inode *inode; struct _inode *_inode; struct file *file; struct _file *_file; int error, fd; if (IS_ERR(anon_inode_inode)) return -ENODEV; file = get_empty_filp(); if (!file) return -ENFILE; _file = tx_cache_get_file(file); inode = igrab(anon_inode_inode); if (IS_ERR(inode)) { error = PTR_ERR(inode); goto err_put_filp; } _inode = tx_cache_get_inode(inode); error = get_unused_fd(); if (error < 0) goto err_iput; fd = error; /* * Link the inode to a directory entry by creating a unique name * using the inode sequence number. */ error = -ENOMEM; this.name = name; this.len = strlen(name); this.hash = 0; dentry = d_alloc(tx_cache_get_dentry(anon_inode_mnt->mnt_sb->s_root), &this); if (!dentry) goto err_put_unused_fd; _dentry = tx_cache_get_dentry(dentry); _dentry->d_op = &anon_inodefs_dentry_operations; /* Do not publish this dentry inside the global dentry hash table */ _dentry->d_flags &= ~DCACHE_UNHASHED; d_instantiate(_dentry, _inode); _file->f_path.mnt = mntget(anon_inode_mnt); _file->f_path.dentry = dentry; file->f_mapping = _inode->i_mapping; _file->f_pos = 0; _file->f_flags = O_RDWR; file->f_op = fops; _file->f_mode = FMODE_READ | FMODE_WRITE; _file->f_version = 0; file->private_data = priv; fd_install(fd, file); *pfd = fd; *pinode = inode; *pfile = file; return 0; err_put_unused_fd: put_unused_fd(fd); err_iput: iput(inode); err_put_filp: put_filp(file); return error; }
/* * This is the worker routine which does all the work of mapping the disk * blocks and constructs largest possible bios, submits them for IO if the * blocks are not contiguous on the disk. * * We pass a buffer_head back and forth and use its buffer_mapped() flag to * represent the validity of its disk mapping and to decide when to do the next * get_block() call. */ static struct bio * do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages, sector_t *last_block_in_bio, struct buffer_head *map_bh, unsigned long *first_logical_block, get_block_t get_block) { struct _inode *inode = tx_cache_get_inode(page->mapping->host); const unsigned blkbits = inode->i_blkbits; const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits; const unsigned blocksize = 1 << blkbits; sector_t block_in_file; sector_t last_block; sector_t last_block_in_file; sector_t blocks[MAX_BUF_PER_PAGE]; unsigned page_block; unsigned first_hole = blocks_per_page; struct block_device *bdev = NULL; int length; int fully_mapped = 1; unsigned nblocks; unsigned relative_block; if (page_has_buffers(page)) goto confused; block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT - blkbits); last_block = block_in_file + nr_pages * blocks_per_page; last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits; if (last_block > last_block_in_file) last_block = last_block_in_file; page_block = 0; /* * Map blocks using the result from the previous get_blocks call first. */ nblocks = map_bh->b_size >> blkbits; if (buffer_mapped(map_bh) && block_in_file > *first_logical_block && block_in_file < (*first_logical_block + nblocks)) { unsigned map_offset = block_in_file - *first_logical_block; unsigned last = nblocks - map_offset; for (relative_block = 0; ; relative_block++) { if (relative_block == last) { clear_buffer_mapped(map_bh); break; } if (page_block == blocks_per_page) break; blocks[page_block] = map_bh->b_blocknr + map_offset + relative_block; page_block++; block_in_file++; } bdev = map_bh->b_bdev; } /* * Then do more get_blocks calls until we are done with this page. */ map_bh->b_page = page; while (page_block < blocks_per_page) { map_bh->b_state = 0; map_bh->b_size = 0; if (block_in_file < last_block) { map_bh->b_size = (last_block-block_in_file) << blkbits; if (get_block(inode, block_in_file, map_bh, 0)) goto confused; *first_logical_block = block_in_file; } if (!buffer_mapped(map_bh)) { fully_mapped = 0; if (first_hole == blocks_per_page) first_hole = page_block; page_block++; block_in_file++; clear_buffer_mapped(map_bh); continue; } /* some filesystems will copy data into the page during * the get_block call, in which case we don't want to * read it again. map_buffer_to_page copies the data * we just collected from get_block into the page's buffers * so readpage doesn't have to repeat the get_block call */ if (buffer_uptodate(map_bh)) { map_buffer_to_page(page, map_bh, page_block); goto confused; } if (first_hole != blocks_per_page) goto confused; /* hole -> non-hole */ /* Contiguous blocks? */ if (page_block && blocks[page_block-1] != map_bh->b_blocknr-1) goto confused; nblocks = map_bh->b_size >> blkbits; for (relative_block = 0; ; relative_block++) { if (relative_block == nblocks) { clear_buffer_mapped(map_bh); break; } else if (page_block == blocks_per_page) break; blocks[page_block] = map_bh->b_blocknr+relative_block; page_block++; block_in_file++; } bdev = map_bh->b_bdev; } if (first_hole != blocks_per_page) { zero_user_page(page, first_hole << blkbits, PAGE_CACHE_SIZE - (first_hole << blkbits), KM_USER0); if (first_hole == 0) { SetPageUptodate(page); unlock_page(page); goto out; } } else if (fully_mapped) { SetPageMappedToDisk(page); } /* * This page will go to BIO. Do we need to send this BIO off first? */ if (bio && (*last_block_in_bio != blocks[0] - 1)) bio = mpage_bio_submit(READ, bio); alloc_new: if (bio == NULL) { bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9), min_t(int, nr_pages, bio_get_nr_vecs(bdev)), GFP_KERNEL); if (bio == NULL) goto confused; }