summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/9p/acl.c2
-rw-r--r--fs/btrfs/acl.c3
-rw-r--r--fs/ceph/acl.c2
-rw-r--r--fs/ext2/acl.c3
-rw-r--r--fs/ext4/acl.c3
-rw-r--r--fs/f2fs/acl.c3
-rw-r--r--fs/hfsplus/posix_acl.c3
-rw-r--r--fs/inode.c4
-rw-r--r--fs/jffs2/acl.c2
-rw-r--r--fs/jfs/acl.c2
-rw-r--r--fs/namei.c2
-rw-r--r--fs/nfs/nfs3acl.c43
-rw-r--r--fs/ocfs2/dlmglue.c3
-rw-r--r--fs/posix_acl.c103
-rw-r--r--fs/reiserfs/xattr_acl.c6
-rw-r--r--fs/xfs/xfs_acl.c20
-rw-r--r--include/linux/fs.h12
17 files changed, 138 insertions, 78 deletions
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
index 9da967f38387..2d94e94b6b59 100644
--- a/fs/9p/acl.c
+++ b/fs/9p/acl.c
@@ -93,7 +93,7 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
93 * instantiating the inode (v9fs_inode_from_fid) 93 * instantiating the inode (v9fs_inode_from_fid)
94 */ 94 */
95 acl = get_cached_acl(inode, type); 95 acl = get_cached_acl(inode, type);
96 BUG_ON(acl == ACL_NOT_CACHED); 96 BUG_ON(is_uncached_acl(acl));
97 return acl; 97 return acl;
98} 98}
99 99
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 6d263bb1621c..67a607709d4f 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -63,9 +63,6 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
63 } 63 }
64 kfree(value); 64 kfree(value);
65 65
66 if (!IS_ERR(acl))
67 set_cached_acl(inode, type, acl);
68
69 return acl; 66 return acl;
70} 67}
71 68
diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c
index f19708487e2f..5457f216e2e5 100644
--- a/fs/ceph/acl.c
+++ b/fs/ceph/acl.c
@@ -37,6 +37,8 @@ static inline void ceph_set_cached_acl(struct inode *inode,
37 spin_lock(&ci->i_ceph_lock); 37 spin_lock(&ci->i_ceph_lock);
38 if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)) 38 if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0))
39 set_cached_acl(inode, type, acl); 39 set_cached_acl(inode, type, acl);
40 else
41 forget_cached_acl(inode, type);
40 spin_unlock(&ci->i_ceph_lock); 42 spin_unlock(&ci->i_ceph_lock);
41} 43}
42 44
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 27695e6f4e46..42f1d1814083 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -172,9 +172,6 @@ ext2_get_acl(struct inode *inode, int type)
172 acl = ERR_PTR(retval); 172 acl = ERR_PTR(retval);
173 kfree(value); 173 kfree(value);
174 174
175 if (!IS_ERR(acl))
176 set_cached_acl(inode, type, acl);
177
178 return acl; 175 return acl;
179} 176}
180 177
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index 69b1e73026a5..c6601a476c02 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -172,9 +172,6 @@ ext4_get_acl(struct inode *inode, int type)
172 acl = ERR_PTR(retval); 172 acl = ERR_PTR(retval);
173 kfree(value); 173 kfree(value);
174 174
175 if (!IS_ERR(acl))
176 set_cached_acl(inode, type, acl);
177
178 return acl; 175 return acl;
179} 176}
180 177
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
index c8f25f7241f0..6f1fdda977b3 100644
--- a/fs/f2fs/acl.c
+++ b/fs/f2fs/acl.c
@@ -190,9 +190,6 @@ static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type,
190 acl = ERR_PTR(retval); 190 acl = ERR_PTR(retval);
191 kfree(value); 191 kfree(value);
192 192
193 if (!IS_ERR(acl))
194 set_cached_acl(inode, type, acl);
195
196 return acl; 193 return acl;
197} 194}
198 195
diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c
index afb33eda6d7d..ab7ea2506b4d 100644
--- a/fs/hfsplus/posix_acl.c
+++ b/fs/hfsplus/posix_acl.c
@@ -48,9 +48,6 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
48 48
49 hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value); 49 hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
50 50
51 if (!IS_ERR(acl))
52 set_cached_acl(inode, type, acl);
53
54 return acl; 51 return acl;
55} 52}
56 53
diff --git a/fs/inode.c b/fs/inode.c
index 69b8b526c194..4202aac99464 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -238,9 +238,9 @@ void __destroy_inode(struct inode *inode)
238 } 238 }
239 239
240#ifdef CONFIG_FS_POSIX_ACL 240#ifdef CONFIG_FS_POSIX_ACL
241 if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED) 241 if (inode->i_acl && !is_uncached_acl(inode->i_acl))
242 posix_acl_release(inode->i_acl); 242 posix_acl_release(inode->i_acl);
243 if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED) 243 if (inode->i_default_acl && !is_uncached_acl(inode->i_default_acl))
244 posix_acl_release(inode->i_default_acl); 244 posix_acl_release(inode->i_default_acl);
245#endif 245#endif
246 this_cpu_dec(nr_inodes); 246 this_cpu_dec(nr_inodes);
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index 2f7a3c090489..bc2693d56298 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -203,8 +203,6 @@ struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
203 acl = ERR_PTR(rc); 203 acl = ERR_PTR(rc);
204 } 204 }
205 kfree(value); 205 kfree(value);
206 if (!IS_ERR(acl))
207 set_cached_acl(inode, type, acl);
208 return acl; 206 return acl;
209} 207}
210 208
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index ab4882801b24..21fa92ba2c19 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -63,8 +63,6 @@ struct posix_acl *jfs_get_acl(struct inode *inode, int type)
63 acl = posix_acl_from_xattr(&init_user_ns, value, size); 63 acl = posix_acl_from_xattr(&init_user_ns, value, size);
64 } 64 }
65 kfree(value); 65 kfree(value);
66 if (!IS_ERR(acl))
67 set_cached_acl(inode, type, acl);
68 return acl; 66 return acl;
69} 67}
70 68
diff --git a/fs/namei.c b/fs/namei.c
index 794f81dce766..3498d53de26f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -265,7 +265,7 @@ static int check_acl(struct inode *inode, int mask)
265 if (!acl) 265 if (!acl)
266 return -EAGAIN; 266 return -EAGAIN;
267 /* no ->get_acl() calls in RCU mode... */ 267 /* no ->get_acl() calls in RCU mode... */
268 if (acl == ACL_NOT_CACHED) 268 if (is_uncached_acl(acl))
269 return -ECHILD; 269 return -ECHILD;
270 return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK); 270 return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK);
271 } 271 }
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 17c0fa1eccfa..720d92f5abfb 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -11,6 +11,38 @@
11 11
12#define NFSDBG_FACILITY NFSDBG_PROC 12#define NFSDBG_FACILITY NFSDBG_PROC
13 13
14/*
15 * nfs3_prepare_get_acl, nfs3_complete_get_acl, nfs3_abort_get_acl: Helpers for
16 * caching get_acl results in a race-free way. See fs/posix_acl.c:get_acl()
17 * for explanations.
18 */
19static void nfs3_prepare_get_acl(struct posix_acl **p)
20{
21 struct posix_acl *sentinel = uncached_acl_sentinel(current);
22
23 if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED) {
24 /* Not the first reader or sentinel already in place. */
25 }
26}
27
28static void nfs3_complete_get_acl(struct posix_acl **p, struct posix_acl *acl)
29{
30 struct posix_acl *sentinel = uncached_acl_sentinel(current);
31
32 /* Only cache the ACL if our sentinel is still in place. */
33 posix_acl_dup(acl);
34 if (cmpxchg(p, sentinel, acl) != sentinel)
35 posix_acl_release(acl);
36}
37
38static void nfs3_abort_get_acl(struct posix_acl **p)
39{
40 struct posix_acl *sentinel = uncached_acl_sentinel(current);
41
42 /* Remove our sentinel upon failure. */
43 cmpxchg(p, sentinel, ACL_NOT_CACHED);
44}
45
14struct posix_acl *nfs3_get_acl(struct inode *inode, int type) 46struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
15{ 47{
16 struct nfs_server *server = NFS_SERVER(inode); 48 struct nfs_server *server = NFS_SERVER(inode);
@@ -55,6 +87,11 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
55 if (res.fattr == NULL) 87 if (res.fattr == NULL)
56 return ERR_PTR(-ENOMEM); 88 return ERR_PTR(-ENOMEM);
57 89
90 if (args.mask & NFS_ACL)
91 nfs3_prepare_get_acl(&inode->i_acl);
92 if (args.mask & NFS_DFACL)
93 nfs3_prepare_get_acl(&inode->i_default_acl);
94
58 status = rpc_call_sync(server->client_acl, &msg, 0); 95 status = rpc_call_sync(server->client_acl, &msg, 0);
59 dprintk("NFS reply getacl: %d\n", status); 96 dprintk("NFS reply getacl: %d\n", status);
60 97
@@ -89,12 +126,12 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
89 } 126 }
90 127
91 if (res.mask & NFS_ACL) 128 if (res.mask & NFS_ACL)
92 set_cached_acl(inode, ACL_TYPE_ACCESS, res.acl_access); 129 nfs3_complete_get_acl(&inode->i_acl, res.acl_access);
93 else 130 else
94 forget_cached_acl(inode, ACL_TYPE_ACCESS); 131 forget_cached_acl(inode, ACL_TYPE_ACCESS);
95 132
96 if (res.mask & NFS_DFACL) 133 if (res.mask & NFS_DFACL)
97 set_cached_acl(inode, ACL_TYPE_DEFAULT, res.acl_default); 134 nfs3_complete_get_acl(&inode->i_default_acl, res.acl_default);
98 else 135 else
99 forget_cached_acl(inode, ACL_TYPE_DEFAULT); 136 forget_cached_acl(inode, ACL_TYPE_DEFAULT);
100 137
@@ -108,6 +145,8 @@ struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
108 } 145 }
109 146
110getout: 147getout:
148 nfs3_abort_get_acl(&inode->i_acl);
149 nfs3_abort_get_acl(&inode->i_default_acl);
111 posix_acl_release(res.acl_access); 150 posix_acl_release(res.acl_access);
112 posix_acl_release(res.acl_default); 151 posix_acl_release(res.acl_default);
113 nfs_free_fattr(res.fattr); 152 nfs_free_fattr(res.fattr);
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 474e57f834e6..1eaa9100c889 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -54,6 +54,7 @@
54#include "uptodate.h" 54#include "uptodate.h"
55#include "quota.h" 55#include "quota.h"
56#include "refcounttree.h" 56#include "refcounttree.h"
57#include "acl.h"
57 58
58#include "buffer_head_io.h" 59#include "buffer_head_io.h"
59 60
@@ -3623,6 +3624,8 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
3623 filemap_fdatawait(mapping); 3624 filemap_fdatawait(mapping);
3624 } 3625 }
3625 3626
3627 forget_all_cached_acls(inode);
3628
3626out: 3629out:
3627 return UNBLOCK_CONTINUE; 3630 return UNBLOCK_CONTINUE;
3628} 3631}
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 711dd5170376..bc6736d60786 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -37,14 +37,18 @@ EXPORT_SYMBOL(acl_by_type);
37struct posix_acl *get_cached_acl(struct inode *inode, int type) 37struct posix_acl *get_cached_acl(struct inode *inode, int type)
38{ 38{
39 struct posix_acl **p = acl_by_type(inode, type); 39 struct posix_acl **p = acl_by_type(inode, type);
40 struct posix_acl *acl = ACCESS_ONCE(*p); 40 struct posix_acl *acl;
41 if (acl) { 41
42 spin_lock(&inode->i_lock); 42 for (;;) {
43 acl = *p; 43 rcu_read_lock();
44 if (acl != ACL_NOT_CACHED) 44 acl = rcu_dereference(*p);
45 acl = posix_acl_dup(acl); 45 if (!acl || is_uncached_acl(acl) ||
46 spin_unlock(&inode->i_lock); 46 atomic_inc_not_zero(&acl->a_refcount))
47 break;
48 rcu_read_unlock();
49 cpu_relax();
47 } 50 }
51 rcu_read_unlock();
48 return acl; 52 return acl;
49} 53}
50EXPORT_SYMBOL(get_cached_acl); 54EXPORT_SYMBOL(get_cached_acl);
@@ -59,58 +63,72 @@ void set_cached_acl(struct inode *inode, int type, struct posix_acl *acl)
59{ 63{
60 struct posix_acl **p = acl_by_type(inode, type); 64 struct posix_acl **p = acl_by_type(inode, type);
61 struct posix_acl *old; 65 struct posix_acl *old;
62 spin_lock(&inode->i_lock); 66
63 old = *p; 67 old = xchg(p, posix_acl_dup(acl));
64 rcu_assign_pointer(*p, posix_acl_dup(acl)); 68 if (!is_uncached_acl(old))
65 spin_unlock(&inode->i_lock);
66 if (old != ACL_NOT_CACHED)
67 posix_acl_release(old); 69 posix_acl_release(old);
68} 70}
69EXPORT_SYMBOL(set_cached_acl); 71EXPORT_SYMBOL(set_cached_acl);
70 72
71void forget_cached_acl(struct inode *inode, int type) 73static void __forget_cached_acl(struct posix_acl **p)
72{ 74{
73 struct posix_acl **p = acl_by_type(inode, type);
74 struct posix_acl *old; 75 struct posix_acl *old;
75 spin_lock(&inode->i_lock); 76
76 old = *p; 77 old = xchg(p, ACL_NOT_CACHED);
77 *p = ACL_NOT_CACHED; 78 if (!is_uncached_acl(old))
78 spin_unlock(&inode->i_lock);
79 if (old != ACL_NOT_CACHED)
80 posix_acl_release(old); 79 posix_acl_release(old);
81} 80}
81
82void forget_cached_acl(struct inode *inode, int type)
83{
84 __forget_cached_acl(acl_by_type(inode, type));
85}
82EXPORT_SYMBOL(forget_cached_acl); 86EXPORT_SYMBOL(forget_cached_acl);
83 87
84void forget_all_cached_acls(struct inode *inode) 88void forget_all_cached_acls(struct inode *inode)
85{ 89{
86 struct posix_acl *old_access, *old_default; 90 __forget_cached_acl(&inode->i_acl);
87 spin_lock(&inode->i_lock); 91 __forget_cached_acl(&inode->i_default_acl);
88 old_access = inode->i_acl;
89 old_default = inode->i_default_acl;
90 inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED;
91 spin_unlock(&inode->i_lock);
92 if (old_access != ACL_NOT_CACHED)
93 posix_acl_release(old_access);
94 if (old_default != ACL_NOT_CACHED)
95 posix_acl_release(old_default);
96} 92}
97EXPORT_SYMBOL(forget_all_cached_acls); 93EXPORT_SYMBOL(forget_all_cached_acls);
98 94
99struct posix_acl *get_acl(struct inode *inode, int type) 95struct posix_acl *get_acl(struct inode *inode, int type)
100{ 96{
97 void *sentinel;
98 struct posix_acl **p;
101 struct posix_acl *acl; 99 struct posix_acl *acl;
102 100
101 /*
102 * The sentinel is used to detect when another operation like
103 * set_cached_acl() or forget_cached_acl() races with get_acl().
104 * It is guaranteed that is_uncached_acl(sentinel) is true.
105 */
106
103 acl = get_cached_acl(inode, type); 107 acl = get_cached_acl(inode, type);
104 if (acl != ACL_NOT_CACHED) 108 if (!is_uncached_acl(acl))
105 return acl; 109 return acl;
106 110
107 if (!IS_POSIXACL(inode)) 111 if (!IS_POSIXACL(inode))
108 return NULL; 112 return NULL;
109 113
114 sentinel = uncached_acl_sentinel(current);
115 p = acl_by_type(inode, type);
116
110 /* 117 /*
111 * A filesystem can force a ACL callback by just never filling the 118 * If the ACL isn't being read yet, set our sentinel. Otherwise, the
112 * ACL cache. But normally you'd fill the cache either at inode 119 * current value of the ACL will not be ACL_NOT_CACHED and so our own
113 * instantiation time, or on the first ->get_acl call. 120 * sentinel will not be set; another task will update the cache. We
121 * could wait for that other task to complete its job, but it's easier
122 * to just call ->get_acl to fetch the ACL ourself. (This is going to
123 * be an unlikely race.)
124 */
125 if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED)
126 /* fall through */ ;
127
128 /*
129 * Normally, the ACL returned by ->get_acl will be cached.
130 * A filesystem can prevent that by calling
131 * forget_cached_acl(inode, type) in ->get_acl.
114 * 132 *
115 * If the filesystem doesn't have a get_acl() function at all, we'll 133 * If the filesystem doesn't have a get_acl() function at all, we'll
116 * just create the negative cache entry. 134 * just create the negative cache entry.
@@ -119,7 +137,24 @@ struct posix_acl *get_acl(struct inode *inode, int type)
119 set_cached_acl(inode, type, NULL); 137 set_cached_acl(inode, type, NULL);
120 return NULL; 138 return NULL;
121 } 139 }
122 return inode->i_op->get_acl(inode, type); 140 acl = inode->i_op->get_acl(inode, type);
141
142 if (IS_ERR(acl)) {
143 /*
144 * Remove our sentinel so that we don't block future attempts
145 * to cache the ACL.
146 */
147 cmpxchg(p, sentinel, ACL_NOT_CACHED);
148 return acl;
149 }
150
151 /*
152 * Cache the result, but only if our sentinel is still in place.
153 */
154 posix_acl_dup(acl);
155 if (unlikely(cmpxchg(p, sentinel, acl) != sentinel))
156 posix_acl_release(acl);
157 return acl;
123} 158}
124EXPORT_SYMBOL(get_acl); 159EXPORT_SYMBOL(get_acl);
125 160
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index ec74bbedc873..dbed42f755e0 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -197,10 +197,8 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
197 197
198 size = reiserfs_xattr_get(inode, name, NULL, 0); 198 size = reiserfs_xattr_get(inode, name, NULL, 0);
199 if (size < 0) { 199 if (size < 0) {
200 if (size == -ENODATA || size == -ENOSYS) { 200 if (size == -ENODATA || size == -ENOSYS)
201 set_cached_acl(inode, type, NULL);
202 return NULL; 201 return NULL;
203 }
204 return ERR_PTR(size); 202 return ERR_PTR(size);
205 } 203 }
206 204
@@ -220,8 +218,6 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
220 } else { 218 } else {
221 acl = reiserfs_posix_acl_from_disk(value, retval); 219 acl = reiserfs_posix_acl_from_disk(value, retval);
222 } 220 }
223 if (!IS_ERR(acl))
224 set_cached_acl(inode, type, acl);
225 221
226 kfree(value); 222 kfree(value);
227 return acl; 223 return acl;
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 2d5df1f23bbc..b6e527b8eccb 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -158,22 +158,14 @@ xfs_get_acl(struct inode *inode, int type)
158 if (error) { 158 if (error) {
159 /* 159 /*
160 * If the attribute doesn't exist make sure we have a negative 160 * If the attribute doesn't exist make sure we have a negative
161 * cache entry, for any other error assume it is transient and 161 * cache entry, for any other error assume it is transient.
162 * leave the cache entry as ACL_NOT_CACHED.
163 */ 162 */
164 if (error == -ENOATTR) 163 if (error != -ENOATTR)
165 goto out_update_cache; 164 acl = ERR_PTR(error);
166 acl = ERR_PTR(error); 165 } else {
167 goto out; 166 acl = xfs_acl_from_disk(xfs_acl, len,
167 XFS_ACL_MAX_ENTRIES(ip->i_mount));
168 } 168 }
169
170 acl = xfs_acl_from_disk(xfs_acl, len, XFS_ACL_MAX_ENTRIES(ip->i_mount));
171 if (IS_ERR(acl))
172 goto out;
173
174out_update_cache:
175 set_cached_acl(inode, type, acl);
176out:
177 kmem_free(xfs_acl); 169 kmem_free(xfs_acl);
178 return acl; 170 return acl;
179} 171}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 14a97194b34b..329ed372d708 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -577,6 +577,18 @@ static inline void mapping_allow_writable(struct address_space *mapping)
577struct posix_acl; 577struct posix_acl;
578#define ACL_NOT_CACHED ((void *)(-1)) 578#define ACL_NOT_CACHED ((void *)(-1))
579 579
580static inline struct posix_acl *
581uncached_acl_sentinel(struct task_struct *task)
582{
583 return (void *)task + 1;
584}
585
586static inline bool
587is_uncached_acl(struct posix_acl *acl)
588{
589 return (long)acl & 1;
590}
591
580#define IOP_FASTPERM 0x0001 592#define IOP_FASTPERM 0x0001
581#define IOP_LOOKUP 0x0002 593#define IOP_LOOKUP 0x0002
582#define IOP_NOFOLLOW 0x0004 594#define IOP_NOFOLLOW 0x0004