/* afs_put_super * Called from unmount to release super_block. */ static void afs_put_super(struct super_block *sbp) { AFS_GLOCK(); AFS_STATCNT(afs_unmount); afs_globalVFS = 0; afs_globalVp = 0; afs_shutdown(); mntput(afs_cacheMnt); osi_linux_verify_alloced_memory(); #if defined(HAVE_LINUX_BDI_INIT) bdi_destroy(afs_backing_dev_info); #endif kfree(afs_backing_dev_info); AFS_GUNLOCK(); sbp->s_dev = 0; module_put(THIS_MODULE); }
/* * 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, const struct cred *cred) { int error; struct file *f; validate_creds(cred); /* We must always pass in a valid mount pointer. */ BUG_ON(!mnt); error = -ENFILE; f = get_empty_filp(); if (f == NULL) { dput(dentry); mntput(mnt); return ERR_PTR(error); } f->f_flags = flags; return __dentry_open(dentry, mnt, f, NULL, cred); }
/** * ptm_open_peer - open the peer of a pty * @master: the open struct file of the ptmx device node * @tty: the master of the pty being opened * @flags: the flags for open * * Provide a race free way for userspace to open the slave end of a pty * (where they have the master fd and cannot access or trust the mount * namespace /dev/pts was mounted inside). */ int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags) { int fd = -1; struct file *filp; int retval = -EINVAL; struct path path; if (tty->driver != ptm_driver) return -EIO; fd = get_unused_fd_flags(flags); if (fd < 0) { retval = fd; goto err; } /* Compute the slave's path */ path.mnt = devpts_mntget(master, tty->driver_data); if (IS_ERR(path.mnt)) { retval = PTR_ERR(path.mnt); goto err_put; } path.dentry = tty->link->driver_data; filp = dentry_open(&path, flags, current_cred()); mntput(path.mnt); if (IS_ERR(filp)) { retval = PTR_ERR(filp); goto err_put; } fd_install(fd, filp); return fd; err_put: put_unused_fd(fd); err: return retval; }
static int acct_on(char *name) { struct file *file; struct _file *_file; int error; /* Difference from BSD - they don't do O_APPEND */ file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0); if (IS_ERR(file)) return PTR_ERR(file); _file = tx_cache_get_file(file); if (!S_ISREG(d_get_inode(f_get_dentry_ro(_file))->i_mode)) { filp_close(file, NULL); return -EACCES; } if (!file->f_op->write) { filp_close(file, NULL); return -EIO; } error = security_acct(file); if (error) { filp_close(file, NULL); return error; } spin_lock(&acct_globals.lock); mnt_pin(_file->f_path.mnt); acct_file_reopen(file); spin_unlock(&acct_globals.lock); mntput(_file->f_path.mnt); /* it's pinned, now give up active reference */ return 0; }
/* afs_put_super * Called from unmount to release super_block. */ static void afs_put_super(struct super_block *sbp) { AFS_GLOCK(); AFS_STATCNT(afs_unmount); afs_globalVFS = 0; afs_globalVp = 0; osi_linux_free_inode_pages(); /* invalidate and release remaining AFS inodes. */ afs_shutdown(); mntput(afs_cacheMnt); osi_linux_verify_alloced_memory(); #if defined(HAVE_LINUX_BDI_INIT) bdi_destroy(afs_backing_dev_info); #endif osi_Free(afs_backing_dev_info, sizeof(struct backing_dev_info)); AFS_GUNLOCK(); sbp->s_dev = 0; module_put(THIS_MODULE); }
/* the real guts of fput() - releasing the last reference to file */ static void __fput(struct file *file) { struct dentry *dentry = file->f_path.dentry; struct vfsmount *mnt = file->f_path.mnt; struct inode *inode = dentry->d_inode; might_sleep(); fsnotify_close(file); /* * The function eventpoll_release() should be the first called * in the file cleanup chain. */ eventpoll_release(file); locks_remove_flock(file); if (unlikely(file->f_flags & FASYNC)) { if (file->f_op && file->f_op->fasync) file->f_op->fasync(-1, file, 0); } if (file->f_op && file->f_op->release) file->f_op->release(inode, file); security_file_free(file); ima_file_free(file); if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) cdev_put(inode->i_cdev); fops_put(file->f_op); put_pid(file->f_owner.pid); file_sb_list_del(file); if (file->f_mode & FMODE_WRITE) drop_file_write_access(file); file->f_path.dentry = NULL; file->f_path.mnt = NULL; file_free(file); dput(dentry); mntput(mnt); }
/** * \<\<public\>\> Releases the root directory and then the mount * object. VFS takes care of releasing the object in case their * reference count reaches 0. We need to take care of setting the * vfs_mnt to NULL. * * The last 2 steps don't need to be semaphore protected as we are * working on copies of both pointers and we wanted to protect the * access to vfs_mnt only. If anybody tries to get a root from now on * a new VFS mount will be created. If the root directory has been * also destroyed, the read_super method takes care of instantiating a * new super block along with the root directory. */ void tcmi_ctlfs_put_root(void) { struct vfsmount *cur_vfs_mnt; struct tcmi_ctlfs_entry *cur_root_dir; mdbg(INFO3, "sb c_count=%d, s_active=%d", self.sb->s_count, atomic_read(&self.sb->s_active)); mdbg(INFO3, "mount mnt_count=%d", atomic_read(&self.vfs_mnt->mnt_count)); /* mdbg(INFO3, "root d_count=%d", atomic_read(&self.root_dir->super.dentry->d_count));*/ down(&self.vfs_mnt_sem); cur_vfs_mnt = self.vfs_mnt; cur_root_dir = self.root_dir; /* If we are the last thread accesing the kernel mount */ if (atomic_read(&self.vfs_mnt->mnt_count) == 1) self.vfs_mnt = NULL; up(&self.vfs_mnt_sem); /* no locking needed since working on copies of both * pointers */ tcmi_ctlfs_entry_put(cur_root_dir); mntput(cur_vfs_mnt); }
/* * free a single branch */ static void au_br_do_free(struct au_branch *br) { int i; struct au_wbr *wbr; struct au_dykey **key; au_hnotify_fin_br(br); if (br->br_xino.xi_file) fput(br->br_xino.xi_file); mutex_destroy(&br->br_xino.xi_nondir_mtx); AuDebugOn(atomic_read(&br->br_count)); wbr = br->br_wbr; if (wbr) { for (i = 0; i < AuBrWh_Last; i++) dput(wbr->wbr_wh[i]); AuDebugOn(atomic_read(&wbr->wbr_wh_running)); AuRwDestroy(&wbr->wbr_wh_rwsem); } key = br->br_dykey; for (i = 0; i < AuBrDynOp; i++, key++) if (*key) au_dy_put(*key); else break; /* recursive lock, s_umount of branch's */ lockdep_off(); mntput(br->br_mnt); lockdep_on(); kfree(wbr); kfree(br); }
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, struct file *f, int (*open)(struct inode *, struct file *), const struct cred *cred) { static const struct file_operations empty_fops = {}; struct inode *inode; int error; f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; if (unlikely(f->f_flags & O_PATH)) f->f_mode = FMODE_PATH; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = __get_file_write_access(inode, mnt); if (error) goto cleanup_file; if (!special_file(inode->i_mode)) file_take_write(f); } f->f_mapping = inode->i_mapping; f->f_path.dentry = dentry; f->f_path.mnt = mnt; f->f_pos = 0; file_sb_list_add(f, inode->i_sb); if (unlikely(f->f_mode & FMODE_PATH)) { f->f_op = &empty_fops; return f; } f->f_op = fops_get(inode->i_fop); error = security_dentry_open(f, cred); if (error) goto cleanup_all; error = break_lease(inode, f->f_flags); if (error) goto cleanup_all; if (!open && f->f_op) open = f->f_op->open; if (open) { error = open(inode, f); if (error) goto cleanup_all; } if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(inode); f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); file_ra_state_init(&f->f_ra, 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_mem))) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) { put_write_access(inode); if (!special_file(inode->i_mode)) { /* * We don't consider this a real * mnt_want/drop_write() pair * because it all happenend right * here, so just reset the state. */ file_reset_write(f); mnt_drop_write(mnt); } } file_sb_list_del(f); f->f_path.dentry = NULL; f->f_path.mnt = NULL; cleanup_file: put_filp(f); dput(dentry); mntput(mnt); return ERR_PTR(error); }
void pid_ns_release_proc(struct pid_namespace *ns) { mntput(ns->proc_mnt); }
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); }
/* * add a cache */ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) { struct cachefiles_object *fsdef; struct path path; struct kstatfs stats; struct dentry *graveyard, *cachedir, *root; const struct cred *saved_cred; int ret; _enter(""); /* we want to work under the module's security ID */ ret = cachefiles_get_security_ID(cache); if (ret < 0) return ret; cachefiles_begin_secure(cache, &saved_cred); /* allocate the root index object */ ret = -ENOMEM; fsdef = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL); if (!fsdef) goto error_root_object; ASSERTCMP(fsdef->backer, ==, NULL); atomic_set(&fsdef->usage, 1); fsdef->type = FSCACHE_COOKIE_TYPE_INDEX; _debug("- fsdef %p", fsdef); /* look up the directory at the root of the cache */ ret = kern_path(cache->rootdirname, LOOKUP_DIRECTORY, &path); if (ret < 0) goto error_open_root; cache->mnt = path.mnt; root = path.dentry; /* check parameters */ ret = -EOPNOTSUPP; if (!root->d_inode || !root->d_inode->i_op->lookup || !root->d_inode->i_op->mkdir || !root->d_inode->i_op->setxattr || !root->d_inode->i_op->getxattr || !root->d_sb->s_op->statfs || !root->d_sb->s_op->sync_fs) goto error_unsupported; ret = -EROFS; if (root->d_sb->s_flags & MS_RDONLY) goto error_unsupported; /* determine the security of the on-disk cache as this governs * security ID of files we create */ ret = cachefiles_determine_cache_security(cache, root, &saved_cred); if (ret < 0) goto error_unsupported; /* get the cache size and blocksize */ ret = vfs_statfs(&path, &stats); if (ret < 0) goto error_unsupported; ret = -ERANGE; if (stats.f_bsize <= 0) goto error_unsupported; ret = -EOPNOTSUPP; if (stats.f_bsize > PAGE_SIZE) goto error_unsupported; cache->bsize = stats.f_bsize; cache->bshift = 0; if (stats.f_bsize < PAGE_SIZE) cache->bshift = PAGE_SHIFT - ilog2(stats.f_bsize); _debug("blksize %u (shift %u)", cache->bsize, cache->bshift); _debug("size %llu, avail %llu", (unsigned long long) stats.f_blocks, (unsigned long long) stats.f_bavail); /* set up caching limits */ do_div(stats.f_files, 100); cache->fstop = stats.f_files * cache->fstop_percent; cache->fcull = stats.f_files * cache->fcull_percent; cache->frun = stats.f_files * cache->frun_percent; _debug("limits {%llu,%llu,%llu} files", (unsigned long long) cache->frun, (unsigned long long) cache->fcull, (unsigned long long) cache->fstop); stats.f_blocks >>= cache->bshift; do_div(stats.f_blocks, 100); cache->bstop = stats.f_blocks * cache->bstop_percent; cache->bcull = stats.f_blocks * cache->bcull_percent; cache->brun = stats.f_blocks * cache->brun_percent; _debug("limits {%llu,%llu,%llu} blocks", (unsigned long long) cache->brun, (unsigned long long) cache->bcull, (unsigned long long) cache->bstop); /* get the cache directory and check its type */ cachedir = cachefiles_get_directory(cache, root, "cache"); if (IS_ERR(cachedir)) { ret = PTR_ERR(cachedir); goto error_unsupported; } fsdef->dentry = cachedir; fsdef->fscache.cookie = NULL; ret = cachefiles_check_object_type(fsdef); if (ret < 0) goto error_unsupported; /* get the graveyard directory */ graveyard = cachefiles_get_directory(cache, root, "graveyard"); if (IS_ERR(graveyard)) { ret = PTR_ERR(graveyard); goto error_unsupported; } cache->graveyard = graveyard; /* publish the cache */ fscache_init_cache(&cache->cache, &cachefiles_cache_ops, "%s", fsdef->dentry->d_sb->s_id); fscache_object_init(&fsdef->fscache, NULL, &cache->cache); ret = fscache_add_cache(&cache->cache, &fsdef->fscache, cache->tag); if (ret < 0) goto error_add_cache; /* done */ set_bit(CACHEFILES_READY, &cache->flags); dput(root); pr_info("File cache on %s registered\n", cache->cache.identifier); /* check how much space the cache has */ cachefiles_has_space(cache, 0, 0); cachefiles_end_secure(cache, saved_cred); return 0; error_add_cache: dput(cache->graveyard); cache->graveyard = NULL; error_unsupported: mntput(cache->mnt); cache->mnt = NULL; dput(fsdef->dentry); fsdef->dentry = NULL; dput(root); error_open_root: kmem_cache_free(cachefiles_object_jar, fsdef); error_root_object: cachefiles_end_secure(cache, saved_cred); pr_err("Failed to register: %d\n", ret); return ret; }
/* * nfs_follow_mountpoint - handle crossing a mountpoint on the server * @dentry - dentry of mountpoint * @nd - nameidata info * * When we encounter a mountpoint on the server, we want to set up * a mountpoint on the client too, to prevent inode numbers from * colliding, and to allow "df" to work properly. * On NFSv4, we also want to allow for the fact that different * filesystems may be migrated to different servers in a failover * situation, and that different filesystems may want to use * different security flavours. */ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) { struct vfsmount *mnt; struct nfs_server *server = NFS_SERVER(dentry->d_inode); struct dentry *parent; struct nfs_fh fh; struct nfs_fattr fattr; int err; dprintk("--> nfs_follow_mountpoint()\n"); err = -ESTALE; if (IS_ROOT(dentry)) goto out_err; dprintk("%s: enter\n", __func__); dput(nd->path.dentry); nd->path.dentry = dget(dentry); /* Look it up again */ parent = dget_parent(nd->path.dentry); err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &nd->path.dentry->d_name, &fh, &fattr); dput(parent); if (err != 0) goto out_err; if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry); else mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, &fh, &fattr); err = PTR_ERR(mnt); if (IS_ERR(mnt)) goto out_err; mntget(mnt); err = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags|MNT_SHRINKABLE, &nfs_automount_list); if (err < 0) { mntput(mnt); if (err == -EBUSY) goto out_follow; goto out_err; } path_put(&nd->path); nd->path.mnt = mnt; nd->path.dentry = dget(mnt->mnt_root); schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); out: dprintk("%s: done, returned %d\n", __func__, err); dprintk("<-- nfs_follow_mountpoint() = %d\n", err); return ERR_PTR(err); out_err: path_put(&nd->path); goto out; out_follow: while (d_mountpoint(nd->path.dentry) && follow_down(&nd->path.mnt, &nd->path.dentry)) ; err = 0; goto out; }
/** * ecryptfs_open * @inode: inode speciying file to open * @file: Structure to return filled in * * Opens the file specified by inode. * * Returns zero on success; non-zero otherwise */ static int ecryptfs_open(struct inode *inode, struct file *file) { int rc = 0; struct ecryptfs_crypt_stat *crypt_stat = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct dentry *ecryptfs_dentry = file->f_path.dentry; /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); struct inode *lower_inode = NULL; struct file *lower_file = NULL; struct vfsmount *lower_mnt; struct ecryptfs_file_info *file_info; int lower_flags; /* Released in ecryptfs_release or end of function if failure */ file_info = kmem_cache_alloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); if (!file_info) { ecryptfs_printk(KERN_ERR, "Error attempting to allocate memory\n"); rc = -ENOMEM; goto out; } memset(file_info, 0, sizeof(*file_info)); lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; mutex_lock(&crypt_stat->cs_mutex); if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) { ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); /* Policy code enabled in future release */ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED); ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); lower_flags = file->f_flags; if ((lower_flags & O_ACCMODE) == O_WRONLY) lower_flags = (lower_flags & O_ACCMODE) | O_RDWR; if (file->f_flags & O_APPEND) lower_flags &= ~O_APPEND; lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); /* Corresponding fput() in ecryptfs_release() */ if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt, lower_flags))) { ecryptfs_printk(KERN_ERR, "Error opening lower file\n"); goto out_puts; } ecryptfs_set_file_lower(file, lower_file); /* Isn't this check the same as the one in lookup? */ lower_inode = lower_dentry->d_inode; if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); rc = 0; goto out; } mutex_lock(&crypt_stat->cs_mutex); if (i_size_read(lower_inode) < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) { if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; printk(KERN_WARNING "Attempt to read file that is " "not in a valid eCryptfs format, and plaintext " "passthrough mode is not enabled; returning " "-EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); goto out_puts; } crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); rc = 0; mutex_unlock(&crypt_stat->cs_mutex); goto out; } else if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED) || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID)) { rc = ecryptfs_read_headers(ecryptfs_dentry, lower_file); if (rc) { ecryptfs_printk(KERN_DEBUG, "Valid headers not found\n"); if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; printk(KERN_WARNING "Attempt to read file that " "is not in a valid eCryptfs format, " "and plaintext passthrough mode is not " "enabled; returning -EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); goto out_puts; } ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); rc = 0; mutex_unlock(&crypt_stat->cs_mutex); goto out; } } mutex_unlock(&crypt_stat->cs_mutex); ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] " "size: [0x%.16x]\n", inode, inode->i_ino, i_size_read(inode)); ecryptfs_set_file_lower(file, lower_file); goto out; out_puts: mntput(lower_mnt); dput(lower_dentry); kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); out: return rc; }
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags, struct file *f) { struct inode *inode; static LIST_HEAD(kill_list); int error; f->f_flags = flags; f->f_mode = (flags+1) & O_ACCMODE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_file; } f->f_dentry = dentry; f->f_vfsmnt = mnt; f->f_pos = 0; f->f_reada = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_sb->s_files); /* preallocate kiobuf for O_DIRECT */ f->f_iobuf = NULL; f->f_iobuf_lock = 0; if (f->f_flags & O_DIRECT) { error = alloc_kiovec(1, &f->f_iobuf); if (error) goto cleanup_all; } if (f->f_op && f->f_op->open) { error = f->f_op->open(inode,f); if (error) goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); /* NB: we're sure to have correct a_ops only after f_op->open */ if (f->f_flags & O_DIRECT) { if (!inode->i_mapping || !inode->i_mapping->a_ops || !(inode->i_mapping->a_ops->direct_IO || inode->i_mapping->a_ops->direct_sector_IO)) { fput(f); f = ERR_PTR(-EINVAL); } } return f; cleanup_all: if (f->f_iobuf) free_kiovec(1, &f->f_iobuf); fops_put(f->f_op); if (f->f_mode & FMODE_WRITE) put_write_access(inode); file_move(f, &kill_list); /* out of the way.. */ f->f_dentry = NULL; f->f_vfsmnt = NULL; cleanup_file: put_filp(f); dput(dentry); mntput(mnt); return ERR_PTR(error); }
/* * Object creation/destruction. */ LinuxSystemRoot* newLinuxSystemRoot(void) { LinuxSystemRoot* object; unsigned m_seq = 0; object = talpa_alloc(sizeof(template_LinuxSystemRoot)); if ( object ) { struct task_struct* inittask; memcpy(object, &template_LinuxSystemRoot, sizeof(template_LinuxSystemRoot)); object->i_ISystemRoot.object = object; talpa_tasklist_lock(); inittask = talpa_find_task_by_pid(1); talpa_tasklist_unlock(); if ( inittask ) { struct fs_struct *init_fs; struct vfsmount *rootmnt; task_lock(inittask); init_fs = inittask->fs; if ( init_fs ) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) spin_lock(&init_fs->lock); #else write_lock(&init_fs->lock); #endif init_fs->users++; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) spin_unlock(&init_fs->lock); #else write_unlock(&init_fs->lock); #endif #else atomic_inc(&init_fs->count); #endif } task_unlock(inittask); if ( init_fs ) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) spin_lock(&init_fs->lock); #else write_lock(&init_fs->lock); #endif restart_mnt: talpa_vfsmount_lock(&m_seq); // locks dcache_lock on 2.4 for (rootmnt = talpa_fs_mnt(init_fs); rootmnt != getParent(rootmnt); rootmnt = getParent(rootmnt)); object->mMnt = mntget(rootmnt); object->mDentry = dget(rootmnt->mnt_root); if (talpa_vfsmount_unlock(&m_seq)) // unlocks dcache_lock on 2.4 { goto restart_mnt; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) init_fs->users--; #else atomic_dec(&init_fs->count); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) spin_unlock(&init_fs->lock); #else write_unlock(&init_fs->lock); #endif } } if ( !object->mMnt || !object->mDentry ) { if ( object->mMnt ) { mntput(object->mMnt); } if ( object->mDentry ) { dput(object->mDentry); } talpa_free(object); return NULL; } } return object; }
/* This must be called with the super block already locked. */ int unionfs_ioctl_delbranch(struct super_block *sb, unsigned long arg) { struct dentry *hidden_dentry; struct inode *hidden_inode; struct super_block *hidden_sb; struct vfsmount *hidden_mnt; struct dentry *root_dentry; struct inode *root_inode; int err = 0; int pmindex, i, gen; print_entry("branch = %lu ", arg); lock_dentry(sb->s_root); err = -EBUSY; if (sbmax(sb) == 1) goto out; err = -EINVAL; if (arg < 0 || arg > stopd(sb)->b_end) goto out; err = -EBUSY; if (branch_count(sb, arg)) goto out; if ((err = newputmap(sb))) goto out; pmindex = stopd(sb)->usi_lastputmap; pmindex -= stopd(sb)->usi_firstputmap; atomic_inc(&stopd(sb)->usi_generation); gen = atomic_read(&stopd(sb)->usi_generation); root_dentry = sb->s_root; root_inode = sb->s_root->d_inode; hidden_dentry = dtohd_index(root_dentry, arg); hidden_mnt = stohiddenmnt_index(sb, arg); hidden_inode = itohi_index(root_inode, arg); hidden_sb = stohs_index(sb, arg); DPUT(hidden_dentry); iput(hidden_inode); mntput(hidden_mnt); for (i = arg; i <= (sbend(sb) - 1); i++) { set_branch_count(sb, i, branch_count(sb, i + 1)); set_stohiddenmnt_index(sb, i, stohiddenmnt_index(sb, i + 1)); set_stohs_index(sb, i, stohs_index(sb, i + 1)); set_branchperms(sb, i, branchperms(sb, i + 1)); set_dtohd_index(root_dentry, i, dtohd_index(root_dentry, i + 1)); set_itohi_index(root_inode, i, itohi_index(root_inode, i + 1)); stopd(sb)->usi_putmaps[pmindex]->map[i + 1] = i; } set_dtohd_index(root_dentry, sbend(sb), NULL); set_itohi_index(root_inode, sbend(sb), NULL); set_stohiddenmnt_index(sb, sbend(sb), NULL); set_stohs_index(sb, sbend(sb), NULL); stopd(sb)->b_end--; set_dbend(root_dentry, dbend(root_dentry) - 1); dtopd(root_dentry)->udi_bcount--; itopd(root_inode)->b_end--; atomic_set(&dtopd(root_dentry)->udi_generation, gen); atomic_set(&itopd(root_inode)->uii_generation, gen); fixputmaps(sb); /* This doesn't open a file, so we might have to free the map here. */ if (atomic_read(&stopd(sb)->usi_putmaps[pmindex]->count) == 0) { KFREE(stopd(sb)->usi_putmaps[pmindex]); stopd(sb)->usi_putmaps[pmindex] = NULL; } out: unlock_dentry(sb->s_root); print_exit_status(err); return err; }
static int ovl_fill_super(struct super_block *sb, void *data, int silent) { struct path lowerpath; struct path upperpath; struct path workpath; struct inode *root_inode; struct dentry *root_dentry; struct ovl_entry *oe; struct ovl_fs *ufs; struct kstatfs statfs; int err; err = -ENOMEM; ufs = kmalloc(sizeof(struct ovl_fs), GFP_KERNEL); if (!ufs) goto out; err = ovl_parse_opt((char *) data, &ufs->config); if (err) goto out_free_ufs; /* FIXME: workdir is not needed for a R/O mount */ err = -EINVAL; if (!ufs->config.upperdir || !ufs->config.lowerdir || !ufs->config.workdir) { pr_err("overlayfs: missing upperdir or lowerdir or workdir\n"); goto out_free_config; } oe = ovl_alloc_entry(); if (oe == NULL) goto out_free_config; err = ovl_mount_dir(ufs->config.upperdir, &upperpath); if (err) goto out_free_oe; err = ovl_mount_dir(ufs->config.lowerdir, &lowerpath); if (err) goto out_put_upperpath; err = ovl_mount_dir(ufs->config.workdir, &workpath); if (err) goto out_put_lowerpath; err = -EINVAL; if (!S_ISDIR(upperpath.dentry->d_inode->i_mode) || !S_ISDIR(lowerpath.dentry->d_inode->i_mode) || !S_ISDIR(workpath.dentry->d_inode->i_mode)) { pr_err("overlayfs: upperdir or lowerdir or workdir not a directory\n"); goto out_put_workpath; } if (upperpath.mnt != workpath.mnt) { pr_err("overlayfs: workdir and upperdir must reside under the same mount\n"); goto out_put_workpath; } if (upperpath.dentry == workpath.dentry || d_ancestor(upperpath.dentry, workpath.dentry) || d_ancestor(workpath.dentry, upperpath.dentry)) { pr_err("overlayfs: workdir and upperdir must be separate subtrees\n"); goto out_put_workpath; } err = vfs_statfs(&lowerpath, &statfs); if (err) { pr_err("overlayfs: statfs failed on lowerpath\n"); goto out_put_workpath; } ufs->lower_namelen = statfs.f_namelen; sb->s_stack_depth = max(upperpath.mnt->mnt_sb->s_stack_depth, lowerpath.mnt->mnt_sb->s_stack_depth) + 1; err = -EINVAL; if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { pr_err("overlayfs: maximum fs stacking depth exceeded\n"); goto out_put_lowerpath; } ufs->upper_mnt = clone_private_mount(&upperpath); err = PTR_ERR(ufs->upper_mnt); if (IS_ERR(ufs->upper_mnt)) { pr_err("overlayfs: failed to clone upperpath\n"); goto out_put_workpath; } ufs->lower_mnt = clone_private_mount(&lowerpath); err = PTR_ERR(ufs->lower_mnt); if (IS_ERR(ufs->lower_mnt)) { pr_err("overlayfs: failed to clone lowerpath\n"); goto out_put_upper_mnt; } ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); err = PTR_ERR(ufs->workdir); if (IS_ERR(ufs->workdir)) { pr_err("overlayfs: failed to create directory %s/%s\n", ufs->config.workdir, OVL_WORKDIR_NAME); goto out_put_lower_mnt; } /* * Make lower_mnt R/O. That way fchmod/fchown on lower file * will fail instead of modifying lower fs. */ ufs->lower_mnt->mnt_flags |= MNT_READONLY; /* If the upper fs is r/o, we mark overlayfs r/o too */ if (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY) sb->s_flags |= MS_RDONLY; err = -ENOMEM; root_inode = ovl_new_inode(sb, S_IFDIR, oe); if (!root_inode) goto out_put_workdir; root_dentry = d_make_root(root_inode); if (!root_dentry) goto out_put_workdir; mntput(upperpath.mnt); mntput(lowerpath.mnt); path_put(&workpath); oe->__upperdentry = dget(upperpath.dentry); oe->lowerdentry = lowerpath.dentry; root_dentry->d_fsdata = oe; root_dentry->d_op = &ovl_dentry_operations; sb->s_magic = OVERLAYFS_SUPER_MAGIC; sb->s_op = &ovl_super_operations; sb->s_root = root_dentry; sb->s_fs_info = ufs; return 0; out_put_workdir: dput(ufs->workdir); out_put_lower_mnt: mntput(ufs->lower_mnt); out_put_upper_mnt: mntput(ufs->upper_mnt); out_put_workpath: path_put(&workpath); out_put_lowerpath: path_put(&lowerpath); out_put_upperpath: path_put(&upperpath); out_free_oe: kfree(oe); out_free_config: kfree(ufs->config.lowerdir); kfree(ufs->config.upperdir); kfree(ufs->config.workdir); out_free_ufs: kfree(ufs); out: return err; }
/** * ecryptfs_lookup_and_interpose_lower - Perform a lookup */ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, struct dentry *lower_dentry, struct inode *ecryptfs_dir_inode, struct nameidata *ecryptfs_nd) { struct dentry *lower_dir_dentry; struct vfsmount *lower_mnt; struct inode *lower_inode; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct ecryptfs_crypt_stat *crypt_stat; char *page_virt = NULL; u64 file_size; int rc = 0; lower_dir_dentry = lower_dentry->d_parent; lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( ecryptfs_dentry->d_parent)); lower_inode = lower_dentry->d_inode; fsstack_copy_attr_atime(ecryptfs_dir_inode, lower_dir_dentry->d_inode); BUG_ON(!atomic_read(&lower_dentry->d_count)); ecryptfs_set_dentry_private(ecryptfs_dentry, kmem_cache_alloc(ecryptfs_dentry_info_cache, GFP_KERNEL)); if (!ecryptfs_dentry_to_private(ecryptfs_dentry)) { rc = -ENOMEM; printk(KERN_ERR "%s: Out of memory whilst attempting " "to allocate ecryptfs_dentry_info struct\n", __func__); goto out_put; } ecryptfs_set_dentry_lower(ecryptfs_dentry, lower_dentry); ecryptfs_set_dentry_lower_mnt(ecryptfs_dentry, lower_mnt); if (!lower_dentry->d_inode) { /* We want to add because we couldn't find in lower */ d_add(ecryptfs_dentry, NULL); goto out; } rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry, ecryptfs_dir_inode->i_sb, 1); if (rc) { printk(KERN_ERR "%s: Error interposing; rc = [%d]\n", __func__, rc); goto out; } if (S_ISDIR(lower_inode->i_mode)) goto out; if (S_ISLNK(lower_inode->i_mode)) goto out; if (special_file(lower_inode->i_mode)) goto out; if (!ecryptfs_nd) goto out; /* Released in this function */ page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, GFP_USER); if (!page_virt) { printk(KERN_ERR "%s: Cannot kmem_cache_zalloc() a page\n", __func__); rc = -ENOMEM; goto out; } if (!ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->lower_file) { rc = ecryptfs_init_persistent_file(ecryptfs_dentry); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the persistent file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out_free_kmem; } } crypt_stat = &ecryptfs_inode_to_private( ecryptfs_dentry->d_inode)->crypt_stat; /* TODO: lock for crypt_stat comparison */ if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) ecryptfs_set_default_sizes(crypt_stat); rc = ecryptfs_read_and_validate_header_region(page_virt, ecryptfs_dentry->d_inode); if (rc) { rc = ecryptfs_read_and_validate_xattr_region(page_virt, ecryptfs_dentry); if (rc) { rc = 0; goto out_free_kmem; } crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; } mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) file_size = (crypt_stat->num_header_bytes_at_front + i_size_read(lower_dentry->d_inode)); else file_size = i_size_read(lower_dentry->d_inode); } else { file_size = get_unaligned_be64(page_virt); } i_size_write(ecryptfs_dentry->d_inode, (loff_t)file_size); out_free_kmem: kmem_cache_free(ecryptfs_header_cache_2, page_virt); goto out; out_put: dput(lower_dentry); mntput(lower_mnt); d_drop(ecryptfs_dentry); out: return rc; }
void redirect_namei(struct nameidata *dest, const struct nameidata *src) { mntget(src->mnt); dget(src->dentry); mntput(dest->mnt); dput(dest->dentry); *dest = *src; }
static int dazukofs_fill_super(struct super_block *sb, void *data, int silent) { struct dazukofs_sb_info *sbi; struct dentry *root; static const struct qstr name = { .name = "/", .len = 1 }; struct dazukofs_dentry_info *di; sbi = kmem_cache_zalloc(dazukofs_sb_info_cachep, GFP_KERNEL); if (!sbi) return -ENOMEM; sb->s_op = &dazukofs_sops; root = d_alloc(NULL, &name); if (!root) { kmem_cache_free(dazukofs_sb_info_cachep, sbi); return -ENOMEM; } sb->s_root = root; sb->s_root->d_op = &dazukofs_dops; sb->s_root->d_sb = sb; sb->s_root->d_parent = sb->s_root; di = kmem_cache_zalloc(dazukofs_dentry_info_cachep, GFP_KERNEL); if (!di) { kmem_cache_free(dazukofs_sb_info_cachep, sbi); dput(sb->s_root); return -ENOMEM; } set_dentry_private(sb->s_root, di); set_sb_private(sb, sbi); return 0; } static int dazukofs_read_super(struct super_block *sb, const char *dev_name) { struct nameidata nd; struct dentry *lower_root; struct vfsmount *lower_mnt; int err; memset(&nd, 0, sizeof(struct nameidata)); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd.path); #else err = path_lookup(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd); #endif if (err) return err; lower_root = dget(nd.path.dentry); lower_mnt = mntget(nd.path.mnt); if (IS_ERR(lower_root)) { err = PTR_ERR(lower_root); goto out_put; } if (!lower_root->d_inode) { err = -ENOENT; goto out_put; } if (!S_ISDIR(lower_root->d_inode->i_mode)) { err = -EINVAL; goto out_put; } set_lower_sb(sb, lower_root->d_sb); sb->s_maxbytes = lower_root->d_sb->s_maxbytes; set_lower_dentry(sb->s_root, lower_root, lower_mnt); err = dazukofs_interpose(lower_root, sb->s_root, sb, 0); if (err) goto out_put; goto out; out_put: dput(lower_root); mntput(lower_mnt); out: path_put(&nd.path); return err; } // FIXME! #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) static struct dentry* dazukofs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return mount_nodev(fs_type, flags, data, dazukofs_fill_super); } #else static int dazukofs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { struct super_block *sb; int err; err = get_sb_nodev(fs_type, flags, data, dazukofs_fill_super, mnt); if (err) goto out; sb = mnt->mnt_sb; err = dazukofs_parse_mount_options(data, sb); if (err) goto out_abort; err = dazukofs_read_super(sb, dev_name); if (err) goto out_abort; goto out; out_abort: dput(sb->s_root); up_write(&sb->s_umount); deactivate_super(sb); out: return err; } #endif static void init_once(void *data) { struct dazukofs_inode_info *inode_info = (struct dazukofs_inode_info *)data; memset(inode_info, 0, sizeof(struct dazukofs_inode_info)); inode_init_once(&(inode_info->vfs_inode)); } static void destroy_caches(void) { if (dazukofs_inode_info_cachep) { kmem_cache_destroy(dazukofs_inode_info_cachep); dazukofs_inode_info_cachep = NULL; } if (dazukofs_sb_info_cachep) { kmem_cache_destroy(dazukofs_sb_info_cachep); dazukofs_sb_info_cachep = NULL; } if (dazukofs_dentry_info_cachep) { kmem_cache_destroy(dazukofs_dentry_info_cachep); dazukofs_dentry_info_cachep = NULL; } if (dazukofs_file_info_cachep) { kmem_cache_destroy(dazukofs_file_info_cachep); dazukofs_file_info_cachep = NULL; } } static int init_caches(void) { dazukofs_inode_info_cachep = kmem_cache_create("dazukofs_inode_info_cache", sizeof(struct dazukofs_inode_info), 0, SLAB_HWCACHE_ALIGN, init_once); if (!dazukofs_inode_info_cachep) goto out_nomem; dazukofs_sb_info_cachep = kmem_cache_create("dazukofs_sb_info_cache", sizeof(struct dazukofs_sb_info), 0, SLAB_HWCACHE_ALIGN, NULL); if (!dazukofs_sb_info_cachep) goto out_nomem; dazukofs_dentry_info_cachep = kmem_cache_create("dazukofs_dentry_info_cache", sizeof(struct dazukofs_dentry_info), 0, SLAB_HWCACHE_ALIGN, NULL); if (!dazukofs_dentry_info_cachep) goto out_nomem; dazukofs_file_info_cachep = kmem_cache_create("dazukofs_file_info_cache", sizeof(struct dazukofs_file_info), 0, SLAB_HWCACHE_ALIGN, NULL); if (!dazukofs_file_info_cachep) goto out_nomem; return 0; out_nomem: destroy_caches(); return -ENOMEM; }
/** * ecryptfs_lookup_and_interpose_lower - Perform a lookup */ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, struct dentry *lower_dentry, struct inode *ecryptfs_dir_inode) { struct dentry *lower_dir_dentry; struct vfsmount *lower_mnt; struct inode *lower_inode; struct ecryptfs_crypt_stat *crypt_stat; char *page_virt = NULL; int put_lower = 0, rc = 0; lower_dir_dentry = lower_dentry->d_parent; lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( ecryptfs_dentry->d_parent)); lower_inode = lower_dentry->d_inode; fsstack_copy_attr_atime(ecryptfs_dir_inode, lower_dir_dentry->d_inode); BUG_ON(!lower_dentry->d_count); ecryptfs_set_dentry_private(ecryptfs_dentry, kmem_cache_alloc(ecryptfs_dentry_info_cache, GFP_KERNEL)); if (!ecryptfs_dentry_to_private(ecryptfs_dentry)) { rc = -ENOMEM; printk(KERN_ERR "%s: Out of memory whilst attempting " "to allocate ecryptfs_dentry_info struct\n", __func__); goto out_put; } ecryptfs_set_dentry_lower(ecryptfs_dentry, lower_dentry); ecryptfs_set_dentry_lower_mnt(ecryptfs_dentry, lower_mnt); if (!lower_dentry->d_inode) { /* We want to add because we couldn't find in lower */ d_add(ecryptfs_dentry, NULL); goto out; } rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry, ecryptfs_dir_inode->i_sb, ECRYPTFS_INTERPOSE_FLAG_D_ADD); if (rc) { printk(KERN_ERR "%s: Error interposing; rc = [%d]\n", __func__, rc); goto out; } if (S_ISDIR(lower_inode->i_mode)) goto out; if (S_ISLNK(lower_inode->i_mode)) goto out; if (special_file(lower_inode->i_mode)) goto out; /* Released in this function */ page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, GFP_USER); if (!page_virt) { printk(KERN_ERR "%s: Cannot kmem_cache_zalloc() a page\n", __func__); rc = -ENOMEM; goto out; } rc = ecryptfs_get_lower_file(ecryptfs_dentry); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out_free_kmem; } put_lower = 1; crypt_stat = &ecryptfs_inode_to_private( ecryptfs_dentry->d_inode)->crypt_stat; /* TODO: lock for crypt_stat comparison */ if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) ecryptfs_set_default_sizes(crypt_stat); rc = ecryptfs_read_and_validate_header_region(page_virt, ecryptfs_dentry->d_inode); if (rc) { memset(page_virt, 0, PAGE_CACHE_SIZE); rc = ecryptfs_read_and_validate_xattr_region(page_virt, ecryptfs_dentry); if (rc) { rc = 0; goto out_free_kmem; } crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; } ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode); out_free_kmem: kmem_cache_free(ecryptfs_header_cache_2, page_virt); goto out; out_put: dput(lower_dentry); mntput(lower_mnt); d_drop(ecryptfs_dentry); out: if (put_lower) ecryptfs_put_lower_file(ecryptfs_dentry->d_inode); return rc; }
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; f->f_flags = flags; f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); if (error) goto cleanup_file; } f->f_mapping = inode->i_mapping; f->f_path.dentry = dentry; f->f_path.mnt = mnt; f->f_pos = 0; f->f_op = fops_get(inode->i_fop); file_move(f, &inode->i_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, 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(inode); file_kill(f); f->f_path.dentry = NULL; f->f_path.mnt = NULL; cleanup_file: put_filp(f); dput(dentry); mntput(mnt); return ERR_PTR(error); }
/*mds still need lov setup here*/ static int mds_cmd_setup(struct obd_device *obd, struct lustre_cfg *lcfg) { struct mds_obd *mds = &obd->u.mds; struct lvfs_run_ctxt saved; const char *dev; struct vfsmount *mnt; struct lustre_sb_info *lsi; struct lustre_mount_info *lmi; struct dentry *dentry; int rc = 0; ENTRY; CDEBUG(D_INFO, "obd %s setup \n", obd->obd_name); if (strncmp(obd->obd_name, MDD_OBD_NAME, strlen(MDD_OBD_NAME))) RETURN(0); if (lcfg->lcfg_bufcount < 5) { CERROR("invalid arg for setup %s\n", MDD_OBD_NAME); RETURN(-EINVAL); } dev = lustre_cfg_string(lcfg, 4); lmi = server_get_mount(dev); LASSERT(lmi != NULL); lsi = s2lsi(lmi->lmi_sb); mnt = lmi->lmi_mnt; /* FIXME: MDD LOV initialize objects. * we need only lmi here but not get mount * OSD did mount already, so put mount back */ cfs_atomic_dec(&lsi->lsi_mounts); mntput(mnt); cfs_init_rwsem(&mds->mds_notify_lock); obd->obd_fsops = fsfilt_get_ops(MT_STR(lsi->lsi_ldd)); mds_init_ctxt(obd, mnt); push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); dentry = simple_mkdir(current->fs->pwd, mnt, "OBJECTS", 0777, 1); if (IS_ERR(dentry)) { rc = PTR_ERR(dentry); CERROR("cannot create OBJECTS directory: rc = %d\n", rc); GOTO(err_putfs, rc); } mds->mds_objects_dir = dentry; dentry = ll_lookup_one_len("__iopen__", current->fs->pwd, strlen("__iopen__")); if (IS_ERR(dentry)) { rc = PTR_ERR(dentry); CERROR("cannot lookup __iopen__ directory: rc = %d\n", rc); GOTO(err_objects, rc); } mds->mds_fid_de = dentry; if (!dentry->d_inode || is_bad_inode(dentry->d_inode)) { rc = -ENOENT; CERROR("__iopen__ directory has no inode? rc = %d\n", rc); GOTO(err_fid, rc); } rc = mds_lov_init_objids(obd); if (rc != 0) { CERROR("cannot init lov objid rc = %d\n", rc); GOTO(err_fid, rc ); } rc = mds_lov_presetup(mds, lcfg); if (rc < 0) GOTO(err_objects, rc); /* Don't wait for mds_postrecov trying to clear orphans */ obd->obd_async_recov = 1; rc = mds_postsetup(obd); /* Bug 11557 - allow async abort_recov start FIXME can remove most of this obd_async_recov plumbing obd->obd_async_recov = 0; */ if (rc) GOTO(err_objects, rc); err_pop: pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); RETURN(rc); err_fid: dput(mds->mds_fid_de); err_objects: dput(mds->mds_objects_dir); err_putfs: fsfilt_put_ops(obd->obd_fsops); goto err_pop; }
__be32 nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, unsigned int len, struct svc_export **exp_ret, struct dentry **dentry_ret) { struct svc_export *exp; struct dentry *dparent; struct dentry *dentry; __be32 err; int host_err; dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); /* Obtain dentry and export. */ err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC); if (err) return err; dparent = fhp->fh_dentry; exp = fhp->fh_export; exp_get(exp); /* Lookup the name, but don't follow links */ if (isdotent(name, len)) { if (len==1) dentry = dget(dparent); else if (dparent != exp->ex_path.dentry) dentry = dget_parent(dparent); else if (!EX_NOHIDE(exp)) dentry = dget(dparent); /* .. == . just like at / */ else { /* checking mountpoint crossing is very different when stepping up */ struct svc_export *exp2 = NULL; struct dentry *dp; struct vfsmount *mnt = mntget(exp->ex_path.mnt); dentry = dget(dparent); while(dentry == mnt->mnt_root && follow_up(&mnt, &dentry)) ; dp = dget_parent(dentry); dput(dentry); dentry = dp; exp2 = rqst_exp_parent(rqstp, mnt, dentry); if (PTR_ERR(exp2) == -ENOENT) { dput(dentry); dentry = dget(dparent); } else if (IS_ERR(exp2)) { host_err = PTR_ERR(exp2); dput(dentry); mntput(mnt); goto out_nfserr; } else { exp_put(exp); exp = exp2; } mntput(mnt); } } else { fh_lock(fhp); dentry = lookup_one_len(name, dparent, len); host_err = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out_nfserr; /* * check if we have crossed a mount point ... */ if (d_mountpoint(dentry)) { if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { dput(dentry); goto out_nfserr; } } } *dentry_ret = dentry; *exp_ret = exp; return 0; out_nfserr: exp_put(exp); return nfserrno(host_err); }
long do_sys_open_by_handle(int mountdirfd, struct file_handle __user * ufh, int open_flag) { int fd; long retval = 0; struct file *filp; struct dentry *dentry; struct file_handle f_handle; struct vfsmount *mnt = NULL; struct file_handle *handle = NULL; /* can't use O_CREATE with open_by_handle */ if(open_flag & O_CREAT) { retval = -EINVAL; goto out_err; } if(copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) { retval = -EFAULT; goto out_err; } if((f_handle.handle_size > MAX_HANDLE_SZ) || (f_handle.handle_size <= 0)) { retval = -EINVAL; goto out_err; } handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_size, GFP_KERNEL); if(!handle) { retval = -ENOMEM; goto out_err; } /* copy the full handle */ if(copy_from_user(handle, ufh, sizeof(struct file_handle) + f_handle.handle_size)) { retval = -EFAULT; goto out_handle; } dentry = handle_to_dentry(mountdirfd, handle, &mnt); if(IS_ERR(dentry)) { retval = PTR_ERR(dentry); goto out_handle; } retval = may_handle_open(dentry, open_flag); if(retval) goto out_handle; fd = get_unused_fd(); if(fd < 0) { retval = fd; goto out_dentry; } filp = dentry_open(dentry, mnt, open_flag); if(IS_ERR(filp)) { put_unused_fd(fd); retval = PTR_ERR(filp); } else { retval = fd; fsnotify_open(filp->f_dentry); fd_install(fd, filp); } kfree(handle); return retval; out_dentry: dput(dentry); mntput(mnt); out_handle: kfree(handle); out_err: return retval; }
static void __exit capifs_exit(void) { unregister_filesystem(&capifs_fs_type); mntput(capifs_mnt); }
static void __exit exit_devpts_fs(void) { unregister_filesystem(&devpts_fs_type); mntput(devpts_mnt); }
static int ovl_fill_super(struct super_block *sb, void *data, int silent) { struct path lowerpath; struct path upperpath; struct inode *root_inode; struct dentry *root_dentry; struct ovl_entry *oe; struct ovl_fs *ufs; struct kstatfs statfs; int err; err = -ENOMEM; ufs = kmalloc(sizeof(struct ovl_fs), GFP_KERNEL); if (!ufs) goto out; err = ovl_parse_opt((char *) data, &ufs->config); if (err) goto out_free_ufs; err = -EINVAL; if (!ufs->config.upperdir || !ufs->config.lowerdir) { pr_err("overlayfs: missing upperdir or lowerdir\n"); goto out_free_config; } oe = ovl_alloc_entry(); if (oe == NULL) goto out_free_config; err = kern_path(ufs->config.upperdir, LOOKUP_FOLLOW, &upperpath); if (err) goto out_free_oe; err = kern_path(ufs->config.lowerdir, LOOKUP_FOLLOW, &lowerpath); if (err) goto out_put_upperpath; err = -ENOTDIR; if (!S_ISDIR(upperpath.dentry->d_inode->i_mode) || !S_ISDIR(lowerpath.dentry->d_inode->i_mode)) goto out_put_lowerpath; err = vfs_statfs(&lowerpath, &statfs); if (err) { pr_err("overlayfs: statfs failed on lowerpath\n"); goto out_put_lowerpath; } ufs->lower_namelen = statfs.f_namelen; sb->s_stack_depth = max(upperpath.mnt->mnt_sb->s_stack_depth, lowerpath.mnt->mnt_sb->s_stack_depth) + 1; err = -EINVAL; if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { pr_err("overlayfs: maximum fs stacking depth exceeded\n"); goto out_put_lowerpath; } ufs->upper_mnt = clone_private_mount(&upperpath); err = PTR_ERR(ufs->upper_mnt); if (IS_ERR(ufs->upper_mnt)) { pr_err("overlayfs: failed to clone upperpath\n"); goto out_put_lowerpath; } ufs->lower_mnt = clone_private_mount(&lowerpath); err = PTR_ERR(ufs->lower_mnt); if (IS_ERR(ufs->lower_mnt)) { pr_err("overlayfs: failed to clone lowerpath\n"); goto out_put_upper_mnt; } /* * Make lower_mnt R/O. That way fchmod/fchown on lower file * will fail instead of modifying lower fs. */ ufs->lower_mnt->mnt_flags |= MNT_READONLY; /* If the upper fs is r/o, we mark overlayfs r/o too */ if (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY) sb->s_flags |= MS_RDONLY; if (!(sb->s_flags & MS_RDONLY)) { err = mnt_want_write(ufs->upper_mnt); if (err) goto out_put_lower_mnt; } err = -ENOMEM; root_inode = ovl_new_inode(sb, S_IFDIR, oe); if (!root_inode) goto out_drop_write; root_dentry = d_make_root(root_inode); if (!root_dentry) goto out_drop_write; mntput(upperpath.mnt); mntput(lowerpath.mnt); oe->__upperdentry = dget(upperpath.dentry); oe->lowerdentry = lowerpath.dentry; root_dentry->d_fsdata = oe; root_dentry->d_op = &ovl_dentry_operations; sb->s_magic = OVERLAYFS_SUPER_MAGIC; sb->s_op = &ovl_super_operations; sb->s_root = root_dentry; sb->s_fs_info = ufs; return 0; out_drop_write: if (!(sb->s_flags & MS_RDONLY)) mnt_drop_write(ufs->upper_mnt); out_put_lower_mnt: mntput(ufs->lower_mnt); out_put_upper_mnt: mntput(ufs->upper_mnt); out_put_lowerpath: path_put(&lowerpath); out_put_upperpath: path_put(&upperpath); out_free_oe: kfree(oe); out_free_config: kfree(ufs->config.lowerdir); kfree(ufs->config.upperdir); out_free_ufs: kfree(ufs); out: return err; }
/* * Look up one component of a pathname. * N.B. After this call _both_ fhp and resfh need an fh_put * * If the lookup would cross a mountpoint, and the mounted filesystem * is exported to the client with NFSEXP_CROSSMNT, then the lookup is * accepted as it stands and the mounted directory is * returned. Otherwise the covered directory is returned. * NOTE: this mountpoint crossing is not supported properly by all * clients and is explicitly disallowed for NFSv3 * NeilBrown <*****@*****.**> */ int nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, int len, struct svc_fh *resfh) { struct svc_export *exp; struct dentry *dparent; struct dentry *dentry; int err; dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); /* Obtain dentry and export. */ err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC); if (err) goto out; dparent = fhp->fh_dentry; exp = fhp->fh_export; err = nfserr_acces; /* Lookup the name, but don't follow links */ if (isdotent(name, len)) { if (len==1) dentry = dget(dparent); else { /* must be ".." */ /* checking mountpoint crossing is very different when stepping up */ if (dparent == exp->ex_dentry) { if (!EX_CROSSMNT(exp)) dentry = dget(dparent); /* .. == . just like at / */ else { struct svc_export *exp2 = NULL; struct dentry *dp; struct vfsmount *mnt = mntget(exp->ex_mnt); dentry = dget(dparent); while(follow_up(&mnt, &dentry)) ; dp = dget(dentry->d_parent); dput(dentry); dentry = dp; for ( ; exp2 == NULL && dp->d_parent != dp; dp=dp->d_parent) exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino); if (exp2==NULL) { dput(dentry); dentry = dget(dparent); } else { exp = exp2; } mntput(mnt); } } else dentry = dget(dparent->d_parent); } } else { fh_lock(fhp); dentry = lookup_one_len(name, dparent, len); err = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out_nfserr; /* * check if we have crossed a mount point ... */ if (d_mountpoint(dentry)) { struct svc_export *exp2 = NULL; struct vfsmount *mnt = mntget(exp->ex_mnt); struct dentry *mounts = dget(dentry); while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)) ; exp2 = exp_get(rqstp->rq_client, mounts->d_inode->i_dev, mounts->d_inode->i_ino); if (exp2 && EX_CROSSMNT(exp2)) { /* successfully crossed mount point */ exp = exp2; dput(dentry); dentry = mounts; } else dput(mounts); mntput(mnt); } } /* * Note: we compose the file handle now, but as the * dentry may be negative, it may need to be updated. */ err = fh_compose(resfh, exp, dentry, fhp); if (!err && !dentry->d_inode) err = nfserr_noent; out: return err; out_nfserr: err = nfserrno(err); goto out; }