static int autofs4_getpath(struct autofs_sb_info *sbi, struct dentry *dentry, char **name) { struct dentry *root = sbi->sb->s_root; struct _dentry *tmp; char *buf = *name; char *p; int len = 0; struct _dentry *_dentry = tx_cache_get_dentry(dentry); spin_lock(&dcache_lock); for (tmp = tx_cache_get_dentry(dentry) ; parent(tmp) != root ; tmp = tx_cache_get_dentry(tmp->d_parent)) len += tmp->d_name.len + 1; if (--len > NAME_MAX) { spin_unlock(&dcache_lock); return 0; } *(buf + len) = '\0'; p = buf + len - _dentry->d_name.len; strncpy(p, _dentry->d_name.name, _dentry->d_name.len); for (tmp = tx_cache_get_dentry(_dentry->d_parent); parent(tmp) != root ; tmp = tx_cache_get_dentry(tmp->d_parent)) { *(--p) = '/'; p -= tmp->d_name.len; strncpy(p, tmp->d_name.name, tmp->d_name.len); } spin_unlock(&dcache_lock); return len; }
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; }
static int flush_write_buffer(struct dentry * dentry, struct configfs_buffer * buffer, size_t count) { struct configfs_attribute * attr = to_attr(dentry); struct config_item * item = to_item(tx_cache_get_dentry(dentry)->d_parent); struct configfs_item_operations * ops = buffer->ops; return ops->store_attribute(item,attr,buffer->page,count); }
int configfs_add_file(struct dentry * dir, const struct configfs_attribute * attr, int type) { struct configfs_dirent * parent_sd = dir->d_fsdata; umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG; int error = 0; struct inode *inode = tx_cache_get_dentry(dir)->d_inode; mutex_lock(&inode->i_mutex); error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type); mutex_unlock(&inode->i_mutex); return error; }
/* * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an * error. */ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { int error; struct file *f; error = -ENFILE; f = get_empty_filp(); if (f == NULL) { dput(dentry); mntput(mnt); return ERR_PTR(error); } return __dentry_open(tx_cache_get_dentry(dentry), mnt, flags, f, NULL); }
/** * lookup_instantiate_filp - instantiates the open intent filp * @nd: pointer to nameidata * @dentry: pointer to dentry * @open: open callback * * Helper for filesystems that want to use lookup open intents and pass back * a fully instantiated struct file to the caller. * This function is meant to be called from within a filesystem's * lookup method. * Beware of calling it for non-regular files! Those ->open methods might block * (e.g. in fifo_open), leaving you with parent locked (and in case of fifo, * leading to a deadlock, as nobody can open that fifo anymore, because * another process to open fifo will block on locked parent when doing lookup). * Note that in case of error, nd->intent.open.file is destroyed, but the * path information remains valid. * If the open callback is set to NULL, then the standard f_op->open() * filesystem callback is substituted. */ struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, int (*open)(struct _inode *, struct file *)) { if (IS_ERR(nd->intent.open.file)) goto out; if (IS_ERR(dentry)) goto out_err; nd->intent.open.file = __dentry_open(tx_cache_get_dentry(dget(dentry)), mntget(nd->mnt), nd->intent.open.flags - 1, nd->intent.open.file, open); out: return nd->intent.open.file; out_err: release_open_intent(nd); nd->intent.open.file = (struct file *)dentry; goto out; }
/** * fill_read_buffer - allocate and fill buffer from item. * @dentry: dentry pointer. * @buffer: data buffer for file. * * Allocate @buffer->page, if it hasn't been already, then call the * config_item's show() method to fill the buffer with this attribute's * data. * This is called only once, on the file's first read. */ static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buffer) { struct configfs_attribute * attr = to_attr(dentry); struct config_item * item = to_item(tx_cache_get_dentry(dentry)->d_parent); struct configfs_item_operations * ops = buffer->ops; int ret = 0; ssize_t count; if (!buffer->page) buffer->page = (char *) get_zeroed_page(GFP_KERNEL); if (!buffer->page) return -ENOMEM; count = ops->show_attribute(item,attr,buffer->page); buffer->needs_read_fill = 0; BUG_ON(count > (ssize_t)PAGE_SIZE); if (count >= 0) buffer->count = count; else ret = count; return ret; }
/* * Generic function to fsync a file. * * filp may be NULL if called via the msync of a vma. */ int file_fsync(struct file *filp, struct dentry *dentry, int datasync) { struct inode * inode = tx_cache_get_dentry(dentry)->d_inode; struct super_block * sb; int ret, err; /* sync the inode to buffers */ ret = write_inode_now(inode, 0); /* sync the superblock to buffers */ sb = tx_cache_get_inode_ro(inode)->i_sb; lock_super(sb); if (sb->s_op->write_super) sb->s_op->write_super(sb); unlock_super(sb); /* .. finally sync the buffers to disk */ err = sync_blockdev(sb->s_bdev); if (!ret) ret = err; return ret; }
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; }
/** * 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; }
int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, enum autofs_notify notify) { struct autofs_info *ino; struct autofs_wait_queue *wq; char *name; unsigned int len = 0; unsigned int hash = 0; int status, type; /* In catatonic mode, we don't wait for nobody */ if (sbi->catatonic) return -ENOENT; name = kmalloc(NAME_MAX + 1, GFP_KERNEL); if (!name) return -ENOMEM; /* If this is a direct mount request create a dummy name */ if (IS_ROOT(tx_cache_get_dentry(dentry)) && (sbi->type & AUTOFS_TYPE_DIRECT)) len = sprintf(name, "%p", dentry); else { len = autofs4_getpath(sbi, dentry, &name); if (!len) { kfree(name); return -ENOENT; } } hash = full_name_hash(name, len); if (mutex_lock_interruptible(&sbi->wq_mutex)) { kfree(name); return -EINTR; } wq = autofs4_find_wait(sbi, name, hash, len); ino = autofs4_dentry_ino(dentry); if (!wq && ino && notify == NFY_NONE) { /* * Either we've betean the pending expire to post it's * wait or it finished while we waited on the mutex. * So we need to wait till either, the wait appears * or the expire finishes. */ while (ino->flags & AUTOFS_INF_EXPIRING) { mutex_unlock(&sbi->wq_mutex); schedule_timeout_interruptible(HZ/10); if (mutex_lock_interruptible(&sbi->wq_mutex)) { kfree(name); return -EINTR; } wq = autofs4_find_wait(sbi, name, hash, len); if (wq) break; } /* * Not ideal but the status has already gone. Of the two * cases where we wait on NFY_NONE neither depend on the * return status of the wait. */ if (!wq) { kfree(name); mutex_unlock(&sbi->wq_mutex); return 0; } } if (!wq) { /* Create a new wait queue */ wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); if (!wq) { kfree(name); mutex_unlock(&sbi->wq_mutex); return -ENOMEM; } wq->wait_queue_token = autofs4_next_wait_queue; if (++autofs4_next_wait_queue == 0) autofs4_next_wait_queue = 1; wq->next = sbi->queues; sbi->queues = wq; init_waitqueue_head(&wq->queue); wq->hash = hash; wq->name = name; wq->len = len; wq->dev = autofs4_get_dev(sbi); wq->ino = autofs4_get_ino(sbi); wq->uid = current->uid; wq->gid = current->gid; wq->pid = current->pid; wq->tgid = current->tgid; wq->status = -EINTR; /* Status return if interrupted */ atomic_set(&wq->wait_ctr, 2); mutex_unlock(&sbi->wq_mutex); if (sbi->version < 5) { if (notify == NFY_MOUNT) type = autofs_ptype_missing; else type = autofs_ptype_expire_multi; } else { if (notify == NFY_MOUNT) type = (sbi->type & AUTOFS_TYPE_DIRECT) ? autofs_ptype_missing_direct : autofs_ptype_missing_indirect; else type = (sbi->type & AUTOFS_TYPE_DIRECT) ? autofs_ptype_expire_direct : autofs_ptype_expire_indirect; } DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n", (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); /* autofs4_notify_daemon() may block */ autofs4_notify_daemon(sbi, wq, type); } else { atomic_inc(&wq->wait_ctr); mutex_unlock(&sbi->wq_mutex); kfree(name); DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); } /* wq->name is NULL if and only if the lock is already released */ if (sbi->catatonic) { /* We might have slept, so check again for catatonic mode */ wq->status = -ENOENT; kfree(wq->name); wq->name = NULL; } if (wq->name) { /* Block all but "shutdown" signals while waiting */ sigset_t oldset; unsigned long irqflags; spin_lock_irqsave(¤t->sighand->siglock, irqflags); oldset = current->blocked; siginitsetinv(¤t->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]); recalc_sigpending(); spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); wait_event_interruptible(wq->queue, wq->name == NULL); spin_lock_irqsave(¤t->sighand->siglock, irqflags); current->blocked = oldset; recalc_sigpending(); spin_unlock_irqrestore(¤t->sighand->siglock, irqflags); } else { DPRINTK("skipped sleeping"); } status = wq->status; /* Are we the last process to need status? */ if (atomic_dec_and_test(&wq->wait_ctr)) kfree(wq); return status; }