mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-10-07 13:37:49 +00:00
d_namespace & minor cleanup patches
This commit is contained in:
206
kernel-patches/for-mainline/d_path-lazy-unmounts.diff
Normal file
206
kernel-patches/for-mainline/d_path-lazy-unmounts.diff
Normal file
@@ -0,0 +1,206 @@
|
||||
Index: linux-2.6/fs/dcache.c
|
||||
===================================================================
|
||||
--- linux-2.6.orig/fs/dcache.c
|
||||
+++ linux-2.6/fs/dcache.c
|
||||
@@ -1739,45 +1739,43 @@ shouldnt_be_hashed:
|
||||
* @rootmnt: vfsmnt to which the root dentry belongs
|
||||
* @buffer: buffer to return value in
|
||||
* @buflen: buffer length
|
||||
+ * @fail_deleted: what to return when hitting a deleted dentry
|
||||
*
|
||||
- * Convert a dentry into an ASCII path name. If the entry has been deleted
|
||||
- * the string " (deleted)" is appended. Note that this is ambiguous.
|
||||
+ * Convert a dentry into an ASCII path name. If the entry has been deleted,
|
||||
+ * then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise,
|
||||
+ * the the string " (deleted)" is appended. Note that this is ambiguous.
|
||||
*
|
||||
- * Returns the buffer or an error code if the path was too long.
|
||||
- *
|
||||
- * "buflen" should be positive. Caller holds the dcache_lock.
|
||||
+ * Returns the buffer or an error code.
|
||||
*/
|
||||
-static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
|
||||
- struct dentry *root, struct vfsmount *rootmnt,
|
||||
- char *buffer, int buflen)
|
||||
+static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
|
||||
+ struct dentry *root, struct vfsmount *rootmnt,
|
||||
+ char *buffer, int buflen, int fail_deleted)
|
||||
{
|
||||
- char * end = buffer+buflen;
|
||||
- char * retval;
|
||||
+ char *end = buffer + buflen - 1;
|
||||
int namelen;
|
||||
|
||||
- *--end = '\0';
|
||||
+ buffer = end;
|
||||
+ if (buflen < 2)
|
||||
+ return ERR_PTR(-ENAMETOOLONG);
|
||||
+ *end = '\0';
|
||||
buflen--;
|
||||
+
|
||||
+ spin_lock(&dcache_lock);
|
||||
if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
|
||||
- buflen -= 10;
|
||||
- end -= 10;
|
||||
- if (buflen < 0)
|
||||
+ if (fail_deleted) {
|
||||
+ buffer = ERR_PTR(-ENOENT);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (buflen < 10)
|
||||
goto Elong;
|
||||
- memcpy(end, " (deleted)", 10);
|
||||
+ buflen -= 10;
|
||||
+ buffer -= 10;
|
||||
+ memcpy(buffer, " (deleted)", 10);
|
||||
}
|
||||
-
|
||||
- if (buflen < 1)
|
||||
- goto Elong;
|
||||
- /* Get '/' right */
|
||||
- retval = end-1;
|
||||
- *retval = '/';
|
||||
-
|
||||
- for (;;) {
|
||||
+ while (dentry != root || vfsmnt != rootmnt) {
|
||||
struct dentry * parent;
|
||||
|
||||
- if (dentry == root && vfsmnt == rootmnt)
|
||||
- break;
|
||||
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
|
||||
- /* Global root? */
|
||||
spin_lock(&vfsmount_lock);
|
||||
if (vfsmnt->mnt_parent == vfsmnt) {
|
||||
spin_unlock(&vfsmount_lock);
|
||||
@@ -1791,33 +1789,49 @@ static char * __d_path( struct dentry *d
|
||||
parent = dentry->d_parent;
|
||||
prefetch(parent);
|
||||
namelen = dentry->d_name.len;
|
||||
- buflen -= namelen + 1;
|
||||
- if (buflen < 0)
|
||||
+ if (buflen <= namelen)
|
||||
goto Elong;
|
||||
- end -= namelen;
|
||||
- memcpy(end, dentry->d_name.name, namelen);
|
||||
- *--end = '/';
|
||||
- retval = end;
|
||||
+ buflen -= namelen + 1;
|
||||
+ buffer -= namelen;
|
||||
+ memcpy(buffer, dentry->d_name.name, namelen);
|
||||
+ *--buffer = '/';
|
||||
dentry = parent;
|
||||
}
|
||||
+ /* Get '/' right */
|
||||
+ if (buffer == end)
|
||||
+ *--buffer = '/';
|
||||
|
||||
- return retval;
|
||||
+out:
|
||||
+ spin_unlock(&dcache_lock);
|
||||
+ return buffer;
|
||||
|
||||
global_root:
|
||||
+ /*
|
||||
+ * We went past the (vfsmount, dentry) we were loking for and have
|
||||
+ * either hit a root dentry, a lazily unmounted dentry, or an
|
||||
+ * unconnected dentry. Make sure we won't return a pathname rooted
|
||||
+ * in '/'.
|
||||
+ */
|
||||
namelen = dentry->d_name.len;
|
||||
- buflen -= namelen;
|
||||
- if (buflen < 0)
|
||||
- goto Elong;
|
||||
- retval -= namelen-1; /* hit the slash */
|
||||
- memcpy(retval, dentry->d_name.name, namelen);
|
||||
- return retval;
|
||||
+ if (namelen == 1 && *dentry->d_name.name == '/') {
|
||||
+ if (buffer != end)
|
||||
+ buffer++;
|
||||
+ } else {
|
||||
+ if (buflen < namelen)
|
||||
+ goto Elong;
|
||||
+ buffer -= namelen;
|
||||
+ memcpy(buffer, dentry->d_name.name, namelen);
|
||||
+ }
|
||||
+ goto out;
|
||||
+
|
||||
Elong:
|
||||
- return ERR_PTR(-ENAMETOOLONG);
|
||||
+ buffer = ERR_PTR(-ENAMETOOLONG);
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
/* write full pathname into buffer and return start of pathname */
|
||||
-char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
|
||||
- char *buf, int buflen)
|
||||
+char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
|
||||
+ int buflen)
|
||||
{
|
||||
char *res;
|
||||
struct vfsmount *rootmnt;
|
||||
@@ -1827,9 +1841,7 @@ char * d_path(struct dentry *dentry, str
|
||||
rootmnt = mntget(current->fs->rootmnt);
|
||||
root = dget(current->fs->root);
|
||||
read_unlock(¤t->fs->lock);
|
||||
- spin_lock(&dcache_lock);
|
||||
- res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen);
|
||||
- spin_unlock(&dcache_lock);
|
||||
+ res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0);
|
||||
dput(root);
|
||||
mntput(rootmnt);
|
||||
return res;
|
||||
@@ -1855,10 +1867,10 @@ char * d_path(struct dentry *dentry, str
|
||||
*/
|
||||
asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
|
||||
{
|
||||
- int error;
|
||||
+ int error, len;
|
||||
struct vfsmount *pwdmnt, *rootmnt;
|
||||
struct dentry *pwd, *root;
|
||||
- char *page = (char *) __get_free_page(GFP_USER);
|
||||
+ char *page = (char *) __get_free_page(GFP_USER), *cwd;
|
||||
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
@@ -1870,29 +1882,18 @@ asmlinkage long sys_getcwd(char __user *
|
||||
root = dget(current->fs->root);
|
||||
read_unlock(¤t->fs->lock);
|
||||
|
||||
- error = -ENOENT;
|
||||
- /* Has the current directory has been unlinked? */
|
||||
- spin_lock(&dcache_lock);
|
||||
- if (pwd->d_parent == pwd || !d_unhashed(pwd)) {
|
||||
- unsigned long len;
|
||||
- char * cwd;
|
||||
-
|
||||
- cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE);
|
||||
- spin_unlock(&dcache_lock);
|
||||
-
|
||||
- error = PTR_ERR(cwd);
|
||||
- if (IS_ERR(cwd))
|
||||
- goto out;
|
||||
-
|
||||
- error = -ERANGE;
|
||||
- len = PAGE_SIZE + page - cwd;
|
||||
- if (len <= size) {
|
||||
- error = len;
|
||||
- if (copy_to_user(buf, cwd, len))
|
||||
- error = -EFAULT;
|
||||
- }
|
||||
- } else
|
||||
- spin_unlock(&dcache_lock);
|
||||
+ cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
|
||||
+ error = PTR_ERR(cwd);
|
||||
+ if (IS_ERR(cwd))
|
||||
+ goto out;
|
||||
+
|
||||
+ error = -ERANGE;
|
||||
+ len = PAGE_SIZE + page - cwd;
|
||||
+ if (len <= size) {
|
||||
+ error = len;
|
||||
+ if (copy_to_user(buf, cwd, len))
|
||||
+ error = -EFAULT;
|
||||
+ }
|
||||
|
||||
out:
|
||||
dput(pwd);
|
Reference in New Issue
Block a user