| [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 |  | 
|---|