| [2659] | 1 | From b1f23baecb2de72b44cda8bba27615c012a445f1 Mon Sep 17 00:00:00 2001 | 
|---|
| [2655] | 2 | From: Marc Dionne <marc.dionne@your-file-system.com> | 
|---|
|  | 3 | Date: Thu, 18 Dec 2014 08:43:22 -0500 | 
|---|
|  | 4 | Subject: [PATCH] Linux: d_splice_alias may drop inode reference on error | 
|---|
|  | 5 |  | 
|---|
|  | 6 | d_splice_alias now drops the inode reference on error, so we | 
|---|
|  | 7 | need to grab an extra one to make sure that the inode doesn't | 
|---|
|  | 8 | go away, and release it when done if there was no error. | 
|---|
|  | 9 |  | 
|---|
|  | 10 | For kernels that may not drop the reference, provide an | 
|---|
|  | 11 | additional iput() within an ifdef.  This could be hooked up | 
|---|
|  | 12 | to a configure option to allow building a module for a kernel | 
|---|
|  | 13 | that is known not to drop the reference on error.  That hook | 
|---|
|  | 14 | is not provided here.  Affected kernels should be the early | 
|---|
|  | 15 | 3.17 ones (3.17 - 3.17.2); 3.16 and older kernels should not | 
|---|
|  | 16 | return errors here. | 
|---|
|  | 17 |  | 
|---|
|  | 18 | Change-Id: Id1786ac2227b4d8e0ae801fe59c15a0ecd975bed | 
|---|
|  | 19 | --- | 
|---|
| [2659] | 20 | acinclude.m4                 |  3 +++ | 
|---|
|  | 21 | src/afs/LINUX/osi_vnodeops.c | 29 ++++++++++++++++++++++++++--- | 
|---|
|  | 22 | 2 files changed, 29 insertions(+), 3 deletions(-) | 
|---|
| [2655] | 23 |  | 
|---|
| [2659] | 24 | diff --git a/acinclude.m4 b/acinclude.m4 | 
|---|
|  | 25 | index 96adde0..19f7092 100644 | 
|---|
|  | 26 | --- a/acinclude.m4 | 
|---|
|  | 27 | +++ b/acinclude.m4 | 
|---|
|  | 28 | @@ -984,6 +984,9 @@ case $AFS_SYSNAME in *_linux* | *_umlinux*) | 
|---|
|  | 29 | AC_CHECK_LINUX_FUNC([hlist_unhashed], | 
|---|
|  | 30 | [#include <linux/list.h>], | 
|---|
|  | 31 | [hlist_unhashed(0);]) | 
|---|
|  | 32 | +                AC_CHECK_LINUX_FUNC([ihold], | 
|---|
|  | 33 | +                                    [#include <linux/fs.h>], | 
|---|
|  | 34 | +                                    [ihold(NULL);]) | 
|---|
|  | 35 | AC_CHECK_LINUX_FUNC([i_size_read], | 
|---|
|  | 36 | [#include <linux/fs.h>], | 
|---|
|  | 37 | [i_size_read(NULL);]) | 
|---|
| [2655] | 38 | diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c | 
|---|
| [2659] | 39 | index b2ab9d5..cedfef6 100644 | 
|---|
| [2655] | 40 | --- a/src/afs/LINUX/osi_vnodeops.c | 
|---|
|  | 41 | +++ b/src/afs/LINUX/osi_vnodeops.c | 
|---|
| [2659] | 42 | @@ -1612,6 +1612,17 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp) | 
|---|
| [2655] | 43 | ip->i_flags |= S_AUTOMOUNT; | 
|---|
|  | 44 | #endif | 
|---|
|  | 45 | } | 
|---|
|  | 46 | +    /* | 
|---|
|  | 47 | +     * Take an extra reference so the inode doesn't go away if | 
|---|
|  | 48 | +     * d_splice_alias drops our reference on error. | 
|---|
|  | 49 | +     */ | 
|---|
|  | 50 | +    if (ip) | 
|---|
| [2659] | 51 | +#ifdef HAVE_LINUX_IHOLD | 
|---|
|  | 52 | +       ihold(ip); | 
|---|
|  | 53 | +#else | 
|---|
| [2655] | 54 | +       igrab(ip); | 
|---|
| [2659] | 55 | +#endif | 
|---|
| [2655] | 56 | + | 
|---|
|  | 57 | newdp = d_splice_alias(ip, dp); | 
|---|
|  | 58 |  | 
|---|
|  | 59 | done: | 
|---|
| [2659] | 60 | @@ -1625,14 +1636,26 @@ afs_linux_lookup(struct inode *dip, struct dentry *dp) | 
|---|
| [2655] | 61 | * d_splice_alias can return an error (EIO) if there is an existing | 
|---|
|  | 62 | * connected directory alias for this dentry. | 
|---|
|  | 63 | */ | 
|---|
|  | 64 | -       if (!IS_ERR(newdp)) | 
|---|
|  | 65 | +       if (!IS_ERR(newdp)) { | 
|---|
|  | 66 | +           iput(ip); | 
|---|
|  | 67 | return newdp; | 
|---|
|  | 68 | -       else { | 
|---|
|  | 69 | +       } else { | 
|---|
|  | 70 | d_add(dp, ip); | 
|---|
|  | 71 | +           /* | 
|---|
|  | 72 | +            * Depending on the kernel version, d_splice_alias may or may | 
|---|
|  | 73 | +            * not drop the inode reference on error.  If it didn't, do it | 
|---|
|  | 74 | +            * here. | 
|---|
|  | 75 | +            */ | 
|---|
|  | 76 | +#if defined(D_SPLICE_ALIAS_LEAK_ON_ERROR) | 
|---|
|  | 77 | +           iput(ip); | 
|---|
|  | 78 | +#endif | 
|---|
|  | 79 | return NULL; | 
|---|
|  | 80 | } | 
|---|
|  | 81 | -    } else | 
|---|
|  | 82 | +    } else { | 
|---|
|  | 83 | +       if (ip) | 
|---|
|  | 84 | +           iput(ip); | 
|---|
|  | 85 | return ERR_PTR(afs_convert_code(code)); | 
|---|
|  | 86 | +    } | 
|---|
|  | 87 | } | 
|---|
|  | 88 |  | 
|---|
|  | 89 | static int | 
|---|
|  | 90 | -- | 
|---|
|  | 91 | 2.2.1 | 
|---|
|  | 92 |  | 
|---|