// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2005-2019 Junjiro R. Okajima */ /* * sub-routines for VFS */ #include #include #include #include "aufs.h" struct file *vfsub_dentry_open(struct path *path, int flags) { struct file *file; file = dentry_open(path, flags /* | __FMODE_NONOTIFY */, current_cred()); if (!IS_ERR_OR_NULL(file) && (file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(d_inode(path->dentry)); return file; } struct file *vfsub_filp_open(const char *path, int oflags, int mode) { struct file *file; lockdep_off(); file = filp_open(path, oflags /* | __FMODE_NONOTIFY */, mode); lockdep_on(); return file; } int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) { int err; err = kern_path(name, flags, path); /* add more later */ return err; } struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, int len) { struct path path = { .mnt = NULL }; /* VFS checks it too, but by WARN_ON_ONCE() */ IMustLock(d_inode(parent)); path.dentry = lookup_one_len(name, parent, len); if (IS_ERR(path.dentry)) goto out; out: AuTraceErrPtr(path.dentry); return path.dentry; } /* ---------------------------------------------------------------------- */ struct unlink_args { int *errp; struct inode *dir; struct path *path; struct inode **delegated_inode; }; static void call_unlink(void *args) { struct unlink_args *a = args; struct dentry *d = a->path->dentry; struct inode *h_inode; const int stop_sillyrename = (au_test_nfs(d->d_sb) && au_dcount(d) == 1); IMustLock(a->dir); a->path->dentry = d->d_parent; *a->errp = security_path_unlink(a->path, d); a->path->dentry = d; if (unlikely(*a->errp)) return; if (!stop_sillyrename) dget(d); h_inode = NULL; if (d_is_positive(d)) { h_inode = d_inode(d); ihold(h_inode); } lockdep_off(); *a->errp = vfs_unlink(a->dir, d, a->delegated_inode); lockdep_on(); if (!stop_sillyrename) dput(d); if (h_inode) iput(h_inode); AuTraceErr(*a->errp); } /* * @dir: must be locked. * @dentry: target dentry. */ int vfsub_unlink(struct inode *dir, struct path *path, struct inode **delegated_inode, int force) { int err; struct unlink_args args = { .errp = &err, .dir = dir, .path = path, .delegated_inode = delegated_inode }; if (!force) call_unlink(&args); else { int wkq_err; wkq_err = au_wkq_wait(call_unlink, &args); if (unlikely(wkq_err)) err = wkq_err; } return err; }