Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5af568cb authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
  isofs: Fix lseek() to position beyond 4 GB
  vfs: remove unused MNT_STRICTATIME
  vfs: show unreachable paths in getcwd and proc
  vfs: only add " (deleted)" where necessary
  vfs: add prepend_path() helper
  vfs: __d_path: dont prepend the name of the root dentry
  ia64: perfmon: add d_dname method
  vfs: add helpers to get root and pwd
  cachefiles: use path_get instead of lone dget
  fs/sysv/super.c: add support for non-PDP11 v7 filesystems
  V7: Adjust sanity checks for some volumes
  Add v7 alias
  v9fs: fixup for inode_setattr being removed

Manual merge to take Al's version of the fs/sysv/super.c file: it merged
cleanly, but Al had removed an unnecessary header include, so his side
was better.
parents 062e27ec 66a362a2
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -2191,8 +2191,15 @@ pfmfs_delete_dentry(struct dentry *dentry)
	return 1;
}

static char *pfmfs_dname(struct dentry *dentry, char *buffer, int buflen)
{
	return dynamic_dname(dentry, buffer, buflen, "pfm:[%lu]",
			     dentry->d_inode->i_ino);
}

static const struct dentry_operations pfmfs_dentry_operations = {
	.d_delete = pfmfs_delete_dentry,
	.d_dname = pfmfs_dname,
};


@@ -2202,8 +2209,7 @@ pfm_alloc_file(pfm_context_t *ctx)
	struct file *file;
	struct inode *inode;
	struct path path;
	char name[32];
	struct qstr this;
	struct qstr this = { .name = "" };

	/*
	 * allocate a new inode
@@ -2218,11 +2224,6 @@ pfm_alloc_file(pfm_context_t *ctx)
	inode->i_uid  = current_fsuid();
	inode->i_gid  = current_fsgid();

	sprintf(name, "[%lu]", inode->i_ino);
	this.name = name;
	this.len  = strlen(name);
	this.hash = inode->i_ino;

	/*
	 * allocate a new dcache entry
	 */
+12 −3
Original line number Diff line number Diff line
@@ -1263,12 +1263,21 @@ static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
		return PTR_ERR(fid);

	retval = p9_client_setattr(fid, &p9attr);
	if (retval >= 0)
		retval = inode_setattr(dentry->d_inode, iattr);
	if (retval < 0)
		return retval;

	if ((iattr->ia_valid & ATTR_SIZE) &&
	    iattr->ia_size != i_size_read(dentry->d_inode)) {
		retval = vmtruncate(dentry->d_inode, iattr->ia_size);
		if (retval)
			return retval;
	}

	setattr_copy(dentry->d_inode, iattr);
	mark_inode_dirty(dentry->d_inode);
	return 0;
}

/**
 * v9fs_stat2inode - populate an inode structure with mistat info
 * @stat: Plan 9 metadata (mistat) structure
+12 −20
Original line number Diff line number Diff line
@@ -552,8 +552,7 @@ static int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args)
 */
static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args)
{
	struct fs_struct *fs;
	struct dentry *dir;
	struct path path;
	const struct cred *saved_cred;
	int ret;

@@ -573,24 +572,21 @@ static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args)
	}

	/* extract the directory dentry from the cwd */
	fs = current->fs;
	read_lock(&fs->lock);
	dir = dget(fs->pwd.dentry);
	read_unlock(&fs->lock);
	get_fs_pwd(current->fs, &path);

	if (!S_ISDIR(dir->d_inode->i_mode))
	if (!S_ISDIR(path.dentry->d_inode->i_mode))
		goto notdir;

	cachefiles_begin_secure(cache, &saved_cred);
	ret = cachefiles_cull(cache, dir, args);
	ret = cachefiles_cull(cache, path.dentry, args);
	cachefiles_end_secure(cache, saved_cred);

	dput(dir);
	path_put(&path);
	_leave(" = %d", ret);
	return ret;

notdir:
	dput(dir);
	path_put(&path);
	kerror("cull command requires dirfd to be a directory");
	return -ENOTDIR;

@@ -628,8 +624,7 @@ inval:
 */
static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args)
{
	struct fs_struct *fs;
	struct dentry *dir;
	struct path path;
	const struct cred *saved_cred;
	int ret;

@@ -649,24 +644,21 @@ static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args)
	}

	/* extract the directory dentry from the cwd */
	fs = current->fs;
	read_lock(&fs->lock);
	dir = dget(fs->pwd.dentry);
	read_unlock(&fs->lock);
	get_fs_pwd(current->fs, &path);

	if (!S_ISDIR(dir->d_inode->i_mode))
	if (!S_ISDIR(path.dentry->d_inode->i_mode))
		goto notdir;

	cachefiles_begin_secure(cache, &saved_cred);
	ret = cachefiles_check_in_use(cache, dir, args);
	ret = cachefiles_check_in_use(cache, path.dentry, args);
	cachefiles_end_secure(cache, saved_cred);

	dput(dir);
	path_put(&path);
	//_leave(" = %d", ret);
	return ret;

notdir:
	dput(dir);
	path_put(&path);
	kerror("inuse command requires dirfd to be a directory");
	return -ENOTDIR;

+133 −55
Original line number Diff line number Diff line
@@ -1905,48 +1905,30 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
}

/**
 * __d_path - return the path of a dentry
 * Prepend path string to a buffer
 *
 * @path: the dentry/vfsmount to report
 * @root: root vfsmnt/dentry (may be modified by this function)
 * @buffer: buffer to return value in
 * @buflen: buffer length
 * @buffer: pointer to the end of the buffer
 * @buflen: pointer to buffer length
 *
 * Convert a dentry into an ASCII path name. If the entry has been deleted
 * the string " (deleted)" is appended. Note that this is ambiguous.
 *
 * Returns a pointer into the buffer or an error code if the
 * path was too long.
 *
 * "buflen" should be positive. Caller holds the dcache_lock.
 * Caller holds the dcache_lock.
 *
 * If path is not reachable from the supplied root, then the value of
 * root is changed (without modifying refcounts).
 */
char *__d_path(const struct path *path, struct path *root,
	       char *buffer, int buflen)
static int prepend_path(const struct path *path, struct path *root,
			char **buffer, int *buflen)
{
	struct dentry *dentry = path->dentry;
	struct vfsmount *vfsmnt = path->mnt;
	char *end = buffer + buflen;
	char *retval;
	bool slash = false;
	int error = 0;

	spin_lock(&vfsmount_lock);
	prepend(&end, &buflen, "\0", 1);
	if (d_unlinked(dentry) &&
		(prepend(&end, &buflen, " (deleted)", 10) != 0))
			goto Elong;

	if (buflen < 1)
		goto Elong;
	/* Get '/' right */
	retval = end-1;
	*retval = '/';

	for (;;) {
	while (dentry != root->dentry || vfsmnt != root->mnt) {
		struct dentry * parent;

		if (dentry == root->dentry && vfsmnt == root->mnt)
			break;
		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
			/* Global root? */
			if (vfsmnt->mnt_parent == vfsmnt) {
@@ -1958,28 +1940,88 @@ char *__d_path(const struct path *path, struct path *root,
		}
		parent = dentry->d_parent;
		prefetch(parent);
		if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||
		    (prepend(&end, &buflen, "/", 1) != 0))
			goto Elong;
		retval = end;
		error = prepend_name(buffer, buflen, &dentry->d_name);
		if (!error)
			error = prepend(buffer, buflen, "/", 1);
		if (error)
			break;

		slash = true;
		dentry = parent;
	}

out:
	if (!error && !slash)
		error = prepend(buffer, buflen, "/", 1);

	spin_unlock(&vfsmount_lock);
	return retval;
	return error;

global_root:
	retval += 1;	/* hit the slash */
	if (prepend_name(&retval, &buflen, &dentry->d_name) != 0)
		goto Elong;
	/*
	 * Filesystems needing to implement special "root names"
	 * should do so with ->d_dname()
	 */
	if (IS_ROOT(dentry) &&
	    (dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) {
		WARN(1, "Root dentry has weird name <%.*s>\n",
		     (int) dentry->d_name.len, dentry->d_name.name);
	}
	root->mnt = vfsmnt;
	root->dentry = dentry;
	goto out;
}

Elong:
	retval = ERR_PTR(-ENAMETOOLONG);
	goto out;
/**
 * __d_path - return the path of a dentry
 * @path: the dentry/vfsmount to report
 * @root: root vfsmnt/dentry (may be modified by this function)
 * @buffer: buffer to return value in
 * @buflen: buffer length
 *
 * Convert a dentry into an ASCII path name.
 *
 * Returns a pointer into the buffer or an error code if the
 * path was too long.
 *
 * "buflen" should be positive. Caller holds the dcache_lock.
 *
 * If path is not reachable from the supplied root, then the value of
 * root is changed (without modifying refcounts).
 */
char *__d_path(const struct path *path, struct path *root,
	       char *buf, int buflen)
{
	char *res = buf + buflen;
	int error;

	prepend(&res, &buflen, "\0", 1);
	error = prepend_path(path, root, &res, &buflen);
	if (error)
		return ERR_PTR(error);

	return res;
}

/*
 * same as __d_path but appends "(deleted)" for unlinked files.
 */
static int path_with_deleted(const struct path *path, struct path *root,
				 char **buf, int *buflen)
{
	prepend(buf, buflen, "\0", 1);
	if (d_unlinked(path->dentry)) {
		int error = prepend(buf, buflen, " (deleted)", 10);
		if (error)
			return error;
	}

	return prepend_path(path, root, buf, buflen);
}

static int prepend_unreachable(char **buffer, int *buflen)
{
	return prepend(buffer, buflen, "(unreachable)", 13);
}

/**
@@ -2000,9 +2042,10 @@ Elong:
 */
char *d_path(const struct path *path, char *buf, int buflen)
{
	char *res;
	char *res = buf + buflen;
	struct path root;
	struct path tmp;
	int error;

	/*
	 * We have various synthetic filesystems that never get mounted.  On
@@ -2014,19 +2057,51 @@ char *d_path(const struct path *path, char *buf, int buflen)
	if (path->dentry->d_op && path->dentry->d_op->d_dname)
		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);

	read_lock(&current->fs->lock);
	root = current->fs->root;
	path_get(&root);
	read_unlock(&current->fs->lock);
	get_fs_root(current->fs, &root);
	spin_lock(&dcache_lock);
	tmp = root;
	res = __d_path(path, &tmp, buf, buflen);
	error = path_with_deleted(path, &tmp, &res, &buflen);
	if (error)
		res = ERR_PTR(error);
	spin_unlock(&dcache_lock);
	path_put(&root);
	return res;
}
EXPORT_SYMBOL(d_path);

/**
 * d_path_with_unreachable - return the path of a dentry
 * @path: path to report
 * @buf: buffer to return value in
 * @buflen: buffer length
 *
 * The difference from d_path() is that this prepends "(unreachable)"
 * to paths which are unreachable from the current process' root.
 */
char *d_path_with_unreachable(const struct path *path, char *buf, int buflen)
{
	char *res = buf + buflen;
	struct path root;
	struct path tmp;
	int error;

	if (path->dentry->d_op && path->dentry->d_op->d_dname)
		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);

	get_fs_root(current->fs, &root);
	spin_lock(&dcache_lock);
	tmp = root;
	error = path_with_deleted(path, &tmp, &res, &buflen);
	if (!error && !path_equal(&tmp, &root))
		error = prepend_unreachable(&res, &buflen);
	spin_unlock(&dcache_lock);
	path_put(&root);
	if (error)
		res =  ERR_PTR(error);

	return res;
}

/*
 * Helper function for dentry_operations.d_dname() members
 */
@@ -2129,27 +2204,30 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
	if (!page)
		return -ENOMEM;

	read_lock(&current->fs->lock);
	pwd = current->fs->pwd;
	path_get(&pwd);
	root = current->fs->root;
	path_get(&root);
	read_unlock(&current->fs->lock);
	get_fs_root_and_pwd(current->fs, &root, &pwd);

	error = -ENOENT;
	spin_lock(&dcache_lock);
	if (!d_unlinked(pwd.dentry)) {
		unsigned long len;
		struct path tmp = root;
		char * cwd;
		char *cwd = page + PAGE_SIZE;
		int buflen = PAGE_SIZE;

		cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE);
		prepend(&cwd, &buflen, "\0", 1);
		error = prepend_path(&pwd, &tmp, &cwd, &buflen);
		spin_unlock(&dcache_lock);

		error = PTR_ERR(cwd);
		if (IS_ERR(cwd))
		if (error)
			goto out;

		/* Unreachable from current root */
		if (!path_equal(&tmp, &root)) {
			error = prepend_unreachable(&cwd, &buflen);
			if (error)
				goto out;
		}

		error = -ERANGE;
		len = PAGE_SIZE + page - cwd;
		if (len <= size) {
+1 −6
Original line number Diff line number Diff line
@@ -106,12 +106,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
		fs->in_exec = 0;
		rwlock_init(&fs->lock);
		fs->umask = old->umask;
		read_lock(&old->lock);
		fs->root = old->root;
		path_get(&old->root);
		fs->pwd = old->pwd;
		path_get(&old->pwd);
		read_unlock(&old->lock);
		get_fs_root_and_pwd(old, &fs->root, &fs->pwd);
	}
	return fs;
}
Loading