diff options
Diffstat (limited to 'fs/nfs/nfs3acl.c')
-rw-r--r-- | fs/nfs/nfs3acl.c | 100 |
1 files changed, 85 insertions, 15 deletions
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 89b6468700e7..451112ff9aa4 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -113,6 +113,69 @@ int nfs3_removexattr(struct dentry *dentry, const char *name) | |||
113 | return nfs3_proc_setacl(inode, type, NULL); | 113 | return nfs3_proc_setacl(inode, type, NULL); |
114 | } | 114 | } |
115 | 115 | ||
116 | static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi) | ||
117 | { | ||
118 | if (nfsi->acl_access != ERR_PTR(-EAGAIN)) { | ||
119 | posix_acl_release(nfsi->acl_access); | ||
120 | nfsi->acl_access = ERR_PTR(-EAGAIN); | ||
121 | } | ||
122 | if (nfsi->acl_default != ERR_PTR(-EAGAIN)) { | ||
123 | posix_acl_release(nfsi->acl_default); | ||
124 | nfsi->acl_default = ERR_PTR(-EAGAIN); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | void nfs3_forget_cached_acls(struct inode *inode) | ||
129 | { | ||
130 | dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id, | ||
131 | inode->i_ino); | ||
132 | spin_lock(&inode->i_lock); | ||
133 | __nfs3_forget_cached_acls(NFS_I(inode)); | ||
134 | spin_unlock(&inode->i_lock); | ||
135 | } | ||
136 | |||
137 | static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type) | ||
138 | { | ||
139 | struct nfs_inode *nfsi = NFS_I(inode); | ||
140 | struct posix_acl *acl = ERR_PTR(-EAGAIN); | ||
141 | |||
142 | spin_lock(&inode->i_lock); | ||
143 | switch(type) { | ||
144 | case ACL_TYPE_ACCESS: | ||
145 | acl = nfsi->acl_access; | ||
146 | break; | ||
147 | |||
148 | case ACL_TYPE_DEFAULT: | ||
149 | acl = nfsi->acl_default; | ||
150 | break; | ||
151 | |||
152 | default: | ||
153 | return ERR_PTR(-EINVAL); | ||
154 | } | ||
155 | if (acl == ERR_PTR(-EAGAIN)) | ||
156 | acl = ERR_PTR(-EAGAIN); | ||
157 | else | ||
158 | acl = posix_acl_dup(acl); | ||
159 | spin_unlock(&inode->i_lock); | ||
160 | dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id, | ||
161 | inode->i_ino, type, acl); | ||
162 | return acl; | ||
163 | } | ||
164 | |||
165 | static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl, | ||
166 | struct posix_acl *dfacl) | ||
167 | { | ||
168 | struct nfs_inode *nfsi = NFS_I(inode); | ||
169 | |||
170 | dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id, | ||
171 | inode->i_ino, acl, dfacl); | ||
172 | spin_lock(&inode->i_lock); | ||
173 | __nfs3_forget_cached_acls(NFS_I(inode)); | ||
174 | nfsi->acl_access = posix_acl_dup(acl); | ||
175 | nfsi->acl_default = posix_acl_dup(dfacl); | ||
176 | spin_unlock(&inode->i_lock); | ||
177 | } | ||
178 | |||
116 | struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | 179 | struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) |
117 | { | 180 | { |
118 | struct nfs_server *server = NFS_SERVER(inode); | 181 | struct nfs_server *server = NFS_SERVER(inode); |
@@ -126,26 +189,32 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
126 | struct nfs3_getaclres res = { | 189 | struct nfs3_getaclres res = { |
127 | .fattr = &fattr, | 190 | .fattr = &fattr, |
128 | }; | 191 | }; |
129 | struct posix_acl *acl = NULL; | 192 | struct posix_acl *acl; |
130 | int status, count; | 193 | int status, count; |
131 | 194 | ||
132 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) | 195 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) |
133 | return ERR_PTR(-EOPNOTSUPP); | 196 | return ERR_PTR(-EOPNOTSUPP); |
134 | 197 | ||
135 | switch (type) { | 198 | status = nfs_revalidate_inode(server, inode); |
136 | case ACL_TYPE_ACCESS: | 199 | if (status < 0) |
137 | args.mask = NFS_ACLCNT|NFS_ACL; | 200 | return ERR_PTR(status); |
138 | break; | 201 | acl = nfs3_get_cached_acl(inode, type); |
139 | 202 | if (acl != ERR_PTR(-EAGAIN)) | |
140 | case ACL_TYPE_DEFAULT: | 203 | return acl; |
141 | if (!S_ISDIR(inode->i_mode)) | 204 | acl = NULL; |
142 | return NULL; | 205 | |
143 | args.mask = NFS_DFACLCNT|NFS_DFACL; | 206 | /* |
144 | break; | 207 | * Only get the access acl when explicitly requested: We don't |
145 | 208 | * need it for access decisions, and only some applications use | |
146 | default: | 209 | * it. Applications which request the access acl first are not |
147 | return ERR_PTR(-EINVAL); | 210 | * penalized from this optimization. |
148 | } | 211 | */ |
212 | if (type == ACL_TYPE_ACCESS) | ||
213 | args.mask |= NFS_ACLCNT|NFS_ACL; | ||
214 | if (S_ISDIR(inode->i_mode)) | ||
215 | args.mask |= NFS_DFACLCNT|NFS_DFACL; | ||
216 | if (args.mask == 0) | ||
217 | return NULL; | ||
149 | 218 | ||
150 | dprintk("NFS call getacl\n"); | 219 | dprintk("NFS call getacl\n"); |
151 | status = rpc_call(server->client_acl, ACLPROC3_GETACL, | 220 | status = rpc_call(server->client_acl, ACLPROC3_GETACL, |
@@ -180,6 +249,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
180 | res.acl_access = NULL; | 249 | res.acl_access = NULL; |
181 | } | 250 | } |
182 | } | 251 | } |
252 | nfs3_cache_acls(inode, res.acl_access, res.acl_default); | ||
183 | 253 | ||
184 | switch(type) { | 254 | switch(type) { |
185 | case ACL_TYPE_ACCESS: | 255 | case ACL_TYPE_ACCESS: |