[PATCH] mm: split page table lock
[linux-2.6] / fs / xfs / linux-2.6 / xfs_export.c
1 /*
2  * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc., 59
21  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  *
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  *
26  * http://www.sgi.com
27  *
28  * For further information regarding this notice, see:
29  *
30  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31  */
32
33 #include "xfs.h"
34 #include "xfs_types.h"
35 #include "xfs_dmapi.h"
36 #include "xfs_log.h"
37 #include "xfs_trans.h"
38 #include "xfs_sb.h"
39 #include "xfs_dir.h"
40 #include "xfs_mount.h"
41 #include "xfs_export.h"
42
43 /*
44  * XFS encode and decodes the fileid portion of NFS filehandles
45  * itself instead of letting the generic NFS code do it.  This
46  * allows filesystems with 64 bit inode numbers to be exported.
47  *
48  * Note that a side effect is that xfs_vget() won't be passed a
49  * zero inode/generation pair under normal circumstances.  As
50  * however a malicious client could send us such data, the check
51  * remains in that code.
52  */
53
54
55 STATIC struct dentry *
56 linvfs_decode_fh(
57         struct super_block      *sb,
58         __u32                   *fh,
59         int                     fh_len,
60         int                     fileid_type,
61         int (*acceptable)(
62                 void            *context,
63                 struct dentry   *de),
64         void                    *context)
65 {
66         xfs_fid2_t              ifid;
67         xfs_fid2_t              pfid;
68         void                    *parent = NULL;
69         int                     is64 = 0;
70         __u32                   *p = fh;
71
72 #if XFS_BIG_INUMS
73         is64 = (fileid_type & XFS_FILEID_TYPE_64FLAG);
74         fileid_type &= ~XFS_FILEID_TYPE_64FLAG;
75 #endif
76
77         /*
78          * Note that we only accept fileids which are long enough
79          * rather than allow the parent generation number to default
80          * to zero.  XFS considers zero a valid generation number not
81          * an invalid/wildcard value.  There's little point printk'ing
82          * a warning here as we don't have the client information
83          * which would make such a warning useful.
84          */
85         if (fileid_type > 2 ||
86             fh_len < xfs_fileid_length((fileid_type == 2), is64))
87                 return NULL;
88
89         p = xfs_fileid_decode_fid2(p, &ifid, is64);
90
91         if (fileid_type == 2) {
92                 p = xfs_fileid_decode_fid2(p, &pfid, is64);
93                 parent = &pfid;
94         }
95         
96         fh = (__u32 *)&ifid;
97         return find_exported_dentry(sb, fh, parent, acceptable, context);
98 }
99
100
101 STATIC int
102 linvfs_encode_fh(
103         struct dentry           *dentry,
104         __u32                   *fh,
105         int                     *max_len,
106         int                     connectable)
107 {
108         struct inode            *inode = dentry->d_inode;
109         int                     type = 1;
110         __u32                   *p = fh;
111         int                     len;
112         int                     is64 = 0;
113 #if XFS_BIG_INUMS
114         vfs_t                   *vfs = LINVFS_GET_VFS(inode->i_sb);
115         xfs_mount_t             *mp = XFS_VFSTOM(vfs);
116         
117         if (!(mp->m_flags & XFS_MOUNT_32BITINOOPT)) {
118                 /* filesystem may contain 64bit inode numbers */
119                 is64 = XFS_FILEID_TYPE_64FLAG;
120         }
121 #endif
122
123         /* Directories don't need their parent encoded, they have ".." */
124         if (S_ISDIR(inode->i_mode))
125             connectable = 0;
126
127         /*
128          * Only encode if there is enough space given.  In practice
129          * this means we can't export a filesystem with 64bit inodes
130          * over NFSv2 with the subtree_check export option; the other
131          * seven combinations work.  The real answer is "don't use v2".
132          */
133         len = xfs_fileid_length(connectable, is64);
134         if (*max_len < len)
135                 return 255;
136         *max_len = len;
137
138         p = xfs_fileid_encode_inode(p, inode, is64);
139         if (connectable) {
140                 spin_lock(&dentry->d_lock);
141                 p = xfs_fileid_encode_inode(p, dentry->d_parent->d_inode, is64);
142                 spin_unlock(&dentry->d_lock);
143                 type = 2;
144         }
145         BUG_ON((p - fh) != len);
146         return type | is64;
147 }
148
149 STATIC struct dentry *
150 linvfs_get_dentry(
151         struct super_block      *sb,
152         void                    *data)
153 {
154         vnode_t                 *vp;
155         struct inode            *inode;
156         struct dentry           *result;
157         vfs_t                   *vfsp = LINVFS_GET_VFS(sb);
158         int                     error;
159
160         VFS_VGET(vfsp, &vp, (fid_t *)data, error);
161         if (error || vp == NULL)
162                 return ERR_PTR(-ESTALE) ;
163
164         inode = LINVFS_GET_IP(vp);
165         result = d_alloc_anon(inode);
166         if (!result) {
167                 iput(inode);
168                 return ERR_PTR(-ENOMEM);
169         }
170         return result;
171 }
172
173 STATIC struct dentry *
174 linvfs_get_parent(
175         struct dentry           *child)
176 {
177         int                     error;
178         vnode_t                 *vp, *cvp;
179         struct dentry           *parent;
180         struct dentry           dotdot;
181
182         dotdot.d_name.name = "..";
183         dotdot.d_name.len = 2;
184         dotdot.d_inode = NULL;
185
186         cvp = NULL;
187         vp = LINVFS_GET_VP(child->d_inode);
188         VOP_LOOKUP(vp, &dotdot, &cvp, 0, NULL, NULL, error);
189         if (unlikely(error))
190                 return ERR_PTR(-error);
191
192         parent = d_alloc_anon(LINVFS_GET_IP(cvp));
193         if (unlikely(!parent)) {
194                 VN_RELE(cvp);
195                 return ERR_PTR(-ENOMEM);
196         }
197         return parent;
198 }
199
200 struct export_operations linvfs_export_ops = {
201         .decode_fh              = linvfs_decode_fh,
202         .encode_fh              = linvfs_encode_fh,
203         .get_parent             = linvfs_get_parent,
204         .get_dentry             = linvfs_get_dentry,
205 };