diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-12 14:59:06 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-12 14:59:06 -0400 |
commit | 19e8a2f875a56009c0ce30389964aca452a85510 (patch) | |
tree | 22ad79d41c34555444030f34bebb979367d7ef32 | |
parent | 5d1365940a68dd57b031b6e3c07d7d451cd69daf (diff) | |
parent | 5a8132761609bd7e42db642d6f157140d5bf2ae8 (diff) |
Merge branch 'afs-dh' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull AFS updates from Al Viro:
"The AFS series posted by dhowells depended upon lookup_one_len()
rework; now that prereq is in the mainline, that series had been
rebased on top of it and got some exposure and testing..."
* 'afs-dh' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
afs: Do better accretion of small writes on newly created content
afs: Add stats for data transfer operations
afs: Trace protocol errors
afs: Locally edit directory data for mkdir/create/unlink/...
afs: Adjust the directory XDR structures
afs: Split the directory content defs into a header
afs: Fix directory handling
afs: Split the dynroot stuff out and give it its own ops tables
afs: Keep track of invalid-before version for dentry coherency
afs: Rearrange status mapping
afs: Make it possible to get the data version in readpage
afs: Init inode before accessing cache
afs: Introduce a statistics proc file
afs: Dump bad status record
afs: Implement @cell substitution handling
afs: Implement @sys substitution handling
afs: Prospectively look up extra files when doing a single lookup
afs: Don't over-increment the cell usage count when pinning it
afs: Fix checker warnings
vfs: Remove the const from dir_context::actor
-rw-r--r-- | Documentation/filesystems/afs.txt | 28 | ||||
-rw-r--r-- | fs/afs/Makefile | 2 | ||||
-rw-r--r-- | fs/afs/addr_list.c | 6 | ||||
-rw-r--r-- | fs/afs/afs.h | 27 | ||||
-rw-r--r-- | fs/afs/afs_fs.h | 2 | ||||
-rw-r--r-- | fs/afs/callback.c | 29 | ||||
-rw-r--r-- | fs/afs/cell.c | 12 | ||||
-rw-r--r-- | fs/afs/cmservice.c | 22 | ||||
-rw-r--r-- | fs/afs/dir.c | 923 | ||||
-rw-r--r-- | fs/afs/dir_edit.c | 505 | ||||
-rw-r--r-- | fs/afs/dynroot.c | 209 | ||||
-rw-r--r-- | fs/afs/file.c | 27 | ||||
-rw-r--r-- | fs/afs/flock.c | 2 | ||||
-rw-r--r-- | fs/afs/fsclient.c | 622 | ||||
-rw-r--r-- | fs/afs/inode.c | 69 | ||||
-rw-r--r-- | fs/afs/internal.h | 105 | ||||
-rw-r--r-- | fs/afs/main.c | 44 | ||||
-rw-r--r-- | fs/afs/proc.c | 326 | ||||
-rw-r--r-- | fs/afs/rotate.c | 2 | ||||
-rw-r--r-- | fs/afs/rxrpc.c | 9 | ||||
-rw-r--r-- | fs/afs/security.c | 13 | ||||
-rw-r--r-- | fs/afs/server.c | 14 | ||||
-rw-r--r-- | fs/afs/super.c | 11 | ||||
-rw-r--r-- | fs/afs/vlclient.c | 28 | ||||
-rw-r--r-- | fs/afs/write.c | 41 | ||||
-rw-r--r-- | fs/afs/xdr_fs.h | 103 | ||||
-rw-r--r-- | include/linux/fs.h | 2 | ||||
-rw-r--r-- | include/trace/events/afs.h | 113 |
28 files changed, 2703 insertions, 593 deletions
diff --git a/Documentation/filesystems/afs.txt b/Documentation/filesystems/afs.txt index c5254f6d234d..8c6ea7b41048 100644 --- a/Documentation/filesystems/afs.txt +++ b/Documentation/filesystems/afs.txt | |||
@@ -11,7 +11,7 @@ Contents: | |||
11 | - Proc filesystem. | 11 | - Proc filesystem. |
12 | - The cell database. | 12 | - The cell database. |
13 | - Security. | 13 | - Security. |
14 | - Examples. | 14 | - The @sys substitution. |
15 | 15 | ||
16 | 16 | ||
17 | ======== | 17 | ======== |
@@ -230,3 +230,29 @@ If a file is opened with a particular key and then the file descriptor is | |||
230 | passed to a process that doesn't have that key (perhaps over an AF_UNIX | 230 | passed to a process that doesn't have that key (perhaps over an AF_UNIX |
231 | socket), then the operations on the file will be made with key that was used to | 231 | socket), then the operations on the file will be made with key that was used to |
232 | open the file. | 232 | open the file. |
233 | |||
234 | |||
235 | ===================== | ||
236 | THE @SYS SUBSTITUTION | ||
237 | ===================== | ||
238 | |||
239 | The list of up to 16 @sys substitutions for the current network namespace can | ||
240 | be configured by writing a list to /proc/fs/afs/sysname: | ||
241 | |||
242 | [root@andromeda ~]# echo foo amd64_linux_26 >/proc/fs/afs/sysname | ||
243 | |||
244 | or cleared entirely by writing an empty list: | ||
245 | |||
246 | [root@andromeda ~]# echo >/proc/fs/afs/sysname | ||
247 | |||
248 | The current list for current network namespace can be retrieved by: | ||
249 | |||
250 | [root@andromeda ~]# cat /proc/fs/afs/sysname | ||
251 | foo | ||
252 | amd64_linux_26 | ||
253 | |||
254 | When @sys is being substituted for, each element of the list is tried in the | ||
255 | order given. | ||
256 | |||
257 | By default, the list will contain one item that conforms to the pattern | ||
258 | "<arch>_linux_26", amd64 being the name for x86_64. | ||
diff --git a/fs/afs/Makefile b/fs/afs/Makefile index 45b7fc405fa6..532acae25453 100644 --- a/fs/afs/Makefile +++ b/fs/afs/Makefile | |||
@@ -12,6 +12,8 @@ kafs-objs := \ | |||
12 | cell.o \ | 12 | cell.o \ |
13 | cmservice.o \ | 13 | cmservice.o \ |
14 | dir.o \ | 14 | dir.o \ |
15 | dir_edit.o \ | ||
16 | dynroot.o \ | ||
15 | file.o \ | 17 | file.o \ |
16 | flock.o \ | 18 | flock.o \ |
17 | fsclient.o \ | 19 | fsclient.o \ |
diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c index fd9f28b8a933..3bedfed608a2 100644 --- a/fs/afs/addr_list.c +++ b/fs/afs/addr_list.c | |||
@@ -243,9 +243,9 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port) | |||
243 | xport == a->sin6_port) | 243 | xport == a->sin6_port) |
244 | return; | 244 | return; |
245 | if (xdr == a->sin6_addr.s6_addr32[3] && | 245 | if (xdr == a->sin6_addr.s6_addr32[3] && |
246 | xport < a->sin6_port) | 246 | (u16 __force)xport < (u16 __force)a->sin6_port) |
247 | break; | 247 | break; |
248 | if (xdr < a->sin6_addr.s6_addr32[3]) | 248 | if ((u32 __force)xdr < (u32 __force)a->sin6_addr.s6_addr32[3]) |
249 | break; | 249 | break; |
250 | } | 250 | } |
251 | 251 | ||
@@ -280,7 +280,7 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port) | |||
280 | xport == a->sin6_port) | 280 | xport == a->sin6_port) |
281 | return; | 281 | return; |
282 | if (diff == 0 && | 282 | if (diff == 0 && |
283 | xport < a->sin6_port) | 283 | (u16 __force)xport < (u16 __force)a->sin6_port) |
284 | break; | 284 | break; |
285 | if (diff < 0) | 285 | if (diff < 0) |
286 | break; | 286 | break; |
diff --git a/fs/afs/afs.h b/fs/afs/afs.h index b94d0edc2b78..b4ff1f7ae4ab 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h | |||
@@ -67,10 +67,14 @@ typedef enum { | |||
67 | } afs_callback_type_t; | 67 | } afs_callback_type_t; |
68 | 68 | ||
69 | struct afs_callback { | 69 | struct afs_callback { |
70 | struct afs_fid fid; /* file identifier */ | 70 | unsigned version; /* Callback version */ |
71 | unsigned version; /* callback version */ | 71 | unsigned expiry; /* Time at which expires */ |
72 | unsigned expiry; /* time at which expires */ | 72 | afs_callback_type_t type; /* Type of callback */ |
73 | afs_callback_type_t type; /* type of callback */ | 73 | }; |
74 | |||
75 | struct afs_callback_break { | ||
76 | struct afs_fid fid; /* File identifier */ | ||
77 | struct afs_callback cb; /* Callback details */ | ||
74 | }; | 78 | }; |
75 | 79 | ||
76 | #define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */ | 80 | #define AFSCBMAX 50 /* maximum callbacks transferred per bulk op */ |
@@ -123,21 +127,20 @@ typedef u32 afs_access_t; | |||
123 | * AFS file status information | 127 | * AFS file status information |
124 | */ | 128 | */ |
125 | struct afs_file_status { | 129 | struct afs_file_status { |
126 | unsigned if_version; /* interface version */ | 130 | u64 size; /* file size */ |
127 | #define AFS_FSTATUS_VERSION 1 | 131 | afs_dataversion_t data_version; /* current data version */ |
132 | time_t mtime_client; /* last time client changed data */ | ||
133 | time_t mtime_server; /* last time server changed data */ | ||
134 | unsigned abort_code; /* Abort if bulk-fetching this failed */ | ||
128 | 135 | ||
129 | afs_file_type_t type; /* file type */ | 136 | afs_file_type_t type; /* file type */ |
130 | unsigned nlink; /* link count */ | 137 | unsigned nlink; /* link count */ |
131 | u64 size; /* file size */ | ||
132 | afs_dataversion_t data_version; /* current data version */ | ||
133 | u32 author; /* author ID */ | 138 | u32 author; /* author ID */ |
134 | kuid_t owner; /* owner ID */ | 139 | u32 owner; /* owner ID */ |
135 | kgid_t group; /* group ID */ | 140 | u32 group; /* group ID */ |
136 | afs_access_t caller_access; /* access rights for authenticated caller */ | 141 | afs_access_t caller_access; /* access rights for authenticated caller */ |
137 | afs_access_t anon_access; /* access rights for unauthenticated caller */ | 142 | afs_access_t anon_access; /* access rights for unauthenticated caller */ |
138 | umode_t mode; /* UNIX mode */ | 143 | umode_t mode; /* UNIX mode */ |
139 | time_t mtime_client; /* last time client changed data */ | ||
140 | time_t mtime_server; /* last time server changed data */ | ||
141 | s32 lock_count; /* file lock count (0=UNLK -1=WRLCK +ve=#RDLCK */ | 144 | s32 lock_count; /* file lock count (0=UNLK -1=WRLCK +ve=#RDLCK */ |
142 | }; | 145 | }; |
143 | 146 | ||
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h index d47b6d01e4c0..ddfa88a7a9c0 100644 --- a/fs/afs/afs_fs.h +++ b/fs/afs/afs_fs.h | |||
@@ -31,10 +31,12 @@ enum AFS_FS_Operations { | |||
31 | FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */ | 31 | FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */ |
32 | FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */ | 32 | FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */ |
33 | FSGETROOTVOLUME = 151, /* AFS Get root volume name */ | 33 | FSGETROOTVOLUME = 151, /* AFS Get root volume name */ |
34 | FSBULKSTATUS = 155, /* AFS Fetch multiple file statuses */ | ||
34 | FSSETLOCK = 156, /* AFS Request a file lock */ | 35 | FSSETLOCK = 156, /* AFS Request a file lock */ |
35 | FSEXTENDLOCK = 157, /* AFS Extend a file lock */ | 36 | FSEXTENDLOCK = 157, /* AFS Extend a file lock */ |
36 | FSRELEASELOCK = 158, /* AFS Release a file lock */ | 37 | FSRELEASELOCK = 158, /* AFS Release a file lock */ |
37 | FSLOOKUP = 161, /* AFS lookup file in directory */ | 38 | FSLOOKUP = 161, /* AFS lookup file in directory */ |
39 | FSINLINEBULKSTATUS = 65536, /* AFS Fetch multiple file statuses with inline errors */ | ||
38 | FSFETCHDATA64 = 65537, /* AFS Fetch file data */ | 40 | FSFETCHDATA64 = 65537, /* AFS Fetch file data */ |
39 | FSSTOREDATA64 = 65538, /* AFS Store file data */ | 41 | FSSTOREDATA64 = 65538, /* AFS Store file data */ |
40 | FSGIVEUPALLCALLBACKS = 65539, /* AFS Give up all outstanding callbacks on a server */ | 42 | FSGIVEUPALLCALLBACKS = 65539, /* AFS Give up all outstanding callbacks on a server */ |
diff --git a/fs/afs/callback.c b/fs/afs/callback.c index f4291b576054..abd9a84f4e88 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c | |||
@@ -97,26 +97,6 @@ again: | |||
97 | } | 97 | } |
98 | 98 | ||
99 | /* | 99 | /* |
100 | * Set a vnode's interest on a server. | ||
101 | */ | ||
102 | void afs_set_cb_interest(struct afs_vnode *vnode, struct afs_cb_interest *cbi) | ||
103 | { | ||
104 | struct afs_cb_interest *old_cbi = NULL; | ||
105 | |||
106 | if (vnode->cb_interest == cbi) | ||
107 | return; | ||
108 | |||
109 | write_seqlock(&vnode->cb_lock); | ||
110 | if (vnode->cb_interest != cbi) { | ||
111 | afs_get_cb_interest(cbi); | ||
112 | old_cbi = vnode->cb_interest; | ||
113 | vnode->cb_interest = cbi; | ||
114 | } | ||
115 | write_sequnlock(&vnode->cb_lock); | ||
116 | afs_put_cb_interest(afs_v2net(vnode), cbi); | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Remove an interest on a server. | 100 | * Remove an interest on a server. |
121 | */ | 101 | */ |
122 | void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi) | 102 | void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi) |
@@ -150,6 +130,7 @@ void afs_break_callback(struct afs_vnode *vnode) | |||
150 | 130 | ||
151 | write_seqlock(&vnode->cb_lock); | 131 | write_seqlock(&vnode->cb_lock); |
152 | 132 | ||
133 | clear_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); | ||
153 | if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { | 134 | if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { |
154 | vnode->cb_break++; | 135 | vnode->cb_break++; |
155 | afs_clear_permits(vnode); | 136 | afs_clear_permits(vnode); |
@@ -207,7 +188,7 @@ static void afs_break_one_callback(struct afs_server *server, | |||
207 | * allow the fileserver to break callback promises | 188 | * allow the fileserver to break callback promises |
208 | */ | 189 | */ |
209 | void afs_break_callbacks(struct afs_server *server, size_t count, | 190 | void afs_break_callbacks(struct afs_server *server, size_t count, |
210 | struct afs_callback callbacks[]) | 191 | struct afs_callback_break *callbacks) |
211 | { | 192 | { |
212 | _enter("%p,%zu,", server, count); | 193 | _enter("%p,%zu,", server, count); |
213 | 194 | ||
@@ -219,9 +200,9 @@ void afs_break_callbacks(struct afs_server *server, size_t count, | |||
219 | callbacks->fid.vid, | 200 | callbacks->fid.vid, |
220 | callbacks->fid.vnode, | 201 | callbacks->fid.vnode, |
221 | callbacks->fid.unique, | 202 | callbacks->fid.unique, |
222 | callbacks->version, | 203 | callbacks->cb.version, |
223 | callbacks->expiry, | 204 | callbacks->cb.expiry, |
224 | callbacks->type | 205 | callbacks->cb.type |
225 | ); | 206 | ); |
226 | afs_break_one_callback(server, &callbacks->fid); | 207 | afs_break_one_callback(server, &callbacks->fid); |
227 | } | 208 | } |
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index 4235a05afc76..fdf4c36cff79 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <keys/rxrpc-type.h> | 18 | #include <keys/rxrpc-type.h> |
19 | #include "internal.h" | 19 | #include "internal.h" |
20 | 20 | ||
21 | unsigned __read_mostly afs_cell_gc_delay = 10; | 21 | static unsigned __read_mostly afs_cell_gc_delay = 10; |
22 | 22 | ||
23 | static void afs_manage_cell(struct work_struct *); | 23 | static void afs_manage_cell(struct work_struct *); |
24 | 24 | ||
@@ -75,7 +75,7 @@ struct afs_cell *afs_lookup_cell_rcu(struct afs_net *net, | |||
75 | cell = rcu_dereference_raw(net->ws_cell); | 75 | cell = rcu_dereference_raw(net->ws_cell); |
76 | if (cell) { | 76 | if (cell) { |
77 | afs_get_cell(cell); | 77 | afs_get_cell(cell); |
78 | continue; | 78 | break; |
79 | } | 79 | } |
80 | ret = -EDESTADDRREQ; | 80 | ret = -EDESTADDRREQ; |
81 | continue; | 81 | continue; |
@@ -130,6 +130,8 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, | |||
130 | _leave(" = -ENAMETOOLONG"); | 130 | _leave(" = -ENAMETOOLONG"); |
131 | return ERR_PTR(-ENAMETOOLONG); | 131 | return ERR_PTR(-ENAMETOOLONG); |
132 | } | 132 | } |
133 | if (namelen == 5 && memcmp(name, "@cell", 5) == 0) | ||
134 | return ERR_PTR(-EINVAL); | ||
133 | 135 | ||
134 | _enter("%*.*s,%s", namelen, namelen, name, vllist); | 136 | _enter("%*.*s,%s", namelen, namelen, name, vllist); |
135 | 137 | ||
@@ -334,8 +336,8 @@ int afs_cell_init(struct afs_net *net, const char *rootcell) | |||
334 | return PTR_ERR(new_root); | 336 | return PTR_ERR(new_root); |
335 | } | 337 | } |
336 | 338 | ||
337 | set_bit(AFS_CELL_FL_NO_GC, &new_root->flags); | 339 | if (!test_and_set_bit(AFS_CELL_FL_NO_GC, &new_root->flags)) |
338 | afs_get_cell(new_root); | 340 | afs_get_cell(new_root); |
339 | 341 | ||
340 | /* install the new cell */ | 342 | /* install the new cell */ |
341 | write_seqlock(&net->cells_lock); | 343 | write_seqlock(&net->cells_lock); |
@@ -411,7 +413,7 @@ static void afs_cell_destroy(struct rcu_head *rcu) | |||
411 | 413 | ||
412 | ASSERTCMP(atomic_read(&cell->usage), ==, 0); | 414 | ASSERTCMP(atomic_read(&cell->usage), ==, 0); |
413 | 415 | ||
414 | afs_put_addrlist(cell->vl_addrs); | 416 | afs_put_addrlist(rcu_access_pointer(cell->vl_addrs)); |
415 | key_put(cell->anonymous_key); | 417 | key_put(cell->anonymous_key); |
416 | kfree(cell); | 418 | kfree(cell); |
417 | 419 | ||
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index 41e277f57b20..357de908df3a 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c | |||
@@ -178,8 +178,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work) | |||
178 | */ | 178 | */ |
179 | static int afs_deliver_cb_callback(struct afs_call *call) | 179 | static int afs_deliver_cb_callback(struct afs_call *call) |
180 | { | 180 | { |
181 | struct afs_callback_break *cb; | ||
181 | struct sockaddr_rxrpc srx; | 182 | struct sockaddr_rxrpc srx; |
182 | struct afs_callback *cb; | ||
183 | struct afs_server *server; | 183 | struct afs_server *server; |
184 | __be32 *bp; | 184 | __be32 *bp; |
185 | int ret, loop; | 185 | int ret, loop; |
@@ -201,7 +201,7 @@ static int afs_deliver_cb_callback(struct afs_call *call) | |||
201 | call->count = ntohl(call->tmp); | 201 | call->count = ntohl(call->tmp); |
202 | _debug("FID count: %u", call->count); | 202 | _debug("FID count: %u", call->count); |
203 | if (call->count > AFSCBMAX) | 203 | if (call->count > AFSCBMAX) |
204 | return -EBADMSG; | 204 | return afs_protocol_error(call, -EBADMSG); |
205 | 205 | ||
206 | call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL); | 206 | call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL); |
207 | if (!call->buffer) | 207 | if (!call->buffer) |
@@ -218,7 +218,7 @@ static int afs_deliver_cb_callback(struct afs_call *call) | |||
218 | 218 | ||
219 | _debug("unmarshall FID array"); | 219 | _debug("unmarshall FID array"); |
220 | call->request = kcalloc(call->count, | 220 | call->request = kcalloc(call->count, |
221 | sizeof(struct afs_callback), | 221 | sizeof(struct afs_callback_break), |
222 | GFP_KERNEL); | 222 | GFP_KERNEL); |
223 | if (!call->request) | 223 | if (!call->request) |
224 | return -ENOMEM; | 224 | return -ENOMEM; |
@@ -229,7 +229,7 @@ static int afs_deliver_cb_callback(struct afs_call *call) | |||
229 | cb->fid.vid = ntohl(*bp++); | 229 | cb->fid.vid = ntohl(*bp++); |
230 | cb->fid.vnode = ntohl(*bp++); | 230 | cb->fid.vnode = ntohl(*bp++); |
231 | cb->fid.unique = ntohl(*bp++); | 231 | cb->fid.unique = ntohl(*bp++); |
232 | cb->type = AFSCM_CB_UNTYPED; | 232 | cb->cb.type = AFSCM_CB_UNTYPED; |
233 | } | 233 | } |
234 | 234 | ||
235 | call->offset = 0; | 235 | call->offset = 0; |
@@ -245,7 +245,7 @@ static int afs_deliver_cb_callback(struct afs_call *call) | |||
245 | call->count2 = ntohl(call->tmp); | 245 | call->count2 = ntohl(call->tmp); |
246 | _debug("CB count: %u", call->count2); | 246 | _debug("CB count: %u", call->count2); |
247 | if (call->count2 != call->count && call->count2 != 0) | 247 | if (call->count2 != call->count && call->count2 != 0) |
248 | return -EBADMSG; | 248 | return afs_protocol_error(call, -EBADMSG); |
249 | call->offset = 0; | 249 | call->offset = 0; |
250 | call->unmarshall++; | 250 | call->unmarshall++; |
251 | 251 | ||
@@ -260,9 +260,9 @@ static int afs_deliver_cb_callback(struct afs_call *call) | |||
260 | cb = call->request; | 260 | cb = call->request; |
261 | bp = call->buffer; | 261 | bp = call->buffer; |
262 | for (loop = call->count2; loop > 0; loop--, cb++) { | 262 | for (loop = call->count2; loop > 0; loop--, cb++) { |
263 | cb->version = ntohl(*bp++); | 263 | cb->cb.version = ntohl(*bp++); |
264 | cb->expiry = ntohl(*bp++); | 264 | cb->cb.expiry = ntohl(*bp++); |
265 | cb->type = ntohl(*bp++); | 265 | cb->cb.type = ntohl(*bp++); |
266 | } | 266 | } |
267 | 267 | ||
268 | call->offset = 0; | 268 | call->offset = 0; |
@@ -500,9 +500,9 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call) | |||
500 | 500 | ||
501 | b = call->buffer; | 501 | b = call->buffer; |
502 | r = call->request; | 502 | r = call->request; |
503 | r->time_low = ntohl(b[0]); | 503 | r->time_low = b[0]; |
504 | r->time_mid = ntohl(b[1]); | 504 | r->time_mid = htons(ntohl(b[1])); |
505 | r->time_hi_and_version = ntohl(b[2]); | 505 | r->time_hi_and_version = htons(ntohl(b[2])); |
506 | r->clock_seq_hi_and_reserved = ntohl(b[3]); | 506 | r->clock_seq_hi_and_reserved = ntohl(b[3]); |
507 | r->clock_seq_low = ntohl(b[4]); | 507 | r->clock_seq_low = ntohl(b[4]); |
508 | 508 | ||
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index ba2b458b36d1..5889f70d4d27 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* dir.c: AFS filesystem directory handling | 1 | /* dir.c: AFS filesystem directory handling |
2 | * | 2 | * |
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2002, 2018 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -10,27 +10,26 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
16 | #include <linux/namei.h> | 14 | #include <linux/namei.h> |
17 | #include <linux/pagemap.h> | 15 | #include <linux/pagemap.h> |
16 | #include <linux/swap.h> | ||
18 | #include <linux/ctype.h> | 17 | #include <linux/ctype.h> |
19 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
20 | #include <linux/dns_resolver.h> | 19 | #include <linux/task_io_accounting_ops.h> |
21 | #include "internal.h" | 20 | #include "internal.h" |
21 | #include "xdr_fs.h" | ||
22 | 22 | ||
23 | static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | 23 | static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, |
24 | unsigned int flags); | 24 | unsigned int flags); |
25 | static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry, | ||
26 | unsigned int flags); | ||
27 | static int afs_dir_open(struct inode *inode, struct file *file); | 25 | static int afs_dir_open(struct inode *inode, struct file *file); |
28 | static int afs_readdir(struct file *file, struct dir_context *ctx); | 26 | static int afs_readdir(struct file *file, struct dir_context *ctx); |
29 | static int afs_d_revalidate(struct dentry *dentry, unsigned int flags); | 27 | static int afs_d_revalidate(struct dentry *dentry, unsigned int flags); |
30 | static int afs_d_delete(const struct dentry *dentry); | 28 | static int afs_d_delete(const struct dentry *dentry); |
31 | static void afs_d_release(struct dentry *dentry); | 29 | static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen, |
32 | static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen, | ||
33 | loff_t fpos, u64 ino, unsigned dtype); | 30 | loff_t fpos, u64 ino, unsigned dtype); |
31 | static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen, | ||
32 | loff_t fpos, u64 ino, unsigned dtype); | ||
34 | static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | 33 | static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, |
35 | bool excl); | 34 | bool excl); |
36 | static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); | 35 | static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); |
@@ -43,6 +42,14 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, | |||
43 | static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | 42 | static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, |
44 | struct inode *new_dir, struct dentry *new_dentry, | 43 | struct inode *new_dir, struct dentry *new_dentry, |
45 | unsigned int flags); | 44 | unsigned int flags); |
45 | static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags); | ||
46 | static void afs_dir_invalidatepage(struct page *page, unsigned int offset, | ||
47 | unsigned int length); | ||
48 | |||
49 | static int afs_dir_set_page_dirty(struct page *page) | ||
50 | { | ||
51 | BUG(); /* This should never happen. */ | ||
52 | } | ||
46 | 53 | ||
47 | const struct file_operations afs_dir_file_operations = { | 54 | const struct file_operations afs_dir_file_operations = { |
48 | .open = afs_dir_open, | 55 | .open = afs_dir_open, |
@@ -67,15 +74,10 @@ const struct inode_operations afs_dir_inode_operations = { | |||
67 | .listxattr = afs_listxattr, | 74 | .listxattr = afs_listxattr, |
68 | }; | 75 | }; |
69 | 76 | ||
70 | const struct file_operations afs_dynroot_file_operations = { | 77 | const struct address_space_operations afs_dir_aops = { |
71 | .open = dcache_dir_open, | 78 | .set_page_dirty = afs_dir_set_page_dirty, |
72 | .release = dcache_dir_close, | 79 | .releasepage = afs_dir_releasepage, |
73 | .iterate_shared = dcache_readdir, | 80 | .invalidatepage = afs_dir_invalidatepage, |
74 | .llseek = dcache_dir_lseek, | ||
75 | }; | ||
76 | |||
77 | const struct inode_operations afs_dynroot_inode_operations = { | ||
78 | .lookup = afs_dynroot_lookup, | ||
79 | }; | 81 | }; |
80 | 82 | ||
81 | const struct dentry_operations afs_fs_dentry_operations = { | 83 | const struct dentry_operations afs_fs_dentry_operations = { |
@@ -85,91 +87,38 @@ const struct dentry_operations afs_fs_dentry_operations = { | |||
85 | .d_automount = afs_d_automount, | 87 | .d_automount = afs_d_automount, |
86 | }; | 88 | }; |
87 | 89 | ||
88 | #define AFS_DIR_HASHTBL_SIZE 128 | 90 | struct afs_lookup_one_cookie { |
89 | #define AFS_DIR_DIRENT_SIZE 32 | 91 | struct dir_context ctx; |
90 | #define AFS_DIRENT_PER_BLOCK 64 | 92 | struct qstr name; |
91 | 93 | bool found; | |
92 | union afs_dirent { | 94 | struct afs_fid fid; |
93 | struct { | ||
94 | uint8_t valid; | ||
95 | uint8_t unused[1]; | ||
96 | __be16 hash_next; | ||
97 | __be32 vnode; | ||
98 | __be32 unique; | ||
99 | uint8_t name[16]; | ||
100 | uint8_t overflow[4]; /* if any char of the name (inc | ||
101 | * NUL) reaches here, consume | ||
102 | * the next dirent too */ | ||
103 | } u; | ||
104 | uint8_t extended_name[32]; | ||
105 | }; | ||
106 | |||
107 | /* AFS directory page header (one at the beginning of every 2048-byte chunk) */ | ||
108 | struct afs_dir_pagehdr { | ||
109 | __be16 npages; | ||
110 | __be16 magic; | ||
111 | #define AFS_DIR_MAGIC htons(1234) | ||
112 | uint8_t nentries; | ||
113 | uint8_t bitmap[8]; | ||
114 | uint8_t pad[19]; | ||
115 | }; | ||
116 | |||
117 | /* directory block layout */ | ||
118 | union afs_dir_block { | ||
119 | |||
120 | struct afs_dir_pagehdr pagehdr; | ||
121 | |||
122 | struct { | ||
123 | struct afs_dir_pagehdr pagehdr; | ||
124 | uint8_t alloc_ctrs[128]; | ||
125 | /* dir hash table */ | ||
126 | uint16_t hashtable[AFS_DIR_HASHTBL_SIZE]; | ||
127 | } hdr; | ||
128 | |||
129 | union afs_dirent dirents[AFS_DIRENT_PER_BLOCK]; | ||
130 | }; | ||
131 | |||
132 | /* layout on a linux VM page */ | ||
133 | struct afs_dir_page { | ||
134 | union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)]; | ||
135 | }; | 95 | }; |
136 | 96 | ||
137 | struct afs_lookup_cookie { | 97 | struct afs_lookup_cookie { |
138 | struct dir_context ctx; | 98 | struct dir_context ctx; |
139 | struct afs_fid fid; | 99 | struct qstr name; |
140 | struct qstr name; | 100 | bool found; |
141 | int found; | 101 | bool one_only; |
102 | unsigned short nr_fids; | ||
103 | struct afs_file_status *statuses; | ||
104 | struct afs_callback *callbacks; | ||
105 | struct afs_fid fids[50]; | ||
142 | }; | 106 | }; |
143 | 107 | ||
144 | /* | 108 | /* |
145 | * check that a directory page is valid | 109 | * check that a directory page is valid |
146 | */ | 110 | */ |
147 | bool afs_dir_check_page(struct inode *dir, struct page *page) | 111 | static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page, |
112 | loff_t i_size) | ||
148 | { | 113 | { |
149 | struct afs_dir_page *dbuf; | 114 | struct afs_xdr_dir_page *dbuf; |
150 | struct afs_vnode *vnode = AFS_FS_I(dir); | 115 | loff_t latter, off; |
151 | loff_t latter, i_size, off; | ||
152 | int tmp, qty; | 116 | int tmp, qty; |
153 | 117 | ||
154 | #if 0 | ||
155 | /* check the page count */ | ||
156 | qty = desc.size / sizeof(dbuf->blocks[0]); | ||
157 | if (qty == 0) | ||
158 | goto error; | ||
159 | |||
160 | if (page->index == 0 && qty != ntohs(dbuf->blocks[0].pagehdr.npages)) { | ||
161 | printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n", | ||
162 | __func__, dir->i_ino, qty, | ||
163 | ntohs(dbuf->blocks[0].pagehdr.npages)); | ||
164 | goto error; | ||
165 | } | ||
166 | #endif | ||
167 | |||
168 | /* Determine how many magic numbers there should be in this page, but | 118 | /* Determine how many magic numbers there should be in this page, but |
169 | * we must take care because the directory may change size under us. | 119 | * we must take care because the directory may change size under us. |
170 | */ | 120 | */ |
171 | off = page_offset(page); | 121 | off = page_offset(page); |
172 | i_size = i_size_read(dir); | ||
173 | if (i_size <= off) | 122 | if (i_size <= off) |
174 | goto checked; | 123 | goto checked; |
175 | 124 | ||
@@ -178,112 +127,225 @@ bool afs_dir_check_page(struct inode *dir, struct page *page) | |||
178 | qty = PAGE_SIZE; | 127 | qty = PAGE_SIZE; |
179 | else | 128 | else |
180 | qty = latter; | 129 | qty = latter; |
181 | qty /= sizeof(union afs_dir_block); | 130 | qty /= sizeof(union afs_xdr_dir_block); |
182 | 131 | ||
183 | /* check them */ | 132 | /* check them */ |
184 | dbuf = page_address(page); | 133 | dbuf = kmap(page); |
185 | for (tmp = 0; tmp < qty; tmp++) { | 134 | for (tmp = 0; tmp < qty; tmp++) { |
186 | if (dbuf->blocks[tmp].pagehdr.magic != AFS_DIR_MAGIC) { | 135 | if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) { |
187 | printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n", | 136 | printk("kAFS: %s(%lx): bad magic %d/%d is %04hx\n", |
188 | __func__, dir->i_ino, tmp, qty, | 137 | __func__, dvnode->vfs_inode.i_ino, tmp, qty, |
189 | ntohs(dbuf->blocks[tmp].pagehdr.magic)); | 138 | ntohs(dbuf->blocks[tmp].hdr.magic)); |
190 | trace_afs_dir_check_failed(vnode, off, i_size); | 139 | trace_afs_dir_check_failed(dvnode, off, i_size); |
140 | kunmap(page); | ||
191 | goto error; | 141 | goto error; |
192 | } | 142 | } |
143 | |||
144 | /* Make sure each block is NUL terminated so we can reasonably | ||
145 | * use string functions on it. The filenames in the page | ||
146 | * *should* be NUL-terminated anyway. | ||
147 | */ | ||
148 | ((u8 *)&dbuf->blocks[tmp])[AFS_DIR_BLOCK_SIZE - 1] = 0; | ||
193 | } | 149 | } |
194 | 150 | ||
151 | kunmap(page); | ||
152 | |||
195 | checked: | 153 | checked: |
196 | SetPageChecked(page); | 154 | afs_stat_v(dvnode, n_read_dir); |
197 | return true; | 155 | return true; |
198 | 156 | ||
199 | error: | 157 | error: |
200 | SetPageError(page); | ||
201 | return false; | 158 | return false; |
202 | } | 159 | } |
203 | 160 | ||
204 | /* | 161 | /* |
205 | * discard a page cached in the pagecache | 162 | * open an AFS directory file |
206 | */ | 163 | */ |
207 | static inline void afs_dir_put_page(struct page *page) | 164 | static int afs_dir_open(struct inode *inode, struct file *file) |
208 | { | 165 | { |
209 | kunmap(page); | 166 | _enter("{%lu}", inode->i_ino); |
210 | unlock_page(page); | 167 | |
211 | put_page(page); | 168 | BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); |
169 | BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); | ||
170 | |||
171 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) | ||
172 | return -ENOENT; | ||
173 | |||
174 | return afs_open(inode, file); | ||
212 | } | 175 | } |
213 | 176 | ||
214 | /* | 177 | /* |
215 | * get a page into the pagecache | 178 | * Read the directory into the pagecache in one go, scrubbing the previous |
179 | * contents. The list of pages is returned, pinning them so that they don't | ||
180 | * get reclaimed during the iteration. | ||
216 | */ | 181 | */ |
217 | static struct page *afs_dir_get_page(struct inode *dir, unsigned long index, | 182 | static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) |
218 | struct key *key) | ||
219 | { | 183 | { |
220 | struct page *page; | 184 | struct afs_read *req; |
221 | _enter("{%lu},%lu", dir->i_ino, index); | 185 | loff_t i_size; |
222 | 186 | int nr_pages, nr_inline, i, n; | |
223 | page = read_cache_page(dir->i_mapping, index, afs_page_filler, key); | 187 | int ret = -ENOMEM; |
224 | if (!IS_ERR(page)) { | 188 | |
225 | lock_page(page); | 189 | retry: |
226 | kmap(page); | 190 | i_size = i_size_read(&dvnode->vfs_inode); |
227 | if (unlikely(!PageChecked(page))) { | 191 | if (i_size < 2048) |
228 | if (PageError(page)) | 192 | return ERR_PTR(-EIO); |
229 | goto fail; | 193 | if (i_size > 2048 * 1024) |
230 | } | 194 | return ERR_PTR(-EFBIG); |
195 | |||
196 | _enter("%llu", i_size); | ||
197 | |||
198 | /* Get a request record to hold the page list. We want to hold it | ||
199 | * inline if we can, but we don't want to make an order 1 allocation. | ||
200 | */ | ||
201 | nr_pages = (i_size + PAGE_SIZE - 1) / PAGE_SIZE; | ||
202 | nr_inline = nr_pages; | ||
203 | if (nr_inline > (PAGE_SIZE - sizeof(*req)) / sizeof(struct page *)) | ||
204 | nr_inline = 0; | ||
205 | |||
206 | req = kzalloc(sizeof(*req) + sizeof(struct page *) * nr_inline, | ||
207 | GFP_KERNEL); | ||
208 | if (!req) | ||
209 | return ERR_PTR(-ENOMEM); | ||
210 | |||
211 | refcount_set(&req->usage, 1); | ||
212 | req->nr_pages = nr_pages; | ||
213 | req->actual_len = i_size; /* May change */ | ||
214 | req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */ | ||
215 | req->data_version = dvnode->status.data_version; /* May change */ | ||
216 | if (nr_inline > 0) { | ||
217 | req->pages = req->array; | ||
218 | } else { | ||
219 | req->pages = kcalloc(nr_pages, sizeof(struct page *), | ||
220 | GFP_KERNEL); | ||
221 | if (!req->pages) | ||
222 | goto error; | ||
231 | } | 223 | } |
232 | return page; | ||
233 | 224 | ||
234 | fail: | 225 | /* Get a list of all the pages that hold or will hold the directory |
235 | afs_dir_put_page(page); | 226 | * content. We need to fill in any gaps that we might find where the |
236 | _leave(" = -EIO"); | 227 | * memory reclaimer has been at work. If there are any gaps, we will |
237 | return ERR_PTR(-EIO); | 228 | * need to reread the entire directory contents. |
238 | } | 229 | */ |
230 | i = 0; | ||
231 | do { | ||
232 | n = find_get_pages_contig(dvnode->vfs_inode.i_mapping, i, | ||
233 | req->nr_pages - i, | ||
234 | req->pages + i); | ||
235 | _debug("find %u at %u/%u", n, i, req->nr_pages); | ||
236 | if (n == 0) { | ||
237 | gfp_t gfp = dvnode->vfs_inode.i_mapping->gfp_mask; | ||
238 | |||
239 | if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) | ||
240 | afs_stat_v(dvnode, n_inval); | ||
241 | |||
242 | ret = -ENOMEM; | ||
243 | req->pages[i] = __page_cache_alloc(gfp); | ||
244 | if (!req->pages[i]) | ||
245 | goto error; | ||
246 | ret = add_to_page_cache_lru(req->pages[i], | ||
247 | dvnode->vfs_inode.i_mapping, | ||
248 | i, gfp); | ||
249 | if (ret < 0) | ||
250 | goto error; | ||
251 | |||
252 | set_page_private(req->pages[i], 1); | ||
253 | SetPagePrivate(req->pages[i]); | ||
254 | unlock_page(req->pages[i]); | ||
255 | i++; | ||
256 | } else { | ||
257 | i += n; | ||
258 | } | ||
259 | } while (i < req->nr_pages); | ||
239 | 260 | ||
240 | /* | 261 | /* If we're going to reload, we need to lock all the pages to prevent |
241 | * open an AFS directory file | 262 | * races. |
242 | */ | 263 | */ |
243 | static int afs_dir_open(struct inode *inode, struct file *file) | 264 | if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { |
244 | { | 265 | ret = -ERESTARTSYS; |
245 | _enter("{%lu}", inode->i_ino); | 266 | for (i = 0; i < req->nr_pages; i++) |
267 | if (lock_page_killable(req->pages[i]) < 0) | ||
268 | goto error_unlock; | ||
246 | 269 | ||
247 | BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); | 270 | if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) |
248 | BUILD_BUG_ON(sizeof(union afs_dirent) != 32); | 271 | goto success; |
249 | 272 | ||
250 | if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags)) | 273 | ret = afs_fetch_data(dvnode, key, req); |
251 | return -ENOENT; | 274 | if (ret < 0) |
275 | goto error_unlock_all; | ||
252 | 276 | ||
253 | return afs_open(inode, file); | 277 | task_io_account_read(PAGE_SIZE * req->nr_pages); |
278 | |||
279 | if (req->len < req->file_size) | ||
280 | goto content_has_grown; | ||
281 | |||
282 | /* Validate the data we just read. */ | ||
283 | ret = -EIO; | ||
284 | for (i = 0; i < req->nr_pages; i++) | ||
285 | if (!afs_dir_check_page(dvnode, req->pages[i], | ||
286 | req->actual_len)) | ||
287 | goto error_unlock_all; | ||
288 | |||
289 | // TODO: Trim excess pages | ||
290 | |||
291 | set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags); | ||
292 | } | ||
293 | |||
294 | success: | ||
295 | i = req->nr_pages; | ||
296 | while (i > 0) | ||
297 | unlock_page(req->pages[--i]); | ||
298 | return req; | ||
299 | |||
300 | error_unlock_all: | ||
301 | i = req->nr_pages; | ||
302 | error_unlock: | ||
303 | while (i > 0) | ||
304 | unlock_page(req->pages[--i]); | ||
305 | error: | ||
306 | afs_put_read(req); | ||
307 | _leave(" = %d", ret); | ||
308 | return ERR_PTR(ret); | ||
309 | |||
310 | content_has_grown: | ||
311 | i = req->nr_pages; | ||
312 | while (i > 0) | ||
313 | unlock_page(req->pages[--i]); | ||
314 | afs_put_read(req); | ||
315 | goto retry; | ||
254 | } | 316 | } |
255 | 317 | ||
256 | /* | 318 | /* |
257 | * deal with one block in an AFS directory | 319 | * deal with one block in an AFS directory |
258 | */ | 320 | */ |
259 | static int afs_dir_iterate_block(struct dir_context *ctx, | 321 | static int afs_dir_iterate_block(struct dir_context *ctx, |
260 | union afs_dir_block *block, | 322 | union afs_xdr_dir_block *block, |
261 | unsigned blkoff) | 323 | unsigned blkoff) |
262 | { | 324 | { |
263 | union afs_dirent *dire; | 325 | union afs_xdr_dirent *dire; |
264 | unsigned offset, next, curr; | 326 | unsigned offset, next, curr; |
265 | size_t nlen; | 327 | size_t nlen; |
266 | int tmp; | 328 | int tmp; |
267 | 329 | ||
268 | _enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block); | 330 | _enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block); |
269 | 331 | ||
270 | curr = (ctx->pos - blkoff) / sizeof(union afs_dirent); | 332 | curr = (ctx->pos - blkoff) / sizeof(union afs_xdr_dirent); |
271 | 333 | ||
272 | /* walk through the block, an entry at a time */ | 334 | /* walk through the block, an entry at a time */ |
273 | for (offset = AFS_DIRENT_PER_BLOCK - block->pagehdr.nentries; | 335 | for (offset = (blkoff == 0 ? AFS_DIR_RESV_BLOCKS0 : AFS_DIR_RESV_BLOCKS); |
274 | offset < AFS_DIRENT_PER_BLOCK; | 336 | offset < AFS_DIR_SLOTS_PER_BLOCK; |
275 | offset = next | 337 | offset = next |
276 | ) { | 338 | ) { |
277 | next = offset + 1; | 339 | next = offset + 1; |
278 | 340 | ||
279 | /* skip entries marked unused in the bitmap */ | 341 | /* skip entries marked unused in the bitmap */ |
280 | if (!(block->pagehdr.bitmap[offset / 8] & | 342 | if (!(block->hdr.bitmap[offset / 8] & |
281 | (1 << (offset % 8)))) { | 343 | (1 << (offset % 8)))) { |
282 | _debug("ENT[%zu.%u]: unused", | 344 | _debug("ENT[%zu.%u]: unused", |
283 | blkoff / sizeof(union afs_dir_block), offset); | 345 | blkoff / sizeof(union afs_xdr_dir_block), offset); |
284 | if (offset >= curr) | 346 | if (offset >= curr) |
285 | ctx->pos = blkoff + | 347 | ctx->pos = blkoff + |
286 | next * sizeof(union afs_dirent); | 348 | next * sizeof(union afs_xdr_dirent); |
287 | continue; | 349 | continue; |
288 | } | 350 | } |
289 | 351 | ||
@@ -291,34 +353,34 @@ static int afs_dir_iterate_block(struct dir_context *ctx, | |||
291 | dire = &block->dirents[offset]; | 353 | dire = &block->dirents[offset]; |
292 | nlen = strnlen(dire->u.name, | 354 | nlen = strnlen(dire->u.name, |
293 | sizeof(*block) - | 355 | sizeof(*block) - |
294 | offset * sizeof(union afs_dirent)); | 356 | offset * sizeof(union afs_xdr_dirent)); |
295 | 357 | ||
296 | _debug("ENT[%zu.%u]: %s %zu \"%s\"", | 358 | _debug("ENT[%zu.%u]: %s %zu \"%s\"", |
297 | blkoff / sizeof(union afs_dir_block), offset, | 359 | blkoff / sizeof(union afs_xdr_dir_block), offset, |
298 | (offset < curr ? "skip" : "fill"), | 360 | (offset < curr ? "skip" : "fill"), |
299 | nlen, dire->u.name); | 361 | nlen, dire->u.name); |
300 | 362 | ||
301 | /* work out where the next possible entry is */ | 363 | /* work out where the next possible entry is */ |
302 | for (tmp = nlen; tmp > 15; tmp -= sizeof(union afs_dirent)) { | 364 | for (tmp = nlen; tmp > 15; tmp -= sizeof(union afs_xdr_dirent)) { |
303 | if (next >= AFS_DIRENT_PER_BLOCK) { | 365 | if (next >= AFS_DIR_SLOTS_PER_BLOCK) { |
304 | _debug("ENT[%zu.%u]:" | 366 | _debug("ENT[%zu.%u]:" |
305 | " %u travelled beyond end dir block" | 367 | " %u travelled beyond end dir block" |
306 | " (len %u/%zu)", | 368 | " (len %u/%zu)", |
307 | blkoff / sizeof(union afs_dir_block), | 369 | blkoff / sizeof(union afs_xdr_dir_block), |
308 | offset, next, tmp, nlen); | 370 | offset, next, tmp, nlen); |
309 | return -EIO; | 371 | return -EIO; |
310 | } | 372 | } |
311 | if (!(block->pagehdr.bitmap[next / 8] & | 373 | if (!(block->hdr.bitmap[next / 8] & |
312 | (1 << (next % 8)))) { | 374 | (1 << (next % 8)))) { |
313 | _debug("ENT[%zu.%u]:" | 375 | _debug("ENT[%zu.%u]:" |
314 | " %u unmarked extension (len %u/%zu)", | 376 | " %u unmarked extension (len %u/%zu)", |
315 | blkoff / sizeof(union afs_dir_block), | 377 | blkoff / sizeof(union afs_xdr_dir_block), |
316 | offset, next, tmp, nlen); | 378 | offset, next, tmp, nlen); |
317 | return -EIO; | 379 | return -EIO; |
318 | } | 380 | } |
319 | 381 | ||
320 | _debug("ENT[%zu.%u]: ext %u/%zu", | 382 | _debug("ENT[%zu.%u]: ext %u/%zu", |
321 | blkoff / sizeof(union afs_dir_block), | 383 | blkoff / sizeof(union afs_xdr_dir_block), |
322 | next, tmp, nlen); | 384 | next, tmp, nlen); |
323 | next++; | 385 | next++; |
324 | } | 386 | } |
@@ -330,13 +392,14 @@ static int afs_dir_iterate_block(struct dir_context *ctx, | |||
330 | /* found the next entry */ | 392 | /* found the next entry */ |
331 | if (!dir_emit(ctx, dire->u.name, nlen, | 393 | if (!dir_emit(ctx, dire->u.name, nlen, |
332 | ntohl(dire->u.vnode), | 394 | ntohl(dire->u.vnode), |
333 | ctx->actor == afs_lookup_filldir ? | 395 | (ctx->actor == afs_lookup_filldir || |
396 | ctx->actor == afs_lookup_one_filldir)? | ||
334 | ntohl(dire->u.unique) : DT_UNKNOWN)) { | 397 | ntohl(dire->u.unique) : DT_UNKNOWN)) { |
335 | _leave(" = 0 [full]"); | 398 | _leave(" = 0 [full]"); |
336 | return 0; | 399 | return 0; |
337 | } | 400 | } |
338 | 401 | ||
339 | ctx->pos = blkoff + next * sizeof(union afs_dirent); | 402 | ctx->pos = blkoff + next * sizeof(union afs_xdr_dirent); |
340 | } | 403 | } |
341 | 404 | ||
342 | _leave(" = 1 [more]"); | 405 | _leave(" = 1 [more]"); |
@@ -349,8 +412,10 @@ static int afs_dir_iterate_block(struct dir_context *ctx, | |||
349 | static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, | 412 | static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, |
350 | struct key *key) | 413 | struct key *key) |
351 | { | 414 | { |
352 | union afs_dir_block *dblock; | 415 | struct afs_vnode *dvnode = AFS_FS_I(dir); |
353 | struct afs_dir_page *dbuf; | 416 | struct afs_xdr_dir_page *dbuf; |
417 | union afs_xdr_dir_block *dblock; | ||
418 | struct afs_read *req; | ||
354 | struct page *page; | 419 | struct page *page; |
355 | unsigned blkoff, limit; | 420 | unsigned blkoff, limit; |
356 | int ret; | 421 | int ret; |
@@ -362,45 +427,53 @@ static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, | |||
362 | return -ESTALE; | 427 | return -ESTALE; |
363 | } | 428 | } |
364 | 429 | ||
430 | req = afs_read_dir(dvnode, key); | ||
431 | if (IS_ERR(req)) | ||
432 | return PTR_ERR(req); | ||
433 | |||
365 | /* round the file position up to the next entry boundary */ | 434 | /* round the file position up to the next entry boundary */ |
366 | ctx->pos += sizeof(union afs_dirent) - 1; | 435 | ctx->pos += sizeof(union afs_xdr_dirent) - 1; |
367 | ctx->pos &= ~(sizeof(union afs_dirent) - 1); | 436 | ctx->pos &= ~(sizeof(union afs_xdr_dirent) - 1); |
368 | 437 | ||
369 | /* walk through the blocks in sequence */ | 438 | /* walk through the blocks in sequence */ |
370 | ret = 0; | 439 | ret = 0; |
371 | while (ctx->pos < dir->i_size) { | 440 | while (ctx->pos < req->actual_len) { |
372 | blkoff = ctx->pos & ~(sizeof(union afs_dir_block) - 1); | 441 | blkoff = ctx->pos & ~(sizeof(union afs_xdr_dir_block) - 1); |
373 | 442 | ||
374 | /* fetch the appropriate page from the directory */ | 443 | /* Fetch the appropriate page from the directory and re-add it |
375 | page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key); | 444 | * to the LRU. |
376 | if (IS_ERR(page)) { | 445 | */ |
377 | ret = PTR_ERR(page); | 446 | page = req->pages[blkoff / PAGE_SIZE]; |
447 | if (!page) { | ||
448 | ret = -EIO; | ||
378 | break; | 449 | break; |
379 | } | 450 | } |
451 | mark_page_accessed(page); | ||
380 | 452 | ||
381 | limit = blkoff & ~(PAGE_SIZE - 1); | 453 | limit = blkoff & ~(PAGE_SIZE - 1); |
382 | 454 | ||
383 | dbuf = page_address(page); | 455 | dbuf = kmap(page); |
384 | 456 | ||
385 | /* deal with the individual blocks stashed on this page */ | 457 | /* deal with the individual blocks stashed on this page */ |
386 | do { | 458 | do { |
387 | dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) / | 459 | dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) / |
388 | sizeof(union afs_dir_block)]; | 460 | sizeof(union afs_xdr_dir_block)]; |
389 | ret = afs_dir_iterate_block(ctx, dblock, blkoff); | 461 | ret = afs_dir_iterate_block(ctx, dblock, blkoff); |
390 | if (ret != 1) { | 462 | if (ret != 1) { |
391 | afs_dir_put_page(page); | 463 | kunmap(page); |
392 | goto out; | 464 | goto out; |
393 | } | 465 | } |
394 | 466 | ||
395 | blkoff += sizeof(union afs_dir_block); | 467 | blkoff += sizeof(union afs_xdr_dir_block); |
396 | 468 | ||
397 | } while (ctx->pos < dir->i_size && blkoff < limit); | 469 | } while (ctx->pos < dir->i_size && blkoff < limit); |
398 | 470 | ||
399 | afs_dir_put_page(page); | 471 | kunmap(page); |
400 | ret = 0; | 472 | ret = 0; |
401 | } | 473 | } |
402 | 474 | ||
403 | out: | 475 | out: |
476 | afs_put_read(req); | ||
404 | _leave(" = %d", ret); | 477 | _leave(" = %d", ret); |
405 | return ret; | 478 | return ret; |
406 | } | 479 | } |
@@ -414,23 +487,23 @@ static int afs_readdir(struct file *file, struct dir_context *ctx) | |||
414 | } | 487 | } |
415 | 488 | ||
416 | /* | 489 | /* |
417 | * search the directory for a name | 490 | * Search the directory for a single name |
418 | * - if afs_dir_iterate_block() spots this function, it'll pass the FID | 491 | * - if afs_dir_iterate_block() spots this function, it'll pass the FID |
419 | * uniquifier through dtype | 492 | * uniquifier through dtype |
420 | */ | 493 | */ |
421 | static int afs_lookup_filldir(struct dir_context *ctx, const char *name, | 494 | static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, |
422 | int nlen, loff_t fpos, u64 ino, unsigned dtype) | 495 | int nlen, loff_t fpos, u64 ino, unsigned dtype) |
423 | { | 496 | { |
424 | struct afs_lookup_cookie *cookie = | 497 | struct afs_lookup_one_cookie *cookie = |
425 | container_of(ctx, struct afs_lookup_cookie, ctx); | 498 | container_of(ctx, struct afs_lookup_one_cookie, ctx); |
426 | 499 | ||
427 | _enter("{%s,%u},%s,%u,,%llu,%u", | 500 | _enter("{%s,%u},%s,%u,,%llu,%u", |
428 | cookie->name.name, cookie->name.len, name, nlen, | 501 | cookie->name.name, cookie->name.len, name, nlen, |
429 | (unsigned long long) ino, dtype); | 502 | (unsigned long long) ino, dtype); |
430 | 503 | ||
431 | /* insanity checks first */ | 504 | /* insanity checks first */ |
432 | BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048); | 505 | BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); |
433 | BUILD_BUG_ON(sizeof(union afs_dirent) != 32); | 506 | BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); |
434 | 507 | ||
435 | if (cookie->name.len != nlen || | 508 | if (cookie->name.len != nlen || |
436 | memcmp(cookie->name.name, name, nlen) != 0) { | 509 | memcmp(cookie->name.name, name, nlen) != 0) { |
@@ -447,15 +520,15 @@ static int afs_lookup_filldir(struct dir_context *ctx, const char *name, | |||
447 | } | 520 | } |
448 | 521 | ||
449 | /* | 522 | /* |
450 | * do a lookup in a directory | 523 | * Do a lookup of a single name in a directory |
451 | * - just returns the FID the dentry name maps to if found | 524 | * - just returns the FID the dentry name maps to if found |
452 | */ | 525 | */ |
453 | static int afs_do_lookup(struct inode *dir, struct dentry *dentry, | 526 | static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry, |
454 | struct afs_fid *fid, struct key *key) | 527 | struct afs_fid *fid, struct key *key) |
455 | { | 528 | { |
456 | struct afs_super_info *as = dir->i_sb->s_fs_info; | 529 | struct afs_super_info *as = dir->i_sb->s_fs_info; |
457 | struct afs_lookup_cookie cookie = { | 530 | struct afs_lookup_one_cookie cookie = { |
458 | .ctx.actor = afs_lookup_filldir, | 531 | .ctx.actor = afs_lookup_one_filldir, |
459 | .name = dentry->d_name, | 532 | .name = dentry->d_name, |
460 | .fid.vid = as->volume->vid | 533 | .fid.vid = as->volume->vid |
461 | }; | 534 | }; |
@@ -482,70 +555,265 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
482 | } | 555 | } |
483 | 556 | ||
484 | /* | 557 | /* |
485 | * Probe to see if a cell may exist. This prevents positive dentries from | 558 | * search the directory for a name |
486 | * being created unnecessarily. | 559 | * - if afs_dir_iterate_block() spots this function, it'll pass the FID |
560 | * uniquifier through dtype | ||
487 | */ | 561 | */ |
488 | static int afs_probe_cell_name(struct dentry *dentry) | 562 | static int afs_lookup_filldir(struct dir_context *ctx, const char *name, |
563 | int nlen, loff_t fpos, u64 ino, unsigned dtype) | ||
489 | { | 564 | { |
490 | struct afs_cell *cell; | 565 | struct afs_lookup_cookie *cookie = |
491 | const char *name = dentry->d_name.name; | 566 | container_of(ctx, struct afs_lookup_cookie, ctx); |
492 | size_t len = dentry->d_name.len; | ||
493 | int ret; | 567 | int ret; |
494 | 568 | ||
495 | /* Names prefixed with a dot are R/W mounts. */ | 569 | _enter("{%s,%u},%s,%u,,%llu,%u", |
496 | if (name[0] == '.') { | 570 | cookie->name.name, cookie->name.len, name, nlen, |
497 | if (len == 1) | 571 | (unsigned long long) ino, dtype); |
498 | return -EINVAL; | ||
499 | name++; | ||
500 | len--; | ||
501 | } | ||
502 | 572 | ||
503 | cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len); | 573 | /* insanity checks first */ |
504 | if (!IS_ERR(cell)) { | 574 | BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); |
505 | afs_put_cell(afs_d2net(dentry), cell); | 575 | BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32); |
506 | return 0; | 576 | |
577 | if (cookie->found) { | ||
578 | if (cookie->nr_fids < 50) { | ||
579 | cookie->fids[cookie->nr_fids].vnode = ino; | ||
580 | cookie->fids[cookie->nr_fids].unique = dtype; | ||
581 | cookie->nr_fids++; | ||
582 | } | ||
583 | } else if (cookie->name.len == nlen && | ||
584 | memcmp(cookie->name.name, name, nlen) == 0) { | ||
585 | cookie->fids[0].vnode = ino; | ||
586 | cookie->fids[0].unique = dtype; | ||
587 | cookie->found = 1; | ||
588 | if (cookie->one_only) | ||
589 | return -1; | ||
507 | } | 590 | } |
508 | 591 | ||
509 | ret = dns_query("afsdb", name, len, "ipv4", NULL, NULL); | 592 | ret = cookie->nr_fids >= 50 ? -1 : 0; |
510 | if (ret == -ENODATA) | 593 | _leave(" = %d", ret); |
511 | ret = -EDESTADDRREQ; | ||
512 | return ret; | 594 | return ret; |
513 | } | 595 | } |
514 | 596 | ||
515 | /* | 597 | /* |
516 | * Try to auto mount the mountpoint with pseudo directory, if the autocell | 598 | * Do a lookup in a directory. We make use of bulk lookup to query a slew of |
517 | * operation is setted. | 599 | * files in one go and create inodes for them. The inode of the file we were |
600 | * asked for is returned. | ||
518 | */ | 601 | */ |
519 | static struct inode *afs_try_auto_mntpt(struct dentry *dentry, | 602 | static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, |
520 | struct inode *dir, struct afs_fid *fid) | 603 | struct key *key) |
521 | { | 604 | { |
522 | struct afs_vnode *vnode = AFS_FS_I(dir); | 605 | struct afs_lookup_cookie *cookie; |
523 | struct inode *inode; | 606 | struct afs_cb_interest *cbi = NULL; |
524 | int ret = -ENOENT; | 607 | struct afs_super_info *as = dir->i_sb->s_fs_info; |
608 | struct afs_iget_data data; | ||
609 | struct afs_fs_cursor fc; | ||
610 | struct afs_vnode *dvnode = AFS_FS_I(dir); | ||
611 | struct inode *inode = NULL; | ||
612 | int ret, i; | ||
525 | 613 | ||
526 | _enter("%p{%pd}, {%x:%u}", | 614 | _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); |
527 | dentry, dentry, vnode->fid.vid, vnode->fid.vnode); | 615 | |
616 | cookie = kzalloc(sizeof(struct afs_lookup_cookie), GFP_KERNEL); | ||
617 | if (!cookie) | ||
618 | return ERR_PTR(-ENOMEM); | ||
619 | |||
620 | cookie->ctx.actor = afs_lookup_filldir; | ||
621 | cookie->name = dentry->d_name; | ||
622 | cookie->nr_fids = 1; /* slot 0 is saved for the fid we actually want */ | ||
623 | |||
624 | read_seqlock_excl(&dvnode->cb_lock); | ||
625 | if (dvnode->cb_interest && | ||
626 | dvnode->cb_interest->server && | ||
627 | test_bit(AFS_SERVER_FL_NO_IBULK, &dvnode->cb_interest->server->flags)) | ||
628 | cookie->one_only = true; | ||
629 | read_sequnlock_excl(&dvnode->cb_lock); | ||
630 | |||
631 | for (i = 0; i < 50; i++) | ||
632 | cookie->fids[i].vid = as->volume->vid; | ||
633 | |||
634 | /* search the directory */ | ||
635 | ret = afs_dir_iterate(dir, &cookie->ctx, key); | ||
636 | if (ret < 0) { | ||
637 | inode = ERR_PTR(ret); | ||
638 | goto out; | ||
639 | } | ||
528 | 640 | ||
529 | if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags)) | 641 | inode = ERR_PTR(-ENOENT); |
642 | if (!cookie->found) | ||
530 | goto out; | 643 | goto out; |
531 | 644 | ||
532 | ret = afs_probe_cell_name(dentry); | 645 | /* Check to see if we already have an inode for the primary fid. */ |
533 | if (ret < 0) | 646 | data.volume = dvnode->volume; |
647 | data.fid = cookie->fids[0]; | ||
648 | inode = ilookup5(dir->i_sb, cookie->fids[0].vnode, afs_iget5_test, &data); | ||
649 | if (inode) | ||
534 | goto out; | 650 | goto out; |
535 | 651 | ||
536 | inode = afs_iget_pseudo_dir(dir->i_sb, false); | 652 | /* Need space for examining all the selected files */ |
537 | if (IS_ERR(inode)) { | 653 | inode = ERR_PTR(-ENOMEM); |
538 | ret = PTR_ERR(inode); | 654 | cookie->statuses = kcalloc(cookie->nr_fids, sizeof(struct afs_file_status), |
655 | GFP_KERNEL); | ||
656 | if (!cookie->statuses) | ||
539 | goto out; | 657 | goto out; |
658 | |||
659 | cookie->callbacks = kcalloc(cookie->nr_fids, sizeof(struct afs_callback), | ||
660 | GFP_KERNEL); | ||
661 | if (!cookie->callbacks) | ||
662 | goto out_s; | ||
663 | |||
664 | /* Try FS.InlineBulkStatus first. Abort codes for the individual | ||
665 | * lookups contained therein are stored in the reply without aborting | ||
666 | * the whole operation. | ||
667 | */ | ||
668 | if (cookie->one_only) | ||
669 | goto no_inline_bulk_status; | ||
670 | |||
671 | inode = ERR_PTR(-ERESTARTSYS); | ||
672 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | ||
673 | while (afs_select_fileserver(&fc)) { | ||
674 | if (test_bit(AFS_SERVER_FL_NO_IBULK, | ||
675 | &fc.cbi->server->flags)) { | ||
676 | fc.ac.abort_code = RX_INVALID_OPERATION; | ||
677 | fc.ac.error = -ECONNABORTED; | ||
678 | break; | ||
679 | } | ||
680 | afs_fs_inline_bulk_status(&fc, | ||
681 | afs_v2net(dvnode), | ||
682 | cookie->fids, | ||
683 | cookie->statuses, | ||
684 | cookie->callbacks, | ||
685 | cookie->nr_fids, NULL); | ||
686 | } | ||
687 | |||
688 | if (fc.ac.error == 0) | ||
689 | cbi = afs_get_cb_interest(fc.cbi); | ||
690 | if (fc.ac.abort_code == RX_INVALID_OPERATION) | ||
691 | set_bit(AFS_SERVER_FL_NO_IBULK, &fc.cbi->server->flags); | ||
692 | inode = ERR_PTR(afs_end_vnode_operation(&fc)); | ||
540 | } | 693 | } |
541 | 694 | ||
542 | *fid = AFS_FS_I(inode)->fid; | 695 | if (!IS_ERR(inode)) |
543 | _leave("= %p", inode); | 696 | goto success; |
544 | return inode; | 697 | if (fc.ac.abort_code != RX_INVALID_OPERATION) |
698 | goto out_c; | ||
699 | |||
700 | no_inline_bulk_status: | ||
701 | /* We could try FS.BulkStatus next, but this aborts the entire op if | ||
702 | * any of the lookups fails - so, for the moment, revert to | ||
703 | * FS.FetchStatus for just the primary fid. | ||
704 | */ | ||
705 | cookie->nr_fids = 1; | ||
706 | inode = ERR_PTR(-ERESTARTSYS); | ||
707 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | ||
708 | while (afs_select_fileserver(&fc)) { | ||
709 | afs_fs_fetch_status(&fc, | ||
710 | afs_v2net(dvnode), | ||
711 | cookie->fids, | ||
712 | cookie->statuses, | ||
713 | cookie->callbacks, | ||
714 | NULL); | ||
715 | } | ||
716 | |||
717 | if (fc.ac.error == 0) | ||
718 | cbi = afs_get_cb_interest(fc.cbi); | ||
719 | inode = ERR_PTR(afs_end_vnode_operation(&fc)); | ||
720 | } | ||
545 | 721 | ||
722 | if (IS_ERR(inode)) | ||
723 | goto out_c; | ||
724 | |||
725 | for (i = 0; i < cookie->nr_fids; i++) | ||
726 | cookie->statuses[i].abort_code = 0; | ||
727 | |||
728 | success: | ||
729 | /* Turn all the files into inodes and save the first one - which is the | ||
730 | * one we actually want. | ||
731 | */ | ||
732 | if (cookie->statuses[0].abort_code != 0) | ||
733 | inode = ERR_PTR(afs_abort_to_error(cookie->statuses[0].abort_code)); | ||
734 | |||
735 | for (i = 0; i < cookie->nr_fids; i++) { | ||
736 | struct inode *ti; | ||
737 | |||
738 | if (cookie->statuses[i].abort_code != 0) | ||
739 | continue; | ||
740 | |||
741 | ti = afs_iget(dir->i_sb, key, &cookie->fids[i], | ||
742 | &cookie->statuses[i], | ||
743 | &cookie->callbacks[i], | ||
744 | cbi); | ||
745 | if (i == 0) { | ||
746 | inode = ti; | ||
747 | } else { | ||
748 | if (!IS_ERR(ti)) | ||
749 | iput(ti); | ||
750 | } | ||
751 | } | ||
752 | |||
753 | out_c: | ||
754 | afs_put_cb_interest(afs_v2net(dvnode), cbi); | ||
755 | kfree(cookie->callbacks); | ||
756 | out_s: | ||
757 | kfree(cookie->statuses); | ||
546 | out: | 758 | out: |
547 | _leave("= %d", ret); | 759 | kfree(cookie); |
548 | return ERR_PTR(ret); | 760 | return inode; |
761 | } | ||
762 | |||
763 | /* | ||
764 | * Look up an entry in a directory with @sys substitution. | ||
765 | */ | ||
766 | static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry, | ||
767 | struct key *key) | ||
768 | { | ||
769 | struct afs_sysnames *subs; | ||
770 | struct afs_net *net = afs_i2net(dir); | ||
771 | struct dentry *ret; | ||
772 | char *buf, *p, *name; | ||
773 | int len, i; | ||
774 | |||
775 | _enter(""); | ||
776 | |||
777 | ret = ERR_PTR(-ENOMEM); | ||
778 | p = buf = kmalloc(AFSNAMEMAX, GFP_KERNEL); | ||
779 | if (!buf) | ||
780 | goto out_p; | ||
781 | if (dentry->d_name.len > 4) { | ||
782 | memcpy(p, dentry->d_name.name, dentry->d_name.len - 4); | ||
783 | p += dentry->d_name.len - 4; | ||
784 | } | ||
785 | |||
786 | /* There is an ordered list of substitutes that we have to try. */ | ||
787 | read_lock(&net->sysnames_lock); | ||
788 | subs = net->sysnames; | ||
789 | refcount_inc(&subs->usage); | ||
790 | read_unlock(&net->sysnames_lock); | ||
791 | |||
792 | for (i = 0; i < subs->nr; i++) { | ||
793 | name = subs->subs[i]; | ||
794 | len = dentry->d_name.len - 4 + strlen(name); | ||
795 | if (len >= AFSNAMEMAX) { | ||
796 | ret = ERR_PTR(-ENAMETOOLONG); | ||
797 | goto out_s; | ||
798 | } | ||
799 | |||
800 | strcpy(p, name); | ||
801 | ret = lookup_one_len(buf, dentry->d_parent, len); | ||
802 | if (IS_ERR(ret) || d_is_positive(ret)) | ||
803 | goto out_s; | ||
804 | dput(ret); | ||
805 | } | ||
806 | |||
807 | /* We don't want to d_add() the @sys dentry here as we don't want to | ||
808 | * the cached dentry to hide changes to the sysnames list. | ||
809 | */ | ||
810 | ret = NULL; | ||
811 | out_s: | ||
812 | afs_put_sysnames(subs); | ||
813 | kfree(buf); | ||
814 | out_p: | ||
815 | key_put(key); | ||
816 | return ret; | ||
549 | } | 817 | } |
550 | 818 | ||
551 | /* | 819 | /* |
@@ -554,16 +822,13 @@ out: | |||
554 | static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | 822 | static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, |
555 | unsigned int flags) | 823 | unsigned int flags) |
556 | { | 824 | { |
557 | struct afs_vnode *vnode; | 825 | struct afs_vnode *dvnode = AFS_FS_I(dir); |
558 | struct afs_fid fid; | ||
559 | struct inode *inode; | 826 | struct inode *inode; |
560 | struct key *key; | 827 | struct key *key; |
561 | int ret; | 828 | int ret; |
562 | 829 | ||
563 | vnode = AFS_FS_I(dir); | ||
564 | |||
565 | _enter("{%x:%u},%p{%pd},", | 830 | _enter("{%x:%u},%p{%pd},", |
566 | vnode->fid.vid, vnode->fid.vnode, dentry, dentry); | 831 | dvnode->fid.vid, dvnode->fid.vnode, dentry, dentry); |
567 | 832 | ||
568 | ASSERTCMP(d_inode(dentry), ==, NULL); | 833 | ASSERTCMP(d_inode(dentry), ==, NULL); |
569 | 834 | ||
@@ -572,28 +837,37 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
572 | return ERR_PTR(-ENAMETOOLONG); | 837 | return ERR_PTR(-ENAMETOOLONG); |
573 | } | 838 | } |
574 | 839 | ||
575 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { | 840 | if (test_bit(AFS_VNODE_DELETED, &dvnode->flags)) { |
576 | _leave(" = -ESTALE"); | 841 | _leave(" = -ESTALE"); |
577 | return ERR_PTR(-ESTALE); | 842 | return ERR_PTR(-ESTALE); |
578 | } | 843 | } |
579 | 844 | ||
580 | key = afs_request_key(vnode->volume->cell); | 845 | key = afs_request_key(dvnode->volume->cell); |
581 | if (IS_ERR(key)) { | 846 | if (IS_ERR(key)) { |
582 | _leave(" = %ld [key]", PTR_ERR(key)); | 847 | _leave(" = %ld [key]", PTR_ERR(key)); |
583 | return ERR_CAST(key); | 848 | return ERR_CAST(key); |
584 | } | 849 | } |
585 | 850 | ||
586 | ret = afs_validate(vnode, key); | 851 | ret = afs_validate(dvnode, key); |
587 | if (ret < 0) { | 852 | if (ret < 0) { |
588 | key_put(key); | 853 | key_put(key); |
589 | _leave(" = %d [val]", ret); | 854 | _leave(" = %d [val]", ret); |
590 | return ERR_PTR(ret); | 855 | return ERR_PTR(ret); |
591 | } | 856 | } |
592 | 857 | ||
593 | ret = afs_do_lookup(dir, dentry, &fid, key); | 858 | if (dentry->d_name.len >= 4 && |
594 | if (ret < 0) { | 859 | dentry->d_name.name[dentry->d_name.len - 4] == '@' && |
860 | dentry->d_name.name[dentry->d_name.len - 3] == 's' && | ||
861 | dentry->d_name.name[dentry->d_name.len - 2] == 'y' && | ||
862 | dentry->d_name.name[dentry->d_name.len - 1] == 's') | ||
863 | return afs_lookup_atsys(dir, dentry, key); | ||
864 | |||
865 | afs_stat_v(dvnode, n_lookup); | ||
866 | inode = afs_do_lookup(dir, dentry, key); | ||
867 | if (IS_ERR(inode)) { | ||
868 | ret = PTR_ERR(inode); | ||
595 | if (ret == -ENOENT) { | 869 | if (ret == -ENOENT) { |
596 | inode = afs_try_auto_mntpt(dentry, dir, &fid); | 870 | inode = afs_try_auto_mntpt(dentry, dir); |
597 | if (!IS_ERR(inode)) { | 871 | if (!IS_ERR(inode)) { |
598 | key_put(key); | 872 | key_put(key); |
599 | goto success; | 873 | goto success; |
@@ -611,10 +885,9 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
611 | _leave(" = %d [do]", ret); | 885 | _leave(" = %d [do]", ret); |
612 | return ERR_PTR(ret); | 886 | return ERR_PTR(ret); |
613 | } | 887 | } |
614 | dentry->d_fsdata = (void *)(unsigned long) vnode->status.data_version; | 888 | dentry->d_fsdata = (void *)(unsigned long)dvnode->status.data_version; |
615 | 889 | ||
616 | /* instantiate the dentry */ | 890 | /* instantiate the dentry */ |
617 | inode = afs_iget(dir->i_sb, key, &fid, NULL, NULL, NULL); | ||
618 | key_put(key); | 891 | key_put(key); |
619 | if (IS_ERR(inode)) { | 892 | if (IS_ERR(inode)) { |
620 | _leave(" = %ld", PTR_ERR(inode)); | 893 | _leave(" = %ld", PTR_ERR(inode)); |
@@ -623,9 +896,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
623 | 896 | ||
624 | success: | 897 | success: |
625 | d_add(dentry, inode); | 898 | d_add(dentry, inode); |
626 | _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%u }", | 899 | _leave(" = 0 { ino=%lu v=%u }", |
627 | fid.vnode, | ||
628 | fid.unique, | ||
629 | d_inode(dentry)->i_ino, | 900 | d_inode(dentry)->i_ino, |
630 | d_inode(dentry)->i_generation); | 901 | d_inode(dentry)->i_generation); |
631 | 902 | ||
@@ -633,67 +904,23 @@ success: | |||
633 | } | 904 | } |
634 | 905 | ||
635 | /* | 906 | /* |
636 | * Look up an entry in a dynroot directory. | ||
637 | */ | ||
638 | static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry, | ||
639 | unsigned int flags) | ||
640 | { | ||
641 | struct afs_vnode *vnode; | ||
642 | struct afs_fid fid; | ||
643 | struct inode *inode; | ||
644 | int ret; | ||
645 | |||
646 | vnode = AFS_FS_I(dir); | ||
647 | |||
648 | _enter("%pd", dentry); | ||
649 | |||
650 | ASSERTCMP(d_inode(dentry), ==, NULL); | ||
651 | |||
652 | if (dentry->d_name.len >= AFSNAMEMAX) { | ||
653 | _leave(" = -ENAMETOOLONG"); | ||
654 | return ERR_PTR(-ENAMETOOLONG); | ||
655 | } | ||
656 | |||
657 | inode = afs_try_auto_mntpt(dentry, dir, &fid); | ||
658 | if (IS_ERR(inode)) { | ||
659 | ret = PTR_ERR(inode); | ||
660 | if (ret == -ENOENT) { | ||
661 | d_add(dentry, NULL); | ||
662 | _leave(" = NULL [negative]"); | ||
663 | return NULL; | ||
664 | } | ||
665 | _leave(" = %d [do]", ret); | ||
666 | return ERR_PTR(ret); | ||
667 | } | ||
668 | |||
669 | d_add(dentry, inode); | ||
670 | _leave(" = 0 { ino=%lu v=%u }", | ||
671 | d_inode(dentry)->i_ino, d_inode(dentry)->i_generation); | ||
672 | return NULL; | ||
673 | } | ||
674 | |||
675 | /* | ||
676 | * check that a dentry lookup hit has found a valid entry | 907 | * check that a dentry lookup hit has found a valid entry |
677 | * - NOTE! the hit can be a negative hit too, so we can't assume we have an | 908 | * - NOTE! the hit can be a negative hit too, so we can't assume we have an |
678 | * inode | 909 | * inode |
679 | */ | 910 | */ |
680 | static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) | 911 | static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) |
681 | { | 912 | { |
682 | struct afs_super_info *as = dentry->d_sb->s_fs_info; | ||
683 | struct afs_vnode *vnode, *dir; | 913 | struct afs_vnode *vnode, *dir; |
684 | struct afs_fid uninitialized_var(fid); | 914 | struct afs_fid uninitialized_var(fid); |
685 | struct dentry *parent; | 915 | struct dentry *parent; |
686 | struct inode *inode; | 916 | struct inode *inode; |
687 | struct key *key; | 917 | struct key *key; |
688 | void *dir_version; | 918 | long dir_version, de_version; |
689 | int ret; | 919 | int ret; |
690 | 920 | ||
691 | if (flags & LOOKUP_RCU) | 921 | if (flags & LOOKUP_RCU) |
692 | return -ECHILD; | 922 | return -ECHILD; |
693 | 923 | ||
694 | if (as->dyn_root) | ||
695 | return 1; | ||
696 | |||
697 | if (d_really_is_positive(dentry)) { | 924 | if (d_really_is_positive(dentry)) { |
698 | vnode = AFS_FS_I(d_inode(dentry)); | 925 | vnode = AFS_FS_I(d_inode(dentry)); |
699 | _enter("{v={%x:%u} n=%pd fl=%lx},", | 926 | _enter("{v={%x:%u} n=%pd fl=%lx},", |
@@ -729,14 +956,25 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) | |||
729 | goto out_bad_parent; | 956 | goto out_bad_parent; |
730 | } | 957 | } |
731 | 958 | ||
732 | dir_version = (void *) (unsigned long) dir->status.data_version; | 959 | /* We only need to invalidate a dentry if the server's copy changed |
733 | if (dentry->d_fsdata == dir_version) | 960 | * behind our back. If we made the change, it's no problem. Note that |
734 | goto out_valid; /* the dir contents are unchanged */ | 961 | * on a 32-bit system, we only have 32 bits in the dentry to store the |
962 | * version. | ||
963 | */ | ||
964 | dir_version = (long)dir->status.data_version; | ||
965 | de_version = (long)dentry->d_fsdata; | ||
966 | if (de_version == dir_version) | ||
967 | goto out_valid; | ||
968 | |||
969 | dir_version = (long)dir->invalid_before; | ||
970 | if (de_version - dir_version >= 0) | ||
971 | goto out_valid; | ||
735 | 972 | ||
736 | _debug("dir modified"); | 973 | _debug("dir modified"); |
974 | afs_stat_v(dir, n_reval); | ||
737 | 975 | ||
738 | /* search the directory for this vnode */ | 976 | /* search the directory for this vnode */ |
739 | ret = afs_do_lookup(&dir->vfs_inode, dentry, &fid, key); | 977 | ret = afs_do_lookup_one(&dir->vfs_inode, dentry, &fid, key); |
740 | switch (ret) { | 978 | switch (ret) { |
741 | case 0: | 979 | case 0: |
742 | /* the filename maps to something */ | 980 | /* the filename maps to something */ |
@@ -789,7 +1027,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) | |||
789 | } | 1027 | } |
790 | 1028 | ||
791 | out_valid: | 1029 | out_valid: |
792 | dentry->d_fsdata = dir_version; | 1030 | dentry->d_fsdata = (void *)dir_version; |
793 | dput(parent); | 1031 | dput(parent); |
794 | key_put(key); | 1032 | key_put(key); |
795 | _leave(" = 1 [valid]"); | 1033 | _leave(" = 1 [valid]"); |
@@ -840,7 +1078,7 @@ zap: | |||
840 | /* | 1078 | /* |
841 | * handle dentry release | 1079 | * handle dentry release |
842 | */ | 1080 | */ |
843 | static void afs_d_release(struct dentry *dentry) | 1081 | void afs_d_release(struct dentry *dentry) |
844 | { | 1082 | { |
845 | _enter("%pd", dentry); | 1083 | _enter("%pd", dentry); |
846 | } | 1084 | } |
@@ -854,6 +1092,7 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, | |||
854 | struct afs_file_status *newstatus, | 1092 | struct afs_file_status *newstatus, |
855 | struct afs_callback *newcb) | 1093 | struct afs_callback *newcb) |
856 | { | 1094 | { |
1095 | struct afs_vnode *vnode; | ||
857 | struct inode *inode; | 1096 | struct inode *inode; |
858 | 1097 | ||
859 | if (fc->ac.error < 0) | 1098 | if (fc->ac.error < 0) |
@@ -871,6 +1110,8 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, | |||
871 | return; | 1110 | return; |
872 | } | 1111 | } |
873 | 1112 | ||
1113 | vnode = AFS_FS_I(inode); | ||
1114 | set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); | ||
874 | d_add(new_dentry, inode); | 1115 | d_add(new_dentry, inode); |
875 | } | 1116 | } |
876 | 1117 | ||
@@ -885,6 +1126,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
885 | struct afs_vnode *dvnode = AFS_FS_I(dir); | 1126 | struct afs_vnode *dvnode = AFS_FS_I(dir); |
886 | struct afs_fid newfid; | 1127 | struct afs_fid newfid; |
887 | struct key *key; | 1128 | struct key *key; |
1129 | u64 data_version = dvnode->status.data_version; | ||
888 | int ret; | 1130 | int ret; |
889 | 1131 | ||
890 | mode |= S_IFDIR; | 1132 | mode |= S_IFDIR; |
@@ -902,7 +1144,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
902 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1144 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
903 | while (afs_select_fileserver(&fc)) { | 1145 | while (afs_select_fileserver(&fc)) { |
904 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1146 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; |
905 | afs_fs_create(&fc, dentry->d_name.name, mode, | 1147 | afs_fs_create(&fc, dentry->d_name.name, mode, data_version, |
906 | &newfid, &newstatus, &newcb); | 1148 | &newfid, &newstatus, &newcb); |
907 | } | 1149 | } |
908 | 1150 | ||
@@ -916,6 +1158,11 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
916 | goto error_key; | 1158 | goto error_key; |
917 | } | 1159 | } |
918 | 1160 | ||
1161 | if (ret == 0 && | ||
1162 | test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) | ||
1163 | afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, | ||
1164 | afs_edit_dir_for_create); | ||
1165 | |||
919 | key_put(key); | 1166 | key_put(key); |
920 | _leave(" = 0"); | 1167 | _leave(" = 0"); |
921 | return 0; | 1168 | return 0; |
@@ -939,6 +1186,7 @@ static void afs_dir_remove_subdir(struct dentry *dentry) | |||
939 | clear_nlink(&vnode->vfs_inode); | 1186 | clear_nlink(&vnode->vfs_inode); |
940 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | 1187 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
941 | clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); | 1188 | clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); |
1189 | clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); | ||
942 | } | 1190 | } |
943 | } | 1191 | } |
944 | 1192 | ||
@@ -950,6 +1198,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) | |||
950 | struct afs_fs_cursor fc; | 1198 | struct afs_fs_cursor fc; |
951 | struct afs_vnode *dvnode = AFS_FS_I(dir); | 1199 | struct afs_vnode *dvnode = AFS_FS_I(dir); |
952 | struct key *key; | 1200 | struct key *key; |
1201 | u64 data_version = dvnode->status.data_version; | ||
953 | int ret; | 1202 | int ret; |
954 | 1203 | ||
955 | _enter("{%x:%u},{%pd}", | 1204 | _enter("{%x:%u},{%pd}", |
@@ -965,13 +1214,18 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) | |||
965 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1214 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
966 | while (afs_select_fileserver(&fc)) { | 1215 | while (afs_select_fileserver(&fc)) { |
967 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1216 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; |
968 | afs_fs_remove(&fc, dentry->d_name.name, true); | 1217 | afs_fs_remove(&fc, dentry->d_name.name, true, |
1218 | data_version); | ||
969 | } | 1219 | } |
970 | 1220 | ||
971 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break); | 1221 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break); |
972 | ret = afs_end_vnode_operation(&fc); | 1222 | ret = afs_end_vnode_operation(&fc); |
973 | if (ret == 0) | 1223 | if (ret == 0) { |
974 | afs_dir_remove_subdir(dentry); | 1224 | afs_dir_remove_subdir(dentry); |
1225 | if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) | ||
1226 | afs_edit_dir_remove(dvnode, &dentry->d_name, | ||
1227 | afs_edit_dir_for_rmdir); | ||
1228 | } | ||
975 | } | 1229 | } |
976 | 1230 | ||
977 | key_put(key); | 1231 | key_put(key); |
@@ -1036,6 +1290,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) | |||
1036 | struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; | 1290 | struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; |
1037 | struct key *key; | 1291 | struct key *key; |
1038 | unsigned long d_version = (unsigned long)dentry->d_fsdata; | 1292 | unsigned long d_version = (unsigned long)dentry->d_fsdata; |
1293 | u64 data_version = dvnode->status.data_version; | ||
1039 | int ret; | 1294 | int ret; |
1040 | 1295 | ||
1041 | _enter("{%x:%u},{%pd}", | 1296 | _enter("{%x:%u},{%pd}", |
@@ -1062,7 +1317,8 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) | |||
1062 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1317 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
1063 | while (afs_select_fileserver(&fc)) { | 1318 | while (afs_select_fileserver(&fc)) { |
1064 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1319 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; |
1065 | afs_fs_remove(&fc, dentry->d_name.name, false); | 1320 | afs_fs_remove(&fc, dentry->d_name.name, false, |
1321 | data_version); | ||
1066 | } | 1322 | } |
1067 | 1323 | ||
1068 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break); | 1324 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break); |
@@ -1071,6 +1327,10 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) | |||
1071 | ret = afs_dir_remove_link( | 1327 | ret = afs_dir_remove_link( |
1072 | dentry, key, d_version, | 1328 | dentry, key, d_version, |
1073 | (unsigned long)dvnode->status.data_version); | 1329 | (unsigned long)dvnode->status.data_version); |
1330 | if (ret == 0 && | ||
1331 | test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) | ||
1332 | afs_edit_dir_remove(dvnode, &dentry->d_name, | ||
1333 | afs_edit_dir_for_unlink); | ||
1074 | } | 1334 | } |
1075 | 1335 | ||
1076 | error_key: | 1336 | error_key: |
@@ -1092,6 +1352,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
1092 | struct afs_vnode *dvnode = AFS_FS_I(dir); | 1352 | struct afs_vnode *dvnode = AFS_FS_I(dir); |
1093 | struct afs_fid newfid; | 1353 | struct afs_fid newfid; |
1094 | struct key *key; | 1354 | struct key *key; |
1355 | u64 data_version = dvnode->status.data_version; | ||
1095 | int ret; | 1356 | int ret; |
1096 | 1357 | ||
1097 | mode |= S_IFREG; | 1358 | mode |= S_IFREG; |
@@ -1113,7 +1374,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
1113 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1374 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
1114 | while (afs_select_fileserver(&fc)) { | 1375 | while (afs_select_fileserver(&fc)) { |
1115 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1376 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; |
1116 | afs_fs_create(&fc, dentry->d_name.name, mode, | 1377 | afs_fs_create(&fc, dentry->d_name.name, mode, data_version, |
1117 | &newfid, &newstatus, &newcb); | 1378 | &newfid, &newstatus, &newcb); |
1118 | } | 1379 | } |
1119 | 1380 | ||
@@ -1127,6 +1388,10 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
1127 | goto error_key; | 1388 | goto error_key; |
1128 | } | 1389 | } |
1129 | 1390 | ||
1391 | if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) | ||
1392 | afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, | ||
1393 | afs_edit_dir_for_create); | ||
1394 | |||
1130 | key_put(key); | 1395 | key_put(key); |
1131 | _leave(" = 0"); | 1396 | _leave(" = 0"); |
1132 | return 0; | 1397 | return 0; |
@@ -1148,10 +1413,12 @@ static int afs_link(struct dentry *from, struct inode *dir, | |||
1148 | struct afs_fs_cursor fc; | 1413 | struct afs_fs_cursor fc; |
1149 | struct afs_vnode *dvnode, *vnode; | 1414 | struct afs_vnode *dvnode, *vnode; |
1150 | struct key *key; | 1415 | struct key *key; |
1416 | u64 data_version; | ||
1151 | int ret; | 1417 | int ret; |
1152 | 1418 | ||
1153 | vnode = AFS_FS_I(d_inode(from)); | 1419 | vnode = AFS_FS_I(d_inode(from)); |
1154 | dvnode = AFS_FS_I(dir); | 1420 | dvnode = AFS_FS_I(dir); |
1421 | data_version = dvnode->status.data_version; | ||
1155 | 1422 | ||
1156 | _enter("{%x:%u},{%x:%u},{%pd}", | 1423 | _enter("{%x:%u},{%x:%u},{%pd}", |
1157 | vnode->fid.vid, vnode->fid.vnode, | 1424 | vnode->fid.vid, vnode->fid.vnode, |
@@ -1178,7 +1445,7 @@ static int afs_link(struct dentry *from, struct inode *dir, | |||
1178 | while (afs_select_fileserver(&fc)) { | 1445 | while (afs_select_fileserver(&fc)) { |
1179 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1446 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; |
1180 | fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break; | 1447 | fc.cb_break_2 = vnode->cb_break + vnode->cb_s_break; |
1181 | afs_fs_link(&fc, vnode, dentry->d_name.name); | 1448 | afs_fs_link(&fc, vnode, dentry->d_name.name, data_version); |
1182 | } | 1449 | } |
1183 | 1450 | ||
1184 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break); | 1451 | afs_vnode_commit_status(&fc, dvnode, fc.cb_break); |
@@ -1194,6 +1461,10 @@ static int afs_link(struct dentry *from, struct inode *dir, | |||
1194 | goto error_key; | 1461 | goto error_key; |
1195 | } | 1462 | } |
1196 | 1463 | ||
1464 | if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) | ||
1465 | afs_edit_dir_add(dvnode, &dentry->d_name, &vnode->fid, | ||
1466 | afs_edit_dir_for_link); | ||
1467 | |||
1197 | key_put(key); | 1468 | key_put(key); |
1198 | _leave(" = 0"); | 1469 | _leave(" = 0"); |
1199 | return 0; | 1470 | return 0; |
@@ -1217,6 +1488,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, | |||
1217 | struct afs_vnode *dvnode = AFS_FS_I(dir); | 1488 | struct afs_vnode *dvnode = AFS_FS_I(dir); |
1218 | struct afs_fid newfid; | 1489 | struct afs_fid newfid; |
1219 | struct key *key; | 1490 | struct key *key; |
1491 | u64 data_version = dvnode->status.data_version; | ||
1220 | int ret; | 1492 | int ret; |
1221 | 1493 | ||
1222 | _enter("{%x:%u},{%pd},%s", | 1494 | _enter("{%x:%u},{%pd},%s", |
@@ -1241,7 +1513,8 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, | |||
1241 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { | 1513 | if (afs_begin_vnode_operation(&fc, dvnode, key)) { |
1242 | while (afs_select_fileserver(&fc)) { | 1514 | while (afs_select_fileserver(&fc)) { |
1243 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; | 1515 | fc.cb_break = dvnode->cb_break + dvnode->cb_s_break; |
1244 | afs_fs_symlink(&fc, dentry->d_name.name, content, | 1516 | afs_fs_symlink(&fc, dentry->d_name.name, |
1517 | content, data_version, | ||
1245 | &newfid, &newstatus); | 1518 | &newfid, &newstatus); |
1246 | } | 1519 | } |
1247 | 1520 | ||
@@ -1255,6 +1528,10 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, | |||
1255 | goto error_key; | 1528 | goto error_key; |
1256 | } | 1529 | } |
1257 | 1530 | ||
1531 | if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) | ||
1532 | afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, | ||
1533 | afs_edit_dir_for_symlink); | ||
1534 | |||
1258 | key_put(key); | 1535 | key_put(key); |
1259 | _leave(" = 0"); | 1536 | _leave(" = 0"); |
1260 | return 0; | 1537 | return 0; |
@@ -1277,6 +1554,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1277 | struct afs_fs_cursor fc; | 1554 | struct afs_fs_cursor fc; |
1278 | struct afs_vnode *orig_dvnode, *new_dvnode, *vnode; | 1555 | struct afs_vnode *orig_dvnode, *new_dvnode, *vnode; |
1279 | struct key *key; | 1556 | struct key *key; |
1557 | u64 orig_data_version, new_data_version; | ||
1558 | bool new_negative = d_is_negative(new_dentry); | ||
1280 | int ret; | 1559 | int ret; |
1281 | 1560 | ||
1282 | if (flags) | 1561 | if (flags) |
@@ -1285,6 +1564,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1285 | vnode = AFS_FS_I(d_inode(old_dentry)); | 1564 | vnode = AFS_FS_I(d_inode(old_dentry)); |
1286 | orig_dvnode = AFS_FS_I(old_dir); | 1565 | orig_dvnode = AFS_FS_I(old_dir); |
1287 | new_dvnode = AFS_FS_I(new_dir); | 1566 | new_dvnode = AFS_FS_I(new_dir); |
1567 | orig_data_version = orig_dvnode->status.data_version; | ||
1568 | new_data_version = new_dvnode->status.data_version; | ||
1288 | 1569 | ||
1289 | _enter("{%x:%u},{%x:%u},{%x:%u},{%pd}", | 1570 | _enter("{%x:%u},{%x:%u},{%x:%u},{%pd}", |
1290 | orig_dvnode->fid.vid, orig_dvnode->fid.vnode, | 1571 | orig_dvnode->fid.vid, orig_dvnode->fid.vnode, |
@@ -1310,7 +1591,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1310 | fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break; | 1591 | fc.cb_break = orig_dvnode->cb_break + orig_dvnode->cb_s_break; |
1311 | fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break; | 1592 | fc.cb_break_2 = new_dvnode->cb_break + new_dvnode->cb_s_break; |
1312 | afs_fs_rename(&fc, old_dentry->d_name.name, | 1593 | afs_fs_rename(&fc, old_dentry->d_name.name, |
1313 | new_dvnode, new_dentry->d_name.name); | 1594 | new_dvnode, new_dentry->d_name.name, |
1595 | orig_data_version, new_data_version); | ||
1314 | } | 1596 | } |
1315 | 1597 | ||
1316 | afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break); | 1598 | afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break); |
@@ -1322,9 +1604,68 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1322 | goto error_key; | 1604 | goto error_key; |
1323 | } | 1605 | } |
1324 | 1606 | ||
1607 | if (ret == 0) { | ||
1608 | if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags)) | ||
1609 | afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name, | ||
1610 | afs_edit_dir_for_rename); | ||
1611 | |||
1612 | if (!new_negative && | ||
1613 | test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags)) | ||
1614 | afs_edit_dir_remove(new_dvnode, &new_dentry->d_name, | ||
1615 | afs_edit_dir_for_rename); | ||
1616 | |||
1617 | if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags)) | ||
1618 | afs_edit_dir_add(new_dvnode, &new_dentry->d_name, | ||
1619 | &vnode->fid, afs_edit_dir_for_rename); | ||
1620 | } | ||
1621 | |||
1325 | error_key: | 1622 | error_key: |
1326 | key_put(key); | 1623 | key_put(key); |
1327 | error: | 1624 | error: |
1328 | _leave(" = %d", ret); | 1625 | _leave(" = %d", ret); |
1329 | return ret; | 1626 | return ret; |
1330 | } | 1627 | } |
1628 | |||
1629 | /* | ||
1630 | * Release a directory page and clean up its private state if it's not busy | ||
1631 | * - return true if the page can now be released, false if not | ||
1632 | */ | ||
1633 | static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags) | ||
1634 | { | ||
1635 | struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host); | ||
1636 | |||
1637 | _enter("{{%x:%u}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, page->index); | ||
1638 | |||
1639 | set_page_private(page, 0); | ||
1640 | ClearPagePrivate(page); | ||
1641 | |||
1642 | /* The directory will need reloading. */ | ||
1643 | if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) | ||
1644 | afs_stat_v(dvnode, n_relpg); | ||
1645 | return 1; | ||
1646 | } | ||
1647 | |||
1648 | /* | ||
1649 | * invalidate part or all of a page | ||
1650 | * - release a page and clean up its private data if offset is 0 (indicating | ||
1651 | * the entire page) | ||
1652 | */ | ||
1653 | static void afs_dir_invalidatepage(struct page *page, unsigned int offset, | ||
1654 | unsigned int length) | ||
1655 | { | ||
1656 | struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host); | ||
1657 | |||
1658 | _enter("{%lu},%u,%u", page->index, offset, length); | ||
1659 | |||
1660 | BUG_ON(!PageLocked(page)); | ||
1661 | |||
1662 | /* The directory will need reloading. */ | ||
1663 | if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) | ||
1664 | afs_stat_v(dvnode, n_inval); | ||
1665 | |||
1666 | /* we clean up only if the entire page is being invalidated */ | ||
1667 | if (offset == 0 && length == PAGE_SIZE) { | ||
1668 | set_page_private(page, 0); | ||
1669 | ClearPagePrivate(page); | ||
1670 | } | ||
1671 | } | ||
diff --git a/fs/afs/dir_edit.c b/fs/afs/dir_edit.c new file mode 100644 index 000000000000..8b400f5aead5 --- /dev/null +++ b/fs/afs/dir_edit.c | |||
@@ -0,0 +1,505 @@ | |||
1 | /* AFS filesystem directory editing | ||
2 | * | ||
3 | * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/fs.h> | ||
14 | #include <linux/namei.h> | ||
15 | #include <linux/pagemap.h> | ||
16 | #include <linux/iversion.h> | ||
17 | #include "internal.h" | ||
18 | #include "xdr_fs.h" | ||
19 | |||
20 | /* | ||
21 | * Find a number of contiguous clear bits in a directory block bitmask. | ||
22 | * | ||
23 | * There are 64 slots, which means we can load the entire bitmap into a | ||
24 | * variable. The first bit doesn't count as it corresponds to the block header | ||
25 | * slot. nr_slots is between 1 and 9. | ||
26 | */ | ||
27 | static int afs_find_contig_bits(union afs_xdr_dir_block *block, unsigned int nr_slots) | ||
28 | { | ||
29 | u64 bitmap; | ||
30 | u32 mask; | ||
31 | int bit, n; | ||
32 | |||
33 | bitmap = (u64)block->hdr.bitmap[0] << 0 * 8; | ||
34 | bitmap |= (u64)block->hdr.bitmap[1] << 1 * 8; | ||
35 | bitmap |= (u64)block->hdr.bitmap[2] << 2 * 8; | ||
36 | bitmap |= (u64)block->hdr.bitmap[3] << 3 * 8; | ||
37 | bitmap |= (u64)block->hdr.bitmap[4] << 4 * 8; | ||
38 | bitmap |= (u64)block->hdr.bitmap[5] << 5 * 8; | ||
39 | bitmap |= (u64)block->hdr.bitmap[6] << 6 * 8; | ||
40 | bitmap |= (u64)block->hdr.bitmap[7] << 7 * 8; | ||
41 | bitmap >>= 1; /* The first entry is metadata */ | ||
42 | bit = 1; | ||
43 | mask = (1 << nr_slots) - 1; | ||
44 | |||
45 | do { | ||
46 | if (sizeof(unsigned long) == 8) | ||
47 | n = ffz(bitmap); | ||
48 | else | ||
49 | n = ((u32)bitmap) != 0 ? | ||
50 | ffz((u32)bitmap) : | ||
51 | ffz((u32)(bitmap >> 32)) + 32; | ||
52 | bitmap >>= n; | ||
53 | bit += n; | ||
54 | |||
55 | if ((bitmap & mask) == 0) { | ||
56 | if (bit > 64 - nr_slots) | ||
57 | return -1; | ||
58 | return bit; | ||
59 | } | ||
60 | |||
61 | n = __ffs(bitmap); | ||
62 | bitmap >>= n; | ||
63 | bit += n; | ||
64 | } while (bitmap); | ||
65 | |||
66 | return -1; | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Set a number of contiguous bits in the directory block bitmap. | ||
71 | */ | ||
72 | static void afs_set_contig_bits(union afs_xdr_dir_block *block, | ||
73 | int bit, unsigned int nr_slots) | ||
74 | { | ||
75 | u64 mask, before, after; | ||
76 | |||
77 | mask = (1 << nr_slots) - 1; | ||
78 | mask <<= bit; | ||
79 | |||
80 | before = *(u64 *)block->hdr.bitmap; | ||
81 | |||
82 | block->hdr.bitmap[0] |= (u8)(mask >> 0 * 8); | ||
83 | block->hdr.bitmap[1] |= (u8)(mask >> 1 * 8); | ||
84 | block->hdr.bitmap[2] |= (u8)(mask >> 2 * 8); | ||
85 | block->hdr.bitmap[3] |= (u8)(mask >> 3 * 8); | ||
86 | block->hdr.bitmap[4] |= (u8)(mask >> 4 * 8); | ||
87 | block->hdr.bitmap[5] |= (u8)(mask >> 5 * 8); | ||
88 | block->hdr.bitmap[6] |= (u8)(mask >> 6 * 8); | ||
89 | block->hdr.bitmap[7] |= (u8)(mask >> 7 * 8); | ||
90 | |||
91 | after = *(u64 *)block->hdr.bitmap; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Clear a number of contiguous bits in the directory block bitmap. | ||
96 | */ | ||
97 | static void afs_clear_contig_bits(union afs_xdr_dir_block *block, | ||
98 | int bit, unsigned int nr_slots) | ||
99 | { | ||
100 | u64 mask, before, after; | ||
101 | |||
102 | mask = (1 << nr_slots) - 1; | ||
103 | mask <<= bit; | ||
104 | |||
105 | before = *(u64 *)block->hdr.bitmap; | ||
106 | |||
107 | block->hdr.bitmap[0] &= ~(u8)(mask >> 0 * 8); | ||
108 | block->hdr.bitmap[1] &= ~(u8)(mask >> 1 * 8); | ||
109 | block->hdr.bitmap[2] &= ~(u8)(mask >> 2 * 8); | ||
110 | block->hdr.bitmap[3] &= ~(u8)(mask >> 3 * 8); | ||
111 | block->hdr.bitmap[4] &= ~(u8)(mask >> 4 * 8); | ||
112 | block->hdr.bitmap[5] &= ~(u8)(mask >> 5 * 8); | ||
113 | block->hdr.bitmap[6] &= ~(u8)(mask >> 6 * 8); | ||
114 | block->hdr.bitmap[7] &= ~(u8)(mask >> 7 * 8); | ||
115 | |||
116 | after = *(u64 *)block->hdr.bitmap; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Scan a directory block looking for a dirent of the right name. | ||
121 | */ | ||
122 | static int afs_dir_scan_block(union afs_xdr_dir_block *block, struct qstr *name, | ||
123 | unsigned int blocknum) | ||
124 | { | ||
125 | union afs_xdr_dirent *de; | ||
126 | u64 bitmap; | ||
127 | int d, len, n; | ||
128 | |||
129 | _enter(""); | ||
130 | |||
131 | bitmap = (u64)block->hdr.bitmap[0] << 0 * 8; | ||
132 | bitmap |= (u64)block->hdr.bitmap[1] << 1 * 8; | ||
133 | bitmap |= (u64)block->hdr.bitmap[2] << 2 * 8; | ||
134 | bitmap |= (u64)block->hdr.bitmap[3] << 3 * 8; | ||
135 | bitmap |= (u64)block->hdr.bitmap[4] << 4 * 8; | ||
136 | bitmap |= (u64)block->hdr.bitmap[5] << 5 * 8; | ||
137 | bitmap |= (u64)block->hdr.bitmap[6] << 6 * 8; | ||
138 | bitmap |= (u64)block->hdr.bitmap[7] << 7 * 8; | ||
139 | |||
140 | for (d = (blocknum == 0 ? AFS_DIR_RESV_BLOCKS0 : AFS_DIR_RESV_BLOCKS); | ||
141 | d < AFS_DIR_SLOTS_PER_BLOCK; | ||
142 | d++) { | ||
143 | if (!((bitmap >> d) & 1)) | ||
144 | continue; | ||
145 | de = &block->dirents[d]; | ||
146 | if (de->u.valid != 1) | ||
147 | continue; | ||
148 | |||
149 | /* The block was NUL-terminated by afs_dir_check_page(). */ | ||
150 | len = strlen(de->u.name); | ||
151 | if (len == name->len && | ||
152 | memcmp(de->u.name, name->name, name->len) == 0) | ||
153 | return d; | ||
154 | |||
155 | n = round_up(12 + len + 1 + 4, AFS_DIR_DIRENT_SIZE); | ||
156 | n /= AFS_DIR_DIRENT_SIZE; | ||
157 | d += n - 1; | ||
158 | } | ||
159 | |||
160 | return -1; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Initialise a new directory block. Note that block 0 is special and contains | ||
165 | * some extra metadata. | ||
166 | */ | ||
167 | static void afs_edit_init_block(union afs_xdr_dir_block *meta, | ||
168 | union afs_xdr_dir_block *block, int block_num) | ||
169 | { | ||
170 | memset(block, 0, sizeof(*block)); | ||
171 | block->hdr.npages = htons(1); | ||
172 | block->hdr.magic = AFS_DIR_MAGIC; | ||
173 | block->hdr.bitmap[0] = 1; | ||
174 | |||
175 | if (block_num == 0) { | ||
176 | block->hdr.bitmap[0] = 0xff; | ||
177 | block->hdr.bitmap[1] = 0x1f; | ||
178 | memset(block->meta.alloc_ctrs, | ||
179 | AFS_DIR_SLOTS_PER_BLOCK, | ||
180 | sizeof(block->meta.alloc_ctrs)); | ||
181 | meta->meta.alloc_ctrs[0] = | ||
182 | AFS_DIR_SLOTS_PER_BLOCK - AFS_DIR_RESV_BLOCKS0; | ||
183 | } | ||
184 | |||
185 | if (block_num < AFS_DIR_BLOCKS_WITH_CTR) | ||
186 | meta->meta.alloc_ctrs[block_num] = | ||
187 | AFS_DIR_SLOTS_PER_BLOCK - AFS_DIR_RESV_BLOCKS; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Edit a directory's file data to add a new directory entry. Doing this after | ||
192 | * create, mkdir, symlink, link or rename if the data version number is | ||
193 | * incremented by exactly one avoids the need to re-download the entire | ||
194 | * directory contents. | ||
195 | * | ||
196 | * The caller must hold the inode locked. | ||
197 | */ | ||
198 | void afs_edit_dir_add(struct afs_vnode *vnode, | ||
199 | struct qstr *name, struct afs_fid *new_fid, | ||
200 | enum afs_edit_dir_reason why) | ||
201 | { | ||
202 | union afs_xdr_dir_block *meta, *block; | ||
203 | struct afs_xdr_dir_page *meta_page, *dir_page; | ||
204 | union afs_xdr_dirent *de; | ||
205 | struct page *page0, *page; | ||
206 | unsigned int need_slots, nr_blocks, b; | ||
207 | pgoff_t index; | ||
208 | loff_t i_size; | ||
209 | gfp_t gfp; | ||
210 | int slot; | ||
211 | |||
212 | _enter(",,{%d,%s},", name->len, name->name); | ||
213 | |||
214 | i_size = i_size_read(&vnode->vfs_inode); | ||
215 | if (i_size > AFS_DIR_BLOCK_SIZE * AFS_DIR_MAX_BLOCKS || | ||
216 | (i_size & (AFS_DIR_BLOCK_SIZE - 1))) { | ||
217 | clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | gfp = vnode->vfs_inode.i_mapping->gfp_mask; | ||
222 | page0 = find_or_create_page(vnode->vfs_inode.i_mapping, 0, gfp); | ||
223 | if (!page0) { | ||
224 | clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); | ||
225 | _leave(" [fgp]"); | ||
226 | return; | ||
227 | } | ||
228 | |||
229 | /* Work out how many slots we're going to need. */ | ||
230 | need_slots = round_up(12 + name->len + 1 + 4, AFS_DIR_DIRENT_SIZE); | ||
231 | need_slots /= AFS_DIR_DIRENT_SIZE; | ||
232 | |||
233 | meta_page = kmap(page0); | ||
234 | meta = &meta_page->blocks[0]; | ||
235 | if (i_size == 0) | ||
236 | goto new_directory; | ||
237 | nr_blocks = i_size / AFS_DIR_BLOCK_SIZE; | ||
238 | |||
239 | /* Find a block that has sufficient slots available. Each VM page | ||
240 | * contains two or more directory blocks. | ||
241 | */ | ||
242 | for (b = 0; b < nr_blocks + 1; b++) { | ||
243 | /* If the directory extended into a new page, then we need to | ||
244 | * tack a new page on the end. | ||
245 | */ | ||
246 | index = b / AFS_DIR_BLOCKS_PER_PAGE; | ||
247 | if (index == 0) { | ||
248 | page = page0; | ||
249 | dir_page = meta_page; | ||
250 | } else { | ||
251 | if (nr_blocks >= AFS_DIR_MAX_BLOCKS) | ||
252 | goto error; | ||
253 | gfp = vnode->vfs_inode.i_mapping->gfp_mask; | ||
254 | page = find_or_create_page(vnode->vfs_inode.i_mapping, | ||
255 | index, gfp); | ||
256 | if (!page) | ||
257 | goto error; | ||
258 | if (!PagePrivate(page)) { | ||
259 | set_page_private(page, 1); | ||
260 | SetPagePrivate(page); | ||
261 | } | ||
262 | dir_page = kmap(page); | ||
263 | } | ||
264 | |||
265 | /* Abandon the edit if we got a callback break. */ | ||
266 | if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) | ||
267 | goto invalidated; | ||
268 | |||
269 | block = &dir_page->blocks[b % AFS_DIR_BLOCKS_PER_PAGE]; | ||
270 | |||
271 | _debug("block %u: %2u %3u %u", | ||
272 | b, | ||
273 | (b < AFS_DIR_BLOCKS_WITH_CTR) ? meta->meta.alloc_ctrs[b] : 99, | ||
274 | ntohs(block->hdr.npages), | ||
275 | ntohs(block->hdr.magic)); | ||
276 | |||
277 | /* Initialise the block if necessary. */ | ||
278 | if (b == nr_blocks) { | ||
279 | _debug("init %u", b); | ||
280 | afs_edit_init_block(meta, block, b); | ||
281 | i_size_write(&vnode->vfs_inode, (b + 1) * AFS_DIR_BLOCK_SIZE); | ||
282 | } | ||
283 | |||
284 | /* Only lower dir pages have a counter in the header. */ | ||
285 | if (b >= AFS_DIR_BLOCKS_WITH_CTR || | ||
286 | meta->meta.alloc_ctrs[b] >= need_slots) { | ||
287 | /* We need to try and find one or more consecutive | ||
288 | * slots to hold the entry. | ||
289 | */ | ||
290 | slot = afs_find_contig_bits(block, need_slots); | ||
291 | if (slot >= 0) { | ||
292 | _debug("slot %u", slot); | ||
293 | goto found_space; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | if (page != page0) { | ||
298 | unlock_page(page); | ||
299 | kunmap(page); | ||
300 | put_page(page); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | /* There are no spare slots of sufficient size, yet the operation | ||
305 | * succeeded. Download the directory again. | ||
306 | */ | ||
307 | trace_afs_edit_dir(vnode, why, afs_edit_dir_create_nospc, 0, 0, 0, 0, name->name); | ||
308 | clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); | ||
309 | goto out_unmap; | ||
310 | |||
311 | new_directory: | ||
312 | afs_edit_init_block(meta, meta, 0); | ||
313 | i_size = AFS_DIR_BLOCK_SIZE; | ||
314 | i_size_write(&vnode->vfs_inode, i_size); | ||
315 | slot = AFS_DIR_RESV_BLOCKS0; | ||
316 | page = page0; | ||
317 | block = meta; | ||
318 | nr_blocks = 1; | ||
319 | b = 0; | ||
320 | |||
321 | found_space: | ||
322 | /* Set the dirent slot. */ | ||
323 | trace_afs_edit_dir(vnode, why, afs_edit_dir_create, b, slot, | ||
324 | new_fid->vnode, new_fid->unique, name->name); | ||
325 | de = &block->dirents[slot]; | ||
326 | de->u.valid = 1; | ||
327 | de->u.unused[0] = 0; | ||
328 | de->u.hash_next = 0; // TODO: Really need to maintain this | ||
329 | de->u.vnode = htonl(new_fid->vnode); | ||
330 | de->u.unique = htonl(new_fid->unique); | ||
331 | memcpy(de->u.name, name->name, name->len + 1); | ||
332 | de->u.name[name->len] = 0; | ||
333 | |||
334 | /* Adjust the bitmap. */ | ||
335 | afs_set_contig_bits(block, slot, need_slots); | ||
336 | if (page != page0) { | ||
337 | unlock_page(page); | ||
338 | kunmap(page); | ||
339 | put_page(page); | ||
340 | } | ||
341 | |||
342 | /* Adjust the allocation counter. */ | ||
343 | if (b < AFS_DIR_BLOCKS_WITH_CTR) | ||
344 | meta->meta.alloc_ctrs[b] -= need_slots; | ||
345 | |||
346 | inode_inc_iversion_raw(&vnode->vfs_inode); | ||
347 | afs_stat_v(vnode, n_dir_cr); | ||
348 | _debug("Insert %s in %u[%u]", name->name, b, slot); | ||
349 | |||
350 | out_unmap: | ||
351 | unlock_page(page0); | ||
352 | kunmap(page0); | ||
353 | put_page(page0); | ||
354 | _leave(""); | ||
355 | return; | ||
356 | |||
357 | invalidated: | ||
358 | trace_afs_edit_dir(vnode, why, afs_edit_dir_create_inval, 0, 0, 0, 0, name->name); | ||
359 | clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); | ||
360 | if (page != page0) { | ||
361 | kunmap(page); | ||
362 | put_page(page); | ||
363 | } | ||
364 | goto out_unmap; | ||
365 | |||
366 | error: | ||
367 | trace_afs_edit_dir(vnode, why, afs_edit_dir_create_error, 0, 0, 0, 0, name->name); | ||
368 | clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); | ||
369 | goto out_unmap; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * Edit a directory's file data to remove a new directory entry. Doing this | ||
374 | * after unlink, rmdir or rename if the data version number is incremented by | ||
375 | * exactly one avoids the need to re-download the entire directory contents. | ||
376 | * | ||
377 | * The caller must hold the inode locked. | ||
378 | */ | ||
379 | void afs_edit_dir_remove(struct afs_vnode *vnode, | ||
380 | struct qstr *name, enum afs_edit_dir_reason why) | ||
381 | { | ||
382 | struct afs_xdr_dir_page *meta_page, *dir_page; | ||
383 | union afs_xdr_dir_block *meta, *block; | ||
384 | union afs_xdr_dirent *de; | ||
385 | struct page *page0, *page; | ||
386 | unsigned int need_slots, nr_blocks, b; | ||
387 | pgoff_t index; | ||
388 | loff_t i_size; | ||
389 | int slot; | ||
390 | |||
391 | _enter(",,{%d,%s},", name->len, name->name); | ||
392 | |||
393 | i_size = i_size_read(&vnode->vfs_inode); | ||
394 | if (i_size < AFS_DIR_BLOCK_SIZE || | ||
395 | i_size > AFS_DIR_BLOCK_SIZE * AFS_DIR_MAX_BLOCKS || | ||
396 | (i_size & (AFS_DIR_BLOCK_SIZE - 1))) { | ||
397 | clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); | ||
398 | return; | ||
399 | } | ||
400 | nr_blocks = i_size / AFS_DIR_BLOCK_SIZE; | ||
401 | |||
402 | page0 = find_lock_page(vnode->vfs_inode.i_mapping, 0); | ||
403 | if (!page0) { | ||
404 | clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); | ||
405 | _leave(" [fgp]"); | ||
406 | return; | ||
407 | } | ||
408 | |||
409 | /* Work out how many slots we're going to discard. */ | ||
410 | need_slots = round_up(12 + name->len + 1 + 4, AFS_DIR_DIRENT_SIZE); | ||
411 | need_slots /= AFS_DIR_DIRENT_SIZE; | ||
412 | |||
413 | meta_page = kmap(page0); | ||
414 | meta = &meta_page->blocks[0]; | ||
415 | |||
416 | /* Find a page that has sufficient slots available. Each VM page | ||
417 | * contains two or more directory blocks. | ||
418 | */ | ||
419 | for (b = 0; b < nr_blocks; b++) { | ||
420 | index = b / AFS_DIR_BLOCKS_PER_PAGE; | ||
421 | if (index != 0) { | ||
422 | page = find_lock_page(vnode->vfs_inode.i_mapping, index); | ||
423 | if (!page) | ||
424 | goto error; | ||
425 | dir_page = kmap(page); | ||
426 | } else { | ||
427 | page = page0; | ||
428 | dir_page = meta_page; | ||
429 | } | ||
430 | |||
431 | /* Abandon the edit if we got a callback break. */ | ||
432 | if (!test_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) | ||
433 | goto invalidated; | ||
434 | |||
435 | block = &dir_page->blocks[b % AFS_DIR_BLOCKS_PER_PAGE]; | ||
436 | |||
437 | if (b > AFS_DIR_BLOCKS_WITH_CTR || | ||
438 | meta->meta.alloc_ctrs[b] <= AFS_DIR_SLOTS_PER_BLOCK - 1 - need_slots) { | ||
439 | slot = afs_dir_scan_block(block, name, b); | ||
440 | if (slot >= 0) | ||
441 | goto found_dirent; | ||
442 | } | ||
443 | |||
444 | if (page != page0) { | ||
445 | unlock_page(page); | ||
446 | kunmap(page); | ||
447 | put_page(page); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | /* Didn't find the dirent to clobber. Download the directory again. */ | ||
452 | trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_noent, | ||
453 | 0, 0, 0, 0, name->name); | ||
454 | clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); | ||
455 | goto out_unmap; | ||
456 | |||
457 | found_dirent: | ||
458 | de = &block->dirents[slot]; | ||
459 | |||
460 | trace_afs_edit_dir(vnode, why, afs_edit_dir_delete, b, slot, | ||
461 | ntohl(de->u.vnode), ntohl(de->u.unique), | ||
462 | name->name); | ||
463 | |||
464 | memset(de, 0, sizeof(*de) * need_slots); | ||
465 | |||
466 | /* Adjust the bitmap. */ | ||
467 | afs_clear_contig_bits(block, slot, need_slots); | ||
468 | if (page != page0) { | ||
469 | unlock_page(page); | ||
470 | kunmap(page); | ||
471 | put_page(page); | ||
472 | } | ||
473 | |||
474 | /* Adjust the allocation counter. */ | ||
475 | if (b < AFS_DIR_BLOCKS_WITH_CTR) | ||
476 | meta->meta.alloc_ctrs[b] += need_slots; | ||
477 | |||
478 | inode_set_iversion_raw(&vnode->vfs_inode, vnode->status.data_version); | ||
479 | afs_stat_v(vnode, n_dir_rm); | ||
480 | _debug("Remove %s from %u[%u]", name->name, b, slot); | ||
481 | |||
482 | out_unmap: | ||
483 | unlock_page(page0); | ||
484 | kunmap(page0); | ||
485 | put_page(page0); | ||
486 | _leave(""); | ||
487 | return; | ||
488 | |||
489 | invalidated: | ||
490 | trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_inval, | ||
491 | 0, 0, 0, 0, name->name); | ||
492 | clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); | ||
493 | if (page != page0) { | ||
494 | unlock_page(page); | ||
495 | kunmap(page); | ||
496 | put_page(page); | ||
497 | } | ||
498 | goto out_unmap; | ||
499 | |||
500 | error: | ||
501 | trace_afs_edit_dir(vnode, why, afs_edit_dir_delete_error, | ||
502 | 0, 0, 0, 0, name->name); | ||
503 | clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags); | ||
504 | goto out_unmap; | ||
505 | } | ||
diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c new file mode 100644 index 000000000000..983f3946ab57 --- /dev/null +++ b/fs/afs/dynroot.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* dir.c: AFS dynamic root handling | ||
2 | * | ||
3 | * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/fs.h> | ||
13 | #include <linux/namei.h> | ||
14 | #include <linux/dns_resolver.h> | ||
15 | #include "internal.h" | ||
16 | |||
17 | const struct file_operations afs_dynroot_file_operations = { | ||
18 | .open = dcache_dir_open, | ||
19 | .release = dcache_dir_close, | ||
20 | .iterate_shared = dcache_readdir, | ||
21 | .llseek = dcache_dir_lseek, | ||
22 | }; | ||
23 | |||
24 | /* | ||
25 | * Probe to see if a cell may exist. This prevents positive dentries from | ||
26 | * being created unnecessarily. | ||
27 | */ | ||
28 | static int afs_probe_cell_name(struct dentry *dentry) | ||
29 | { | ||
30 | struct afs_cell *cell; | ||
31 | const char *name = dentry->d_name.name; | ||
32 | size_t len = dentry->d_name.len; | ||
33 | int ret; | ||
34 | |||
35 | /* Names prefixed with a dot are R/W mounts. */ | ||
36 | if (name[0] == '.') { | ||
37 | if (len == 1) | ||
38 | return -EINVAL; | ||
39 | name++; | ||
40 | len--; | ||
41 | } | ||
42 | |||
43 | cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len); | ||
44 | if (!IS_ERR(cell)) { | ||
45 | afs_put_cell(afs_d2net(dentry), cell); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | ret = dns_query("afsdb", name, len, "ipv4", NULL, NULL); | ||
50 | if (ret == -ENODATA) | ||
51 | ret = -EDESTADDRREQ; | ||
52 | return ret; | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * Try to auto mount the mountpoint with pseudo directory, if the autocell | ||
57 | * operation is setted. | ||
58 | */ | ||
59 | struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir) | ||
60 | { | ||
61 | struct afs_vnode *vnode = AFS_FS_I(dir); | ||
62 | struct inode *inode; | ||
63 | int ret = -ENOENT; | ||
64 | |||
65 | _enter("%p{%pd}, {%x:%u}", | ||
66 | dentry, dentry, vnode->fid.vid, vnode->fid.vnode); | ||
67 | |||
68 | if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags)) | ||
69 | goto out; | ||
70 | |||
71 | ret = afs_probe_cell_name(dentry); | ||
72 | if (ret < 0) | ||
73 | goto out; | ||
74 | |||
75 | inode = afs_iget_pseudo_dir(dir->i_sb, false); | ||
76 | if (IS_ERR(inode)) { | ||
77 | ret = PTR_ERR(inode); | ||
78 | goto out; | ||
79 | } | ||
80 | |||
81 | _leave("= %p", inode); | ||
82 | return inode; | ||
83 | |||
84 | out: | ||
85 | _leave("= %d", ret); | ||
86 | return ERR_PTR(ret); | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Look up @cell in a dynroot directory. This is a substitution for the | ||
91 | * local cell name for the net namespace. | ||
92 | */ | ||
93 | static struct dentry *afs_lookup_atcell(struct dentry *dentry) | ||
94 | { | ||
95 | struct afs_cell *cell; | ||
96 | struct afs_net *net = afs_d2net(dentry); | ||
97 | struct dentry *ret; | ||
98 | unsigned int seq = 0; | ||
99 | char *name; | ||
100 | int len; | ||
101 | |||
102 | if (!net->ws_cell) | ||
103 | return ERR_PTR(-ENOENT); | ||
104 | |||
105 | ret = ERR_PTR(-ENOMEM); | ||
106 | name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL); | ||
107 | if (!name) | ||
108 | goto out_p; | ||
109 | |||
110 | rcu_read_lock(); | ||
111 | do { | ||
112 | read_seqbegin_or_lock(&net->cells_lock, &seq); | ||
113 | cell = rcu_dereference_raw(net->ws_cell); | ||
114 | if (cell) { | ||
115 | len = cell->name_len; | ||
116 | memcpy(name, cell->name, len + 1); | ||
117 | } | ||
118 | } while (need_seqretry(&net->cells_lock, seq)); | ||
119 | done_seqretry(&net->cells_lock, seq); | ||
120 | rcu_read_unlock(); | ||
121 | |||
122 | ret = ERR_PTR(-ENOENT); | ||
123 | if (!cell) | ||
124 | goto out_n; | ||
125 | |||
126 | ret = lookup_one_len(name, dentry->d_parent, len); | ||
127 | |||
128 | /* We don't want to d_add() the @cell dentry here as we don't want to | ||
129 | * the cached dentry to hide changes to the local cell name. | ||
130 | */ | ||
131 | |||
132 | out_n: | ||
133 | kfree(name); | ||
134 | out_p: | ||
135 | return ret; | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * Look up an entry in a dynroot directory. | ||
140 | */ | ||
141 | static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry, | ||
142 | unsigned int flags) | ||
143 | { | ||
144 | struct afs_vnode *vnode; | ||
145 | struct inode *inode; | ||
146 | int ret; | ||
147 | |||
148 | vnode = AFS_FS_I(dir); | ||
149 | |||
150 | _enter("%pd", dentry); | ||
151 | |||
152 | ASSERTCMP(d_inode(dentry), ==, NULL); | ||
153 | |||
154 | if (dentry->d_name.len >= AFSNAMEMAX) { | ||
155 | _leave(" = -ENAMETOOLONG"); | ||
156 | return ERR_PTR(-ENAMETOOLONG); | ||
157 | } | ||
158 | |||
159 | if (dentry->d_name.len == 5 && | ||
160 | memcmp(dentry->d_name.name, "@cell", 5) == 0) | ||
161 | return afs_lookup_atcell(dentry); | ||
162 | |||
163 | inode = afs_try_auto_mntpt(dentry, dir); | ||
164 | if (IS_ERR(inode)) { | ||
165 | ret = PTR_ERR(inode); | ||
166 | if (ret == -ENOENT) { | ||
167 | d_add(dentry, NULL); | ||
168 | _leave(" = NULL [negative]"); | ||
169 | return NULL; | ||
170 | } | ||
171 | _leave(" = %d [do]", ret); | ||
172 | return ERR_PTR(ret); | ||
173 | } | ||
174 | |||
175 | d_add(dentry, inode); | ||
176 | _leave(" = 0 { ino=%lu v=%u }", | ||
177 | d_inode(dentry)->i_ino, d_inode(dentry)->i_generation); | ||
178 | return NULL; | ||
179 | } | ||
180 | |||
181 | const struct inode_operations afs_dynroot_inode_operations = { | ||
182 | .lookup = afs_dynroot_lookup, | ||
183 | }; | ||
184 | |||
185 | /* | ||
186 | * Dirs in the dynamic root don't need revalidation. | ||
187 | */ | ||
188 | static int afs_dynroot_d_revalidate(struct dentry *dentry, unsigned int flags) | ||
189 | { | ||
190 | return 1; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * Allow the VFS to enquire as to whether a dentry should be unhashed (mustn't | ||
195 | * sleep) | ||
196 | * - called from dput() when d_count is going to 0. | ||
197 | * - return 1 to request dentry be unhashed, 0 otherwise | ||
198 | */ | ||
199 | static int afs_dynroot_d_delete(const struct dentry *dentry) | ||
200 | { | ||
201 | return d_really_is_positive(dentry); | ||
202 | } | ||
203 | |||
204 | const struct dentry_operations afs_dynroot_dentry_operations = { | ||
205 | .d_revalidate = afs_dynroot_d_revalidate, | ||
206 | .d_delete = afs_dynroot_d_delete, | ||
207 | .d_release = afs_d_release, | ||
208 | .d_automount = afs_d_automount, | ||
209 | }; | ||
diff --git a/fs/afs/file.c b/fs/afs/file.c index 79e665a35fea..c24c08016dd9 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
@@ -30,7 +30,6 @@ static int afs_readpages(struct file *filp, struct address_space *mapping, | |||
30 | 30 | ||
31 | const struct file_operations afs_file_operations = { | 31 | const struct file_operations afs_file_operations = { |
32 | .open = afs_open, | 32 | .open = afs_open, |
33 | .flush = afs_flush, | ||
34 | .release = afs_release, | 33 | .release = afs_release, |
35 | .llseek = generic_file_llseek, | 34 | .llseek = generic_file_llseek, |
36 | .read_iter = generic_file_read_iter, | 35 | .read_iter = generic_file_read_iter, |
@@ -146,6 +145,9 @@ int afs_open(struct inode *inode, struct file *file) | |||
146 | if (ret < 0) | 145 | if (ret < 0) |
147 | goto error_af; | 146 | goto error_af; |
148 | } | 147 | } |
148 | |||
149 | if (file->f_flags & O_TRUNC) | ||
150 | set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); | ||
149 | 151 | ||
150 | file->private_data = af; | 152 | file->private_data = af; |
151 | _leave(" = 0"); | 153 | _leave(" = 0"); |
@@ -170,6 +172,9 @@ int afs_release(struct inode *inode, struct file *file) | |||
170 | 172 | ||
171 | _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); | 173 | _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); |
172 | 174 | ||
175 | if ((file->f_mode & FMODE_WRITE)) | ||
176 | return vfs_fsync(file, 0); | ||
177 | |||
173 | file->private_data = NULL; | 178 | file->private_data = NULL; |
174 | if (af->wb) | 179 | if (af->wb) |
175 | afs_put_wb_key(af->wb); | 180 | afs_put_wb_key(af->wb); |
@@ -187,10 +192,12 @@ void afs_put_read(struct afs_read *req) | |||
187 | { | 192 | { |
188 | int i; | 193 | int i; |
189 | 194 | ||
190 | if (atomic_dec_and_test(&req->usage)) { | 195 | if (refcount_dec_and_test(&req->usage)) { |
191 | for (i = 0; i < req->nr_pages; i++) | 196 | for (i = 0; i < req->nr_pages; i++) |
192 | if (req->pages[i]) | 197 | if (req->pages[i]) |
193 | put_page(req->pages[i]); | 198 | put_page(req->pages[i]); |
199 | if (req->pages != req->array) | ||
200 | kfree(req->pages); | ||
194 | kfree(req); | 201 | kfree(req); |
195 | } | 202 | } |
196 | } | 203 | } |
@@ -240,6 +247,12 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de | |||
240 | ret = afs_end_vnode_operation(&fc); | 247 | ret = afs_end_vnode_operation(&fc); |
241 | } | 248 | } |
242 | 249 | ||
250 | if (ret == 0) { | ||
251 | afs_stat_v(vnode, n_fetches); | ||
252 | atomic_long_add(desc->actual_len, | ||
253 | &afs_v2net(vnode)->n_fetch_bytes); | ||
254 | } | ||
255 | |||
243 | _leave(" = %d", ret); | 256 | _leave(" = %d", ret); |
244 | return ret; | 257 | return ret; |
245 | } | 258 | } |
@@ -297,10 +310,11 @@ int afs_page_filler(void *data, struct page *page) | |||
297 | * end of the file, the server will return a short read and the | 310 | * end of the file, the server will return a short read and the |
298 | * unmarshalling code will clear the unfilled space. | 311 | * unmarshalling code will clear the unfilled space. |
299 | */ | 312 | */ |
300 | atomic_set(&req->usage, 1); | 313 | refcount_set(&req->usage, 1); |
301 | req->pos = (loff_t)page->index << PAGE_SHIFT; | 314 | req->pos = (loff_t)page->index << PAGE_SHIFT; |
302 | req->len = PAGE_SIZE; | 315 | req->len = PAGE_SIZE; |
303 | req->nr_pages = 1; | 316 | req->nr_pages = 1; |
317 | req->pages = req->array; | ||
304 | req->pages[0] = page; | 318 | req->pages[0] = page; |
305 | get_page(page); | 319 | get_page(page); |
306 | 320 | ||
@@ -309,10 +323,6 @@ int afs_page_filler(void *data, struct page *page) | |||
309 | ret = afs_fetch_data(vnode, key, req); | 323 | ret = afs_fetch_data(vnode, key, req); |
310 | afs_put_read(req); | 324 | afs_put_read(req); |
311 | 325 | ||
312 | if (ret >= 0 && S_ISDIR(inode->i_mode) && | ||
313 | !afs_dir_check_page(inode, page)) | ||
314 | ret = -EIO; | ||
315 | |||
316 | if (ret < 0) { | 326 | if (ret < 0) { |
317 | if (ret == -ENOENT) { | 327 | if (ret == -ENOENT) { |
318 | _debug("got NOENT from server" | 328 | _debug("got NOENT from server" |
@@ -447,10 +457,11 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, | |||
447 | if (!req) | 457 | if (!req) |
448 | return -ENOMEM; | 458 | return -ENOMEM; |
449 | 459 | ||
450 | atomic_set(&req->usage, 1); | 460 | refcount_set(&req->usage, 1); |
451 | req->page_done = afs_readpages_page_done; | 461 | req->page_done = afs_readpages_page_done; |
452 | req->pos = first->index; | 462 | req->pos = first->index; |
453 | req->pos <<= PAGE_SHIFT; | 463 | req->pos <<= PAGE_SHIFT; |
464 | req->pages = req->array; | ||
454 | 465 | ||
455 | /* Transfer the pages to the request. We add them in until one fails | 466 | /* Transfer the pages to the request. We add them in until one fails |
456 | * to add to the LRU and then we stop (as that'll make a hole in the | 467 | * to add to the LRU and then we stop (as that'll make a hole in the |
diff --git a/fs/afs/flock.c b/fs/afs/flock.c index c40ba2fe3cbe..7a0e017070ec 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c | |||
@@ -613,7 +613,7 @@ static int afs_do_getlk(struct file *file, struct file_lock *fl) | |||
613 | posix_test_lock(file, fl); | 613 | posix_test_lock(file, fl); |
614 | if (fl->fl_type == F_UNLCK) { | 614 | if (fl->fl_type == F_UNLCK) { |
615 | /* no local locks; consult the server */ | 615 | /* no local locks; consult the server */ |
616 | ret = afs_fetch_status(vnode, key); | 616 | ret = afs_fetch_status(vnode, key, false); |
617 | if (ret < 0) | 617 | if (ret < 0) |
618 | goto error; | 618 | goto error; |
619 | 619 | ||
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 88ec38c2d83c..efacdb7c1dee 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/iversion.h> | 16 | #include <linux/iversion.h> |
17 | #include "internal.h" | 17 | #include "internal.h" |
18 | #include "afs_fs.h" | 18 | #include "afs_fs.h" |
19 | #include "xdr_fs.h" | ||
19 | 20 | ||
20 | static const struct afs_fid afs_zero_fid; | 21 | static const struct afs_fid afs_zero_fid; |
21 | 22 | ||
@@ -44,109 +45,194 @@ static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) | |||
44 | } | 45 | } |
45 | 46 | ||
46 | /* | 47 | /* |
47 | * decode an AFSFetchStatus block | 48 | * Dump a bad file status record. |
48 | */ | 49 | */ |
49 | static void xdr_decode_AFSFetchStatus(const __be32 **_bp, | 50 | static void xdr_dump_bad(const __be32 *bp) |
50 | struct afs_file_status *status, | ||
51 | struct afs_vnode *vnode, | ||
52 | afs_dataversion_t *store_version) | ||
53 | { | 51 | { |
54 | afs_dataversion_t expected_version; | 52 | __be32 x[4]; |
55 | const __be32 *bp = *_bp; | 53 | int i; |
54 | |||
55 | pr_notice("AFS XDR: Bad status record\n"); | ||
56 | for (i = 0; i < 5 * 4 * 4; i += 16) { | ||
57 | memcpy(x, bp, 16); | ||
58 | bp += 4; | ||
59 | pr_notice("%03x: %08x %08x %08x %08x\n", | ||
60 | i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3])); | ||
61 | } | ||
62 | |||
63 | memcpy(x, bp, 4); | ||
64 | pr_notice("0x50: %08x\n", ntohl(x[0])); | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * Update the core inode struct from a returned status record. | ||
69 | */ | ||
70 | void afs_update_inode_from_status(struct afs_vnode *vnode, | ||
71 | struct afs_file_status *status, | ||
72 | const afs_dataversion_t *expected_version, | ||
73 | u8 flags) | ||
74 | { | ||
75 | struct timespec t; | ||
56 | umode_t mode; | 76 | umode_t mode; |
77 | |||
78 | t.tv_sec = status->mtime_client; | ||
79 | t.tv_nsec = 0; | ||
80 | vnode->vfs_inode.i_ctime = t; | ||
81 | vnode->vfs_inode.i_mtime = t; | ||
82 | vnode->vfs_inode.i_atime = t; | ||
83 | |||
84 | if (flags & (AFS_VNODE_META_CHANGED | AFS_VNODE_NOT_YET_SET)) { | ||
85 | vnode->vfs_inode.i_uid = make_kuid(&init_user_ns, status->owner); | ||
86 | vnode->vfs_inode.i_gid = make_kgid(&init_user_ns, status->group); | ||
87 | set_nlink(&vnode->vfs_inode, status->nlink); | ||
88 | |||
89 | mode = vnode->vfs_inode.i_mode; | ||
90 | mode &= ~S_IALLUGO; | ||
91 | mode |= status->mode; | ||
92 | barrier(); | ||
93 | vnode->vfs_inode.i_mode = mode; | ||
94 | } | ||
95 | |||
96 | if (!(flags & AFS_VNODE_NOT_YET_SET)) { | ||
97 | if (expected_version && | ||
98 | *expected_version != status->data_version) { | ||
99 | _debug("vnode modified %llx on {%x:%u} [exp %llx]", | ||
100 | (unsigned long long) status->data_version, | ||
101 | vnode->fid.vid, vnode->fid.vnode, | ||
102 | (unsigned long long) *expected_version); | ||
103 | vnode->invalid_before = status->data_version; | ||
104 | if (vnode->status.type == AFS_FTYPE_DIR) { | ||
105 | if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) | ||
106 | afs_stat_v(vnode, n_inval); | ||
107 | } else { | ||
108 | set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); | ||
109 | } | ||
110 | } else if (vnode->status.type == AFS_FTYPE_DIR) { | ||
111 | /* Expected directory change is handled elsewhere so | ||
112 | * that we can locally edit the directory and save on a | ||
113 | * download. | ||
114 | */ | ||
115 | if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) | ||
116 | flags &= ~AFS_VNODE_DATA_CHANGED; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | if (flags & (AFS_VNODE_DATA_CHANGED | AFS_VNODE_NOT_YET_SET)) { | ||
121 | inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); | ||
122 | i_size_write(&vnode->vfs_inode, status->size); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * decode an AFSFetchStatus block | ||
128 | */ | ||
129 | static int xdr_decode_AFSFetchStatus(struct afs_call *call, | ||
130 | const __be32 **_bp, | ||
131 | struct afs_file_status *status, | ||
132 | struct afs_vnode *vnode, | ||
133 | const afs_dataversion_t *expected_version, | ||
134 | struct afs_read *read_req) | ||
135 | { | ||
136 | const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; | ||
57 | u64 data_version, size; | 137 | u64 data_version, size; |
58 | bool changed = false; | 138 | u32 type, abort_code; |
59 | kuid_t owner; | 139 | u8 flags = 0; |
60 | kgid_t group; | 140 | int ret; |
61 | 141 | ||
62 | if (vnode) | 142 | if (vnode) |
63 | write_seqlock(&vnode->cb_lock); | 143 | write_seqlock(&vnode->cb_lock); |
64 | 144 | ||
65 | #define EXTRACT(DST) \ | 145 | if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) { |
66 | do { \ | 146 | pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); |
67 | u32 x = ntohl(*bp++); \ | 147 | goto bad; |
68 | if (DST != x) \ | 148 | } |
69 | changed |= true; \ | ||
70 | DST = x; \ | ||
71 | } while (0) | ||
72 | |||
73 | status->if_version = ntohl(*bp++); | ||
74 | EXTRACT(status->type); | ||
75 | EXTRACT(status->nlink); | ||
76 | size = ntohl(*bp++); | ||
77 | data_version = ntohl(*bp++); | ||
78 | EXTRACT(status->author); | ||
79 | owner = make_kuid(&init_user_ns, ntohl(*bp++)); | ||
80 | changed |= !uid_eq(owner, status->owner); | ||
81 | status->owner = owner; | ||
82 | EXTRACT(status->caller_access); /* call ticket dependent */ | ||
83 | EXTRACT(status->anon_access); | ||
84 | EXTRACT(status->mode); | ||
85 | bp++; /* parent.vnode */ | ||
86 | bp++; /* parent.unique */ | ||
87 | bp++; /* seg size */ | ||
88 | status->mtime_client = ntohl(*bp++); | ||
89 | status->mtime_server = ntohl(*bp++); | ||
90 | group = make_kgid(&init_user_ns, ntohl(*bp++)); | ||
91 | changed |= !gid_eq(group, status->group); | ||
92 | status->group = group; | ||
93 | bp++; /* sync counter */ | ||
94 | data_version |= (u64) ntohl(*bp++) << 32; | ||
95 | EXTRACT(status->lock_count); | ||
96 | size |= (u64) ntohl(*bp++) << 32; | ||
97 | bp++; /* spare 4 */ | ||
98 | *_bp = bp; | ||
99 | 149 | ||
100 | if (size != status->size) { | 150 | type = ntohl(xdr->type); |
101 | status->size = size; | 151 | abort_code = ntohl(xdr->abort_code); |
102 | changed |= true; | 152 | switch (type) { |
153 | case AFS_FTYPE_FILE: | ||
154 | case AFS_FTYPE_DIR: | ||
155 | case AFS_FTYPE_SYMLINK: | ||
156 | if (type != status->type && | ||
157 | vnode && | ||
158 | !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { | ||
159 | pr_warning("Vnode %x:%x:%x changed type %u to %u\n", | ||
160 | vnode->fid.vid, | ||
161 | vnode->fid.vnode, | ||
162 | vnode->fid.unique, | ||
163 | status->type, type); | ||
164 | goto bad; | ||
165 | } | ||
166 | status->type = type; | ||
167 | break; | ||
168 | case AFS_FTYPE_INVALID: | ||
169 | if (abort_code != 0) { | ||
170 | status->abort_code = abort_code; | ||
171 | ret = 0; | ||
172 | goto out; | ||
173 | } | ||
174 | /* Fall through */ | ||
175 | default: | ||
176 | goto bad; | ||
103 | } | 177 | } |
104 | status->mode &= S_IALLUGO; | ||
105 | 178 | ||
106 | _debug("vnode time %lx, %lx", | 179 | #define EXTRACT_M(FIELD) \ |
107 | status->mtime_client, status->mtime_server); | 180 | do { \ |
181 | u32 x = ntohl(xdr->FIELD); \ | ||
182 | if (status->FIELD != x) { \ | ||
183 | flags |= AFS_VNODE_META_CHANGED; \ | ||
184 | status->FIELD = x; \ | ||
185 | } \ | ||
186 | } while (0) | ||
108 | 187 | ||
109 | if (vnode) { | 188 | EXTRACT_M(nlink); |
110 | if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { | 189 | EXTRACT_M(author); |
111 | _debug("vnode changed"); | 190 | EXTRACT_M(owner); |
112 | i_size_write(&vnode->vfs_inode, size); | 191 | EXTRACT_M(caller_access); /* call ticket dependent */ |
113 | vnode->vfs_inode.i_uid = status->owner; | 192 | EXTRACT_M(anon_access); |
114 | vnode->vfs_inode.i_gid = status->group; | 193 | EXTRACT_M(mode); |
115 | vnode->vfs_inode.i_generation = vnode->fid.unique; | 194 | EXTRACT_M(group); |
116 | set_nlink(&vnode->vfs_inode, status->nlink); | 195 | |
117 | 196 | status->mtime_client = ntohl(xdr->mtime_client); | |
118 | mode = vnode->vfs_inode.i_mode; | 197 | status->mtime_server = ntohl(xdr->mtime_server); |
119 | mode &= ~S_IALLUGO; | 198 | status->lock_count = ntohl(xdr->lock_count); |
120 | mode |= status->mode; | 199 | |
121 | barrier(); | 200 | size = (u64)ntohl(xdr->size_lo); |
122 | vnode->vfs_inode.i_mode = mode; | 201 | size |= (u64)ntohl(xdr->size_hi) << 32; |
123 | } | 202 | status->size = size; |
203 | |||
204 | data_version = (u64)ntohl(xdr->data_version_lo); | ||
205 | data_version |= (u64)ntohl(xdr->data_version_hi) << 32; | ||
206 | if (data_version != status->data_version) { | ||
207 | status->data_version = data_version; | ||
208 | flags |= AFS_VNODE_DATA_CHANGED; | ||
209 | } | ||
124 | 210 | ||
125 | vnode->vfs_inode.i_ctime.tv_sec = status->mtime_client; | 211 | if (read_req) { |
126 | vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; | 212 | read_req->data_version = data_version; |
127 | vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; | 213 | read_req->file_size = size; |
128 | inode_set_iversion_raw(&vnode->vfs_inode, data_version); | ||
129 | } | 214 | } |
130 | 215 | ||
131 | expected_version = status->data_version; | 216 | *_bp = (const void *)*_bp + sizeof(*xdr); |
132 | if (store_version) | ||
133 | expected_version = *store_version; | ||
134 | 217 | ||
135 | if (expected_version != data_version) { | 218 | if (vnode) { |
136 | status->data_version = data_version; | 219 | if (test_bit(AFS_VNODE_UNSET, &vnode->flags)) |
137 | if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { | 220 | flags |= AFS_VNODE_NOT_YET_SET; |
138 | _debug("vnode modified %llx on {%x:%u}", | 221 | afs_update_inode_from_status(vnode, status, expected_version, |
139 | (unsigned long long) data_version, | 222 | flags); |
140 | vnode->fid.vid, vnode->fid.vnode); | ||
141 | set_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags); | ||
142 | set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); | ||
143 | } | ||
144 | } else if (store_version) { | ||
145 | status->data_version = data_version; | ||
146 | } | 223 | } |
147 | 224 | ||
225 | ret = 0; | ||
226 | |||
227 | out: | ||
148 | if (vnode) | 228 | if (vnode) |
149 | write_sequnlock(&vnode->cb_lock); | 229 | write_sequnlock(&vnode->cb_lock); |
230 | return ret; | ||
231 | |||
232 | bad: | ||
233 | xdr_dump_bad(*_bp); | ||
234 | ret = afs_protocol_error(call, -EBADMSG); | ||
235 | goto out; | ||
150 | } | 236 | } |
151 | 237 | ||
152 | /* | 238 | /* |
@@ -274,7 +360,7 @@ static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, | |||
274 | /* | 360 | /* |
275 | * deliver reply data to an FS.FetchStatus | 361 | * deliver reply data to an FS.FetchStatus |
276 | */ | 362 | */ |
277 | static int afs_deliver_fs_fetch_status(struct afs_call *call) | 363 | static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call) |
278 | { | 364 | { |
279 | struct afs_vnode *vnode = call->reply[0]; | 365 | struct afs_vnode *vnode = call->reply[0]; |
280 | const __be32 *bp; | 366 | const __be32 *bp; |
@@ -288,7 +374,9 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call) | |||
288 | 374 | ||
289 | /* unmarshall the reply once we've received all of it */ | 375 | /* unmarshall the reply once we've received all of it */ |
290 | bp = call->buffer; | 376 | bp = call->buffer; |
291 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 377 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, |
378 | &call->expected_version, NULL) < 0) | ||
379 | return afs_protocol_error(call, -EBADMSG); | ||
292 | xdr_decode_AFSCallBack(call, vnode, &bp); | 380 | xdr_decode_AFSCallBack(call, vnode, &bp); |
293 | if (call->reply[1]) | 381 | if (call->reply[1]) |
294 | xdr_decode_AFSVolSync(&bp, call->reply[1]); | 382 | xdr_decode_AFSVolSync(&bp, call->reply[1]); |
@@ -300,17 +388,18 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call) | |||
300 | /* | 388 | /* |
301 | * FS.FetchStatus operation type | 389 | * FS.FetchStatus operation type |
302 | */ | 390 | */ |
303 | static const struct afs_call_type afs_RXFSFetchStatus = { | 391 | static const struct afs_call_type afs_RXFSFetchStatus_vnode = { |
304 | .name = "FS.FetchStatus", | 392 | .name = "FS.FetchStatus(vnode)", |
305 | .op = afs_FS_FetchStatus, | 393 | .op = afs_FS_FetchStatus, |
306 | .deliver = afs_deliver_fs_fetch_status, | 394 | .deliver = afs_deliver_fs_fetch_status_vnode, |
307 | .destructor = afs_flat_call_destructor, | 395 | .destructor = afs_flat_call_destructor, |
308 | }; | 396 | }; |
309 | 397 | ||
310 | /* | 398 | /* |
311 | * fetch the status information for a file | 399 | * fetch the status information for a file |
312 | */ | 400 | */ |
313 | int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync) | 401 | int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync, |
402 | bool new_inode) | ||
314 | { | 403 | { |
315 | struct afs_vnode *vnode = fc->vnode; | 404 | struct afs_vnode *vnode = fc->vnode; |
316 | struct afs_call *call; | 405 | struct afs_call *call; |
@@ -320,7 +409,8 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy | |||
320 | _enter(",%x,{%x:%u},,", | 409 | _enter(",%x,{%x:%u},,", |
321 | key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); | 410 | key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); |
322 | 411 | ||
323 | call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); | 412 | call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode, |
413 | 16, (21 + 3 + 6) * 4); | ||
324 | if (!call) { | 414 | if (!call) { |
325 | fc->ac.error = -ENOMEM; | 415 | fc->ac.error = -ENOMEM; |
326 | return -ENOMEM; | 416 | return -ENOMEM; |
@@ -329,6 +419,7 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy | |||
329 | call->key = fc->key; | 419 | call->key = fc->key; |
330 | call->reply[0] = vnode; | 420 | call->reply[0] = vnode; |
331 | call->reply[1] = volsync; | 421 | call->reply[1] = volsync; |
422 | call->expected_version = new_inode ? 1 : vnode->status.data_version; | ||
332 | 423 | ||
333 | /* marshall the parameters */ | 424 | /* marshall the parameters */ |
334 | bp = call->request; | 425 | bp = call->request; |
@@ -464,7 +555,9 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) | |||
464 | return ret; | 555 | return ret; |
465 | 556 | ||
466 | bp = call->buffer; | 557 | bp = call->buffer; |
467 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 558 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, |
559 | &vnode->status.data_version, req) < 0) | ||
560 | return afs_protocol_error(call, -EBADMSG); | ||
468 | xdr_decode_AFSCallBack(call, vnode, &bp); | 561 | xdr_decode_AFSCallBack(call, vnode, &bp); |
469 | if (call->reply[1]) | 562 | if (call->reply[1]) |
470 | xdr_decode_AFSVolSync(&bp, call->reply[1]); | 563 | xdr_decode_AFSVolSync(&bp, call->reply[1]); |
@@ -534,6 +627,7 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) | |||
534 | call->reply[0] = vnode; | 627 | call->reply[0] = vnode; |
535 | call->reply[1] = NULL; /* volsync */ | 628 | call->reply[1] = NULL; /* volsync */ |
536 | call->reply[2] = req; | 629 | call->reply[2] = req; |
630 | call->expected_version = vnode->status.data_version; | ||
537 | 631 | ||
538 | /* marshall the parameters */ | 632 | /* marshall the parameters */ |
539 | bp = call->request; | 633 | bp = call->request; |
@@ -546,7 +640,7 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) | |||
546 | bp[6] = 0; | 640 | bp[6] = 0; |
547 | bp[7] = htonl(lower_32_bits(req->len)); | 641 | bp[7] = htonl(lower_32_bits(req->len)); |
548 | 642 | ||
549 | atomic_inc(&req->usage); | 643 | refcount_inc(&req->usage); |
550 | call->cb_break = fc->cb_break; | 644 | call->cb_break = fc->cb_break; |
551 | afs_use_fs_server(call, fc->cbi); | 645 | afs_use_fs_server(call, fc->cbi); |
552 | trace_afs_make_fs_call(call, &vnode->fid); | 646 | trace_afs_make_fs_call(call, &vnode->fid); |
@@ -578,6 +672,7 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) | |||
578 | call->reply[0] = vnode; | 672 | call->reply[0] = vnode; |
579 | call->reply[1] = NULL; /* volsync */ | 673 | call->reply[1] = NULL; /* volsync */ |
580 | call->reply[2] = req; | 674 | call->reply[2] = req; |
675 | call->expected_version = vnode->status.data_version; | ||
581 | 676 | ||
582 | /* marshall the parameters */ | 677 | /* marshall the parameters */ |
583 | bp = call->request; | 678 | bp = call->request; |
@@ -588,7 +683,7 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) | |||
588 | bp[4] = htonl(lower_32_bits(req->pos)); | 683 | bp[4] = htonl(lower_32_bits(req->pos)); |
589 | bp[5] = htonl(lower_32_bits(req->len)); | 684 | bp[5] = htonl(lower_32_bits(req->len)); |
590 | 685 | ||
591 | atomic_inc(&req->usage); | 686 | refcount_inc(&req->usage); |
592 | call->cb_break = fc->cb_break; | 687 | call->cb_break = fc->cb_break; |
593 | afs_use_fs_server(call, fc->cbi); | 688 | afs_use_fs_server(call, fc->cbi); |
594 | trace_afs_make_fs_call(call, &vnode->fid); | 689 | trace_afs_make_fs_call(call, &vnode->fid); |
@@ -613,8 +708,10 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call) | |||
613 | /* unmarshall the reply once we've received all of it */ | 708 | /* unmarshall the reply once we've received all of it */ |
614 | bp = call->buffer; | 709 | bp = call->buffer; |
615 | xdr_decode_AFSFid(&bp, call->reply[1]); | 710 | xdr_decode_AFSFid(&bp, call->reply[1]); |
616 | xdr_decode_AFSFetchStatus(&bp, call->reply[2], NULL, NULL); | 711 | if (xdr_decode_AFSFetchStatus(call, &bp, call->reply[2], NULL, NULL, NULL) < 0 || |
617 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 712 | xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, |
713 | &call->expected_version, NULL) < 0) | ||
714 | return afs_protocol_error(call, -EBADMSG); | ||
618 | xdr_decode_AFSCallBack_raw(&bp, call->reply[3]); | 715 | xdr_decode_AFSCallBack_raw(&bp, call->reply[3]); |
619 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 716 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
620 | 717 | ||
@@ -645,6 +742,7 @@ static const struct afs_call_type afs_RXFSMakeDir = { | |||
645 | int afs_fs_create(struct afs_fs_cursor *fc, | 742 | int afs_fs_create(struct afs_fs_cursor *fc, |
646 | const char *name, | 743 | const char *name, |
647 | umode_t mode, | 744 | umode_t mode, |
745 | u64 current_data_version, | ||
648 | struct afs_fid *newfid, | 746 | struct afs_fid *newfid, |
649 | struct afs_file_status *newstatus, | 747 | struct afs_file_status *newstatus, |
650 | struct afs_callback *newcb) | 748 | struct afs_callback *newcb) |
@@ -672,6 +770,7 @@ int afs_fs_create(struct afs_fs_cursor *fc, | |||
672 | call->reply[1] = newfid; | 770 | call->reply[1] = newfid; |
673 | call->reply[2] = newstatus; | 771 | call->reply[2] = newstatus; |
674 | call->reply[3] = newcb; | 772 | call->reply[3] = newcb; |
773 | call->expected_version = current_data_version + 1; | ||
675 | 774 | ||
676 | /* marshall the parameters */ | 775 | /* marshall the parameters */ |
677 | bp = call->request; | 776 | bp = call->request; |
@@ -715,7 +814,9 @@ static int afs_deliver_fs_remove(struct afs_call *call) | |||
715 | 814 | ||
716 | /* unmarshall the reply once we've received all of it */ | 815 | /* unmarshall the reply once we've received all of it */ |
717 | bp = call->buffer; | 816 | bp = call->buffer; |
718 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 817 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, |
818 | &call->expected_version, NULL) < 0) | ||
819 | return afs_protocol_error(call, -EBADMSG); | ||
719 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 820 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
720 | 821 | ||
721 | _leave(" = 0 [done]"); | 822 | _leave(" = 0 [done]"); |
@@ -742,7 +843,8 @@ static const struct afs_call_type afs_RXFSRemoveDir = { | |||
742 | /* | 843 | /* |
743 | * remove a file or directory | 844 | * remove a file or directory |
744 | */ | 845 | */ |
745 | int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir) | 846 | int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir, |
847 | u64 current_data_version) | ||
746 | { | 848 | { |
747 | struct afs_vnode *vnode = fc->vnode; | 849 | struct afs_vnode *vnode = fc->vnode; |
748 | struct afs_call *call; | 850 | struct afs_call *call; |
@@ -764,6 +866,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir) | |||
764 | 866 | ||
765 | call->key = fc->key; | 867 | call->key = fc->key; |
766 | call->reply[0] = vnode; | 868 | call->reply[0] = vnode; |
869 | call->expected_version = current_data_version + 1; | ||
767 | 870 | ||
768 | /* marshall the parameters */ | 871 | /* marshall the parameters */ |
769 | bp = call->request; | 872 | bp = call->request; |
@@ -801,8 +904,10 @@ static int afs_deliver_fs_link(struct afs_call *call) | |||
801 | 904 | ||
802 | /* unmarshall the reply once we've received all of it */ | 905 | /* unmarshall the reply once we've received all of it */ |
803 | bp = call->buffer; | 906 | bp = call->buffer; |
804 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 907 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, NULL, NULL) < 0 || |
805 | xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL); | 908 | xdr_decode_AFSFetchStatus(call, &bp, &dvnode->status, dvnode, |
909 | &call->expected_version, NULL) < 0) | ||
910 | return afs_protocol_error(call, -EBADMSG); | ||
806 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 911 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
807 | 912 | ||
808 | _leave(" = 0 [done]"); | 913 | _leave(" = 0 [done]"); |
@@ -823,7 +928,7 @@ static const struct afs_call_type afs_RXFSLink = { | |||
823 | * make a hard link | 928 | * make a hard link |
824 | */ | 929 | */ |
825 | int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, | 930 | int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, |
826 | const char *name) | 931 | const char *name, u64 current_data_version) |
827 | { | 932 | { |
828 | struct afs_vnode *dvnode = fc->vnode; | 933 | struct afs_vnode *dvnode = fc->vnode; |
829 | struct afs_call *call; | 934 | struct afs_call *call; |
@@ -844,6 +949,7 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, | |||
844 | call->key = fc->key; | 949 | call->key = fc->key; |
845 | call->reply[0] = dvnode; | 950 | call->reply[0] = dvnode; |
846 | call->reply[1] = vnode; | 951 | call->reply[1] = vnode; |
952 | call->expected_version = current_data_version + 1; | ||
847 | 953 | ||
848 | /* marshall the parameters */ | 954 | /* marshall the parameters */ |
849 | bp = call->request; | 955 | bp = call->request; |
@@ -885,8 +991,10 @@ static int afs_deliver_fs_symlink(struct afs_call *call) | |||
885 | /* unmarshall the reply once we've received all of it */ | 991 | /* unmarshall the reply once we've received all of it */ |
886 | bp = call->buffer; | 992 | bp = call->buffer; |
887 | xdr_decode_AFSFid(&bp, call->reply[1]); | 993 | xdr_decode_AFSFid(&bp, call->reply[1]); |
888 | xdr_decode_AFSFetchStatus(&bp, call->reply[2], NULL, NULL); | 994 | if (xdr_decode_AFSFetchStatus(call, &bp, call->reply[2], NULL, NULL, NULL) || |
889 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); | 995 | xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, |
996 | &call->expected_version, NULL) < 0) | ||
997 | return afs_protocol_error(call, -EBADMSG); | ||
890 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 998 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
891 | 999 | ||
892 | _leave(" = 0 [done]"); | 1000 | _leave(" = 0 [done]"); |
@@ -909,6 +1017,7 @@ static const struct afs_call_type afs_RXFSSymlink = { | |||
909 | int afs_fs_symlink(struct afs_fs_cursor *fc, | 1017 | int afs_fs_symlink(struct afs_fs_cursor *fc, |
910 | const char *name, | 1018 | const char *name, |
911 | const char *contents, | 1019 | const char *contents, |
1020 | u64 current_data_version, | ||
912 | struct afs_fid *newfid, | 1021 | struct afs_fid *newfid, |
913 | struct afs_file_status *newstatus) | 1022 | struct afs_file_status *newstatus) |
914 | { | 1023 | { |
@@ -937,6 +1046,7 @@ int afs_fs_symlink(struct afs_fs_cursor *fc, | |||
937 | call->reply[0] = vnode; | 1046 | call->reply[0] = vnode; |
938 | call->reply[1] = newfid; | 1047 | call->reply[1] = newfid; |
939 | call->reply[2] = newstatus; | 1048 | call->reply[2] = newstatus; |
1049 | call->expected_version = current_data_version + 1; | ||
940 | 1050 | ||
941 | /* marshall the parameters */ | 1051 | /* marshall the parameters */ |
942 | bp = call->request; | 1052 | bp = call->request; |
@@ -987,10 +1097,13 @@ static int afs_deliver_fs_rename(struct afs_call *call) | |||
987 | 1097 | ||
988 | /* unmarshall the reply once we've received all of it */ | 1098 | /* unmarshall the reply once we've received all of it */ |
989 | bp = call->buffer; | 1099 | bp = call->buffer; |
990 | xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL); | 1100 | if (xdr_decode_AFSFetchStatus(call, &bp, &orig_dvnode->status, orig_dvnode, |
991 | if (new_dvnode != orig_dvnode) | 1101 | &call->expected_version, NULL) < 0) |
992 | xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode, | 1102 | return afs_protocol_error(call, -EBADMSG); |
993 | NULL); | 1103 | if (new_dvnode != orig_dvnode && |
1104 | xdr_decode_AFSFetchStatus(call, &bp, &new_dvnode->status, new_dvnode, | ||
1105 | &call->expected_version_2, NULL) < 0) | ||
1106 | return afs_protocol_error(call, -EBADMSG); | ||
994 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 1107 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
995 | 1108 | ||
996 | _leave(" = 0 [done]"); | 1109 | _leave(" = 0 [done]"); |
@@ -1013,7 +1126,9 @@ static const struct afs_call_type afs_RXFSRename = { | |||
1013 | int afs_fs_rename(struct afs_fs_cursor *fc, | 1126 | int afs_fs_rename(struct afs_fs_cursor *fc, |
1014 | const char *orig_name, | 1127 | const char *orig_name, |
1015 | struct afs_vnode *new_dvnode, | 1128 | struct afs_vnode *new_dvnode, |
1016 | const char *new_name) | 1129 | const char *new_name, |
1130 | u64 current_orig_data_version, | ||
1131 | u64 current_new_data_version) | ||
1017 | { | 1132 | { |
1018 | struct afs_vnode *orig_dvnode = fc->vnode; | 1133 | struct afs_vnode *orig_dvnode = fc->vnode; |
1019 | struct afs_call *call; | 1134 | struct afs_call *call; |
@@ -1041,6 +1156,8 @@ int afs_fs_rename(struct afs_fs_cursor *fc, | |||
1041 | call->key = fc->key; | 1156 | call->key = fc->key; |
1042 | call->reply[0] = orig_dvnode; | 1157 | call->reply[0] = orig_dvnode; |
1043 | call->reply[1] = new_dvnode; | 1158 | call->reply[1] = new_dvnode; |
1159 | call->expected_version = current_orig_data_version + 1; | ||
1160 | call->expected_version_2 = current_new_data_version + 1; | ||
1044 | 1161 | ||
1045 | /* marshall the parameters */ | 1162 | /* marshall the parameters */ |
1046 | bp = call->request; | 1163 | bp = call->request; |
@@ -1089,8 +1206,9 @@ static int afs_deliver_fs_store_data(struct afs_call *call) | |||
1089 | 1206 | ||
1090 | /* unmarshall the reply once we've received all of it */ | 1207 | /* unmarshall the reply once we've received all of it */ |
1091 | bp = call->buffer; | 1208 | bp = call->buffer; |
1092 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, | 1209 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, |
1093 | &call->store_version); | 1210 | &call->expected_version, NULL) < 0) |
1211 | return afs_protocol_error(call, -EBADMSG); | ||
1094 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 1212 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
1095 | 1213 | ||
1096 | afs_pages_written_back(vnode, call); | 1214 | afs_pages_written_back(vnode, call); |
@@ -1147,7 +1265,7 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc, | |||
1147 | call->first_offset = offset; | 1265 | call->first_offset = offset; |
1148 | call->last_to = to; | 1266 | call->last_to = to; |
1149 | call->send_pages = true; | 1267 | call->send_pages = true; |
1150 | call->store_version = vnode->status.data_version + 1; | 1268 | call->expected_version = vnode->status.data_version + 1; |
1151 | 1269 | ||
1152 | /* marshall the parameters */ | 1270 | /* marshall the parameters */ |
1153 | bp = call->request; | 1271 | bp = call->request; |
@@ -1222,7 +1340,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, | |||
1222 | call->first_offset = offset; | 1340 | call->first_offset = offset; |
1223 | call->last_to = to; | 1341 | call->last_to = to; |
1224 | call->send_pages = true; | 1342 | call->send_pages = true; |
1225 | call->store_version = vnode->status.data_version + 1; | 1343 | call->expected_version = vnode->status.data_version + 1; |
1226 | 1344 | ||
1227 | /* marshall the parameters */ | 1345 | /* marshall the parameters */ |
1228 | bp = call->request; | 1346 | bp = call->request; |
@@ -1252,7 +1370,6 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, | |||
1252 | */ | 1370 | */ |
1253 | static int afs_deliver_fs_store_status(struct afs_call *call) | 1371 | static int afs_deliver_fs_store_status(struct afs_call *call) |
1254 | { | 1372 | { |
1255 | afs_dataversion_t *store_version; | ||
1256 | struct afs_vnode *vnode = call->reply[0]; | 1373 | struct afs_vnode *vnode = call->reply[0]; |
1257 | const __be32 *bp; | 1374 | const __be32 *bp; |
1258 | int ret; | 1375 | int ret; |
@@ -1264,12 +1381,10 @@ static int afs_deliver_fs_store_status(struct afs_call *call) | |||
1264 | return ret; | 1381 | return ret; |
1265 | 1382 | ||
1266 | /* unmarshall the reply once we've received all of it */ | 1383 | /* unmarshall the reply once we've received all of it */ |
1267 | store_version = NULL; | ||
1268 | if (call->operation_ID == FSSTOREDATA) | ||
1269 | store_version = &call->store_version; | ||
1270 | |||
1271 | bp = call->buffer; | 1384 | bp = call->buffer; |
1272 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version); | 1385 | if (xdr_decode_AFSFetchStatus(call, &bp, &vnode->status, vnode, |
1386 | &call->expected_version, NULL) < 0) | ||
1387 | return afs_protocol_error(call, -EBADMSG); | ||
1273 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ | 1388 | /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ |
1274 | 1389 | ||
1275 | _leave(" = 0 [done]"); | 1390 | _leave(" = 0 [done]"); |
@@ -1324,7 +1439,7 @@ static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr) | |||
1324 | 1439 | ||
1325 | call->key = fc->key; | 1440 | call->key = fc->key; |
1326 | call->reply[0] = vnode; | 1441 | call->reply[0] = vnode; |
1327 | call->store_version = vnode->status.data_version + 1; | 1442 | call->expected_version = vnode->status.data_version + 1; |
1328 | 1443 | ||
1329 | /* marshall the parameters */ | 1444 | /* marshall the parameters */ |
1330 | bp = call->request; | 1445 | bp = call->request; |
@@ -1373,7 +1488,7 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) | |||
1373 | 1488 | ||
1374 | call->key = fc->key; | 1489 | call->key = fc->key; |
1375 | call->reply[0] = vnode; | 1490 | call->reply[0] = vnode; |
1376 | call->store_version = vnode->status.data_version + 1; | 1491 | call->expected_version = vnode->status.data_version + 1; |
1377 | 1492 | ||
1378 | /* marshall the parameters */ | 1493 | /* marshall the parameters */ |
1379 | bp = call->request; | 1494 | bp = call->request; |
@@ -1418,6 +1533,7 @@ int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) | |||
1418 | 1533 | ||
1419 | call->key = fc->key; | 1534 | call->key = fc->key; |
1420 | call->reply[0] = vnode; | 1535 | call->reply[0] = vnode; |
1536 | call->expected_version = vnode->status.data_version; | ||
1421 | 1537 | ||
1422 | /* marshall the parameters */ | 1538 | /* marshall the parameters */ |
1423 | bp = call->request; | 1539 | bp = call->request; |
@@ -1471,7 +1587,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call) | |||
1471 | call->count = ntohl(call->tmp); | 1587 | call->count = ntohl(call->tmp); |
1472 | _debug("volname length: %u", call->count); | 1588 | _debug("volname length: %u", call->count); |
1473 | if (call->count >= AFSNAMEMAX) | 1589 | if (call->count >= AFSNAMEMAX) |
1474 | return -EBADMSG; | 1590 | return afs_protocol_error(call, -EBADMSG); |
1475 | call->offset = 0; | 1591 | call->offset = 0; |
1476 | call->unmarshall++; | 1592 | call->unmarshall++; |
1477 | 1593 | ||
@@ -1518,7 +1634,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call) | |||
1518 | call->count = ntohl(call->tmp); | 1634 | call->count = ntohl(call->tmp); |
1519 | _debug("offline msg length: %u", call->count); | 1635 | _debug("offline msg length: %u", call->count); |
1520 | if (call->count >= AFSNAMEMAX) | 1636 | if (call->count >= AFSNAMEMAX) |
1521 | return -EBADMSG; | 1637 | return afs_protocol_error(call, -EBADMSG); |
1522 | call->offset = 0; | 1638 | call->offset = 0; |
1523 | call->unmarshall++; | 1639 | call->unmarshall++; |
1524 | 1640 | ||
@@ -1565,7 +1681,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call) | |||
1565 | call->count = ntohl(call->tmp); | 1681 | call->count = ntohl(call->tmp); |
1566 | _debug("motd length: %u", call->count); | 1682 | _debug("motd length: %u", call->count); |
1567 | if (call->count >= AFSNAMEMAX) | 1683 | if (call->count >= AFSNAMEMAX) |
1568 | return -EBADMSG; | 1684 | return afs_protocol_error(call, -EBADMSG); |
1569 | call->offset = 0; | 1685 | call->offset = 0; |
1570 | call->unmarshall++; | 1686 | call->unmarshall++; |
1571 | 1687 | ||
@@ -1947,3 +2063,265 @@ int afs_fs_get_capabilities(struct afs_net *net, | |||
1947 | trace_afs_make_fs_call(call, NULL); | 2063 | trace_afs_make_fs_call(call, NULL); |
1948 | return afs_make_call(ac, call, GFP_NOFS, false); | 2064 | return afs_make_call(ac, call, GFP_NOFS, false); |
1949 | } | 2065 | } |
2066 | |||
2067 | /* | ||
2068 | * Deliver reply data to an FS.FetchStatus with no vnode. | ||
2069 | */ | ||
2070 | static int afs_deliver_fs_fetch_status(struct afs_call *call) | ||
2071 | { | ||
2072 | struct afs_file_status *status = call->reply[1]; | ||
2073 | struct afs_callback *callback = call->reply[2]; | ||
2074 | struct afs_volsync *volsync = call->reply[3]; | ||
2075 | struct afs_vnode *vnode = call->reply[0]; | ||
2076 | const __be32 *bp; | ||
2077 | int ret; | ||
2078 | |||
2079 | ret = afs_transfer_reply(call); | ||
2080 | if (ret < 0) | ||
2081 | return ret; | ||
2082 | |||
2083 | _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); | ||
2084 | |||
2085 | /* unmarshall the reply once we've received all of it */ | ||
2086 | bp = call->buffer; | ||
2087 | xdr_decode_AFSFetchStatus(call, &bp, status, vnode, | ||
2088 | &call->expected_version, NULL); | ||
2089 | callback[call->count].version = ntohl(bp[0]); | ||
2090 | callback[call->count].expiry = ntohl(bp[1]); | ||
2091 | callback[call->count].type = ntohl(bp[2]); | ||
2092 | if (vnode) | ||
2093 | xdr_decode_AFSCallBack(call, vnode, &bp); | ||
2094 | else | ||
2095 | bp += 3; | ||
2096 | if (volsync) | ||
2097 | xdr_decode_AFSVolSync(&bp, volsync); | ||
2098 | |||
2099 | _leave(" = 0 [done]"); | ||
2100 | return 0; | ||
2101 | } | ||
2102 | |||
2103 | /* | ||
2104 | * FS.FetchStatus operation type | ||
2105 | */ | ||
2106 | static const struct afs_call_type afs_RXFSFetchStatus = { | ||
2107 | .name = "FS.FetchStatus", | ||
2108 | .op = afs_FS_FetchStatus, | ||
2109 | .deliver = afs_deliver_fs_fetch_status, | ||
2110 | .destructor = afs_flat_call_destructor, | ||
2111 | }; | ||
2112 | |||
2113 | /* | ||
2114 | * Fetch the status information for a fid without needing a vnode handle. | ||
2115 | */ | ||
2116 | int afs_fs_fetch_status(struct afs_fs_cursor *fc, | ||
2117 | struct afs_net *net, | ||
2118 | struct afs_fid *fid, | ||
2119 | struct afs_file_status *status, | ||
2120 | struct afs_callback *callback, | ||
2121 | struct afs_volsync *volsync) | ||
2122 | { | ||
2123 | struct afs_call *call; | ||
2124 | __be32 *bp; | ||
2125 | |||
2126 | _enter(",%x,{%x:%u},,", | ||
2127 | key_serial(fc->key), fid->vid, fid->vnode); | ||
2128 | |||
2129 | call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); | ||
2130 | if (!call) { | ||
2131 | fc->ac.error = -ENOMEM; | ||
2132 | return -ENOMEM; | ||
2133 | } | ||
2134 | |||
2135 | call->key = fc->key; | ||
2136 | call->reply[0] = NULL; /* vnode for fid[0] */ | ||
2137 | call->reply[1] = status; | ||
2138 | call->reply[2] = callback; | ||
2139 | call->reply[3] = volsync; | ||
2140 | call->expected_version = 1; /* vnode->status.data_version */ | ||
2141 | |||
2142 | /* marshall the parameters */ | ||
2143 | bp = call->request; | ||
2144 | bp[0] = htonl(FSFETCHSTATUS); | ||
2145 | bp[1] = htonl(fid->vid); | ||
2146 | bp[2] = htonl(fid->vnode); | ||
2147 | bp[3] = htonl(fid->unique); | ||
2148 | |||
2149 | call->cb_break = fc->cb_break; | ||
2150 | afs_use_fs_server(call, fc->cbi); | ||
2151 | trace_afs_make_fs_call(call, fid); | ||
2152 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); | ||
2153 | } | ||
2154 | |||
2155 | /* | ||
2156 | * Deliver reply data to an FS.InlineBulkStatus call | ||
2157 | */ | ||
2158 | static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) | ||
2159 | { | ||
2160 | struct afs_file_status *statuses; | ||
2161 | struct afs_callback *callbacks; | ||
2162 | struct afs_vnode *vnode = call->reply[0]; | ||
2163 | const __be32 *bp; | ||
2164 | u32 tmp; | ||
2165 | int ret; | ||
2166 | |||
2167 | _enter("{%u}", call->unmarshall); | ||
2168 | |||
2169 | switch (call->unmarshall) { | ||
2170 | case 0: | ||
2171 | call->offset = 0; | ||
2172 | call->unmarshall++; | ||
2173 | |||
2174 | /* Extract the file status count and array in two steps */ | ||
2175 | case 1: | ||
2176 | _debug("extract status count"); | ||
2177 | ret = afs_extract_data(call, &call->tmp, 4, true); | ||
2178 | if (ret < 0) | ||
2179 | return ret; | ||
2180 | |||
2181 | tmp = ntohl(call->tmp); | ||
2182 | _debug("status count: %u/%u", tmp, call->count2); | ||
2183 | if (tmp != call->count2) | ||
2184 | return afs_protocol_error(call, -EBADMSG); | ||
2185 | |||
2186 | call->count = 0; | ||
2187 | call->unmarshall++; | ||
2188 | more_counts: | ||
2189 | call->offset = 0; | ||
2190 | |||
2191 | case 2: | ||
2192 | _debug("extract status array %u", call->count); | ||
2193 | ret = afs_extract_data(call, call->buffer, 21 * 4, true); | ||
2194 | if (ret < 0) | ||
2195 | return ret; | ||
2196 | |||
2197 | bp = call->buffer; | ||
2198 | statuses = call->reply[1]; | ||
2199 | if (xdr_decode_AFSFetchStatus(call, &bp, &statuses[call->count], | ||
2200 | call->count == 0 ? vnode : NULL, | ||
2201 | NULL, NULL) < 0) | ||
2202 | return afs_protocol_error(call, -EBADMSG); | ||
2203 | |||
2204 | call->count++; | ||
2205 | if (call->count < call->count2) | ||
2206 | goto more_counts; | ||
2207 | |||
2208 | call->count = 0; | ||
2209 | call->unmarshall++; | ||
2210 | call->offset = 0; | ||
2211 | |||
2212 | /* Extract the callback count and array in two steps */ | ||
2213 | case 3: | ||
2214 | _debug("extract CB count"); | ||
2215 | ret = afs_extract_data(call, &call->tmp, 4, true); | ||
2216 | if (ret < 0) | ||
2217 | return ret; | ||
2218 | |||
2219 | tmp = ntohl(call->tmp); | ||
2220 | _debug("CB count: %u", tmp); | ||
2221 | if (tmp != call->count2) | ||
2222 | return afs_protocol_error(call, -EBADMSG); | ||
2223 | call->count = 0; | ||
2224 | call->unmarshall++; | ||
2225 | more_cbs: | ||
2226 | call->offset = 0; | ||
2227 | |||
2228 | case 4: | ||
2229 | _debug("extract CB array"); | ||
2230 | ret = afs_extract_data(call, call->buffer, 3 * 4, true); | ||
2231 | if (ret < 0) | ||
2232 | return ret; | ||
2233 | |||
2234 | _debug("unmarshall CB array"); | ||
2235 | bp = call->buffer; | ||
2236 | callbacks = call->reply[2]; | ||
2237 | callbacks[call->count].version = ntohl(bp[0]); | ||
2238 | callbacks[call->count].expiry = ntohl(bp[1]); | ||
2239 | callbacks[call->count].type = ntohl(bp[2]); | ||
2240 | statuses = call->reply[1]; | ||
2241 | if (call->count == 0 && vnode && statuses[0].abort_code == 0) | ||
2242 | xdr_decode_AFSCallBack(call, vnode, &bp); | ||
2243 | call->count++; | ||
2244 | if (call->count < call->count2) | ||
2245 | goto more_cbs; | ||
2246 | |||
2247 | call->offset = 0; | ||
2248 | call->unmarshall++; | ||
2249 | |||
2250 | case 5: | ||
2251 | ret = afs_extract_data(call, call->buffer, 6 * 4, false); | ||
2252 | if (ret < 0) | ||
2253 | return ret; | ||
2254 | |||
2255 | bp = call->buffer; | ||
2256 | if (call->reply[3]) | ||
2257 | xdr_decode_AFSVolSync(&bp, call->reply[3]); | ||
2258 | |||
2259 | call->offset = 0; | ||
2260 | call->unmarshall++; | ||
2261 | |||
2262 | case 6: | ||
2263 | break; | ||
2264 | } | ||
2265 | |||
2266 | _leave(" = 0 [done]"); | ||
2267 | return 0; | ||
2268 | } | ||
2269 | |||
2270 | /* | ||
2271 | * FS.InlineBulkStatus operation type | ||
2272 | */ | ||
2273 | static const struct afs_call_type afs_RXFSInlineBulkStatus = { | ||
2274 | .name = "FS.InlineBulkStatus", | ||
2275 | .op = afs_FS_InlineBulkStatus, | ||
2276 | .deliver = afs_deliver_fs_inline_bulk_status, | ||
2277 | .destructor = afs_flat_call_destructor, | ||
2278 | }; | ||
2279 | |||
2280 | /* | ||
2281 | * Fetch the status information for up to 50 files | ||
2282 | */ | ||
2283 | int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, | ||
2284 | struct afs_net *net, | ||
2285 | struct afs_fid *fids, | ||
2286 | struct afs_file_status *statuses, | ||
2287 | struct afs_callback *callbacks, | ||
2288 | unsigned int nr_fids, | ||
2289 | struct afs_volsync *volsync) | ||
2290 | { | ||
2291 | struct afs_call *call; | ||
2292 | __be32 *bp; | ||
2293 | int i; | ||
2294 | |||
2295 | _enter(",%x,{%x:%u},%u", | ||
2296 | key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids); | ||
2297 | |||
2298 | call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus, | ||
2299 | (2 + nr_fids * 3) * 4, | ||
2300 | 21 * 4); | ||
2301 | if (!call) { | ||
2302 | fc->ac.error = -ENOMEM; | ||
2303 | return -ENOMEM; | ||
2304 | } | ||
2305 | |||
2306 | call->key = fc->key; | ||
2307 | call->reply[0] = NULL; /* vnode for fid[0] */ | ||
2308 | call->reply[1] = statuses; | ||
2309 | call->reply[2] = callbacks; | ||
2310 | call->reply[3] = volsync; | ||
2311 | call->count2 = nr_fids; | ||
2312 | |||
2313 | /* marshall the parameters */ | ||
2314 | bp = call->request; | ||
2315 | *bp++ = htonl(FSINLINEBULKSTATUS); | ||
2316 | *bp++ = htonl(nr_fids); | ||
2317 | for (i = 0; i < nr_fids; i++) { | ||
2318 | *bp++ = htonl(fids[i].vid); | ||
2319 | *bp++ = htonl(fids[i].vnode); | ||
2320 | *bp++ = htonl(fids[i].unique); | ||
2321 | } | ||
2322 | |||
2323 | call->cb_break = fc->cb_break; | ||
2324 | afs_use_fs_server(call, fc->cbi); | ||
2325 | trace_afs_make_fs_call(call, &fids[0]); | ||
2326 | return afs_make_call(&fc->ac, call, GFP_NOFS, false); | ||
2327 | } | ||
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 65c5b1edd338..06194cfe9724 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
@@ -30,12 +30,11 @@ static const struct inode_operations afs_symlink_inode_operations = { | |||
30 | }; | 30 | }; |
31 | 31 | ||
32 | /* | 32 | /* |
33 | * map the AFS file status to the inode member variables | 33 | * Initialise an inode from the vnode status. |
34 | */ | 34 | */ |
35 | static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) | 35 | static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key) |
36 | { | 36 | { |
37 | struct inode *inode = AFS_VNODE_TO_I(vnode); | 37 | struct inode *inode = AFS_VNODE_TO_I(vnode); |
38 | bool changed; | ||
39 | 38 | ||
40 | _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu", | 39 | _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu", |
41 | vnode->status.type, | 40 | vnode->status.type, |
@@ -46,16 +45,21 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) | |||
46 | 45 | ||
47 | read_seqlock_excl(&vnode->cb_lock); | 46 | read_seqlock_excl(&vnode->cb_lock); |
48 | 47 | ||
48 | afs_update_inode_from_status(vnode, &vnode->status, NULL, | ||
49 | AFS_VNODE_NOT_YET_SET); | ||
50 | |||
49 | switch (vnode->status.type) { | 51 | switch (vnode->status.type) { |
50 | case AFS_FTYPE_FILE: | 52 | case AFS_FTYPE_FILE: |
51 | inode->i_mode = S_IFREG | vnode->status.mode; | 53 | inode->i_mode = S_IFREG | vnode->status.mode; |
52 | inode->i_op = &afs_file_inode_operations; | 54 | inode->i_op = &afs_file_inode_operations; |
53 | inode->i_fop = &afs_file_operations; | 55 | inode->i_fop = &afs_file_operations; |
56 | inode->i_mapping->a_ops = &afs_fs_aops; | ||
54 | break; | 57 | break; |
55 | case AFS_FTYPE_DIR: | 58 | case AFS_FTYPE_DIR: |
56 | inode->i_mode = S_IFDIR | vnode->status.mode; | 59 | inode->i_mode = S_IFDIR | vnode->status.mode; |
57 | inode->i_op = &afs_dir_inode_operations; | 60 | inode->i_op = &afs_dir_inode_operations; |
58 | inode->i_fop = &afs_dir_file_operations; | 61 | inode->i_fop = &afs_dir_file_operations; |
62 | inode->i_mapping->a_ops = &afs_dir_aops; | ||
59 | break; | 63 | break; |
60 | case AFS_FTYPE_SYMLINK: | 64 | case AFS_FTYPE_SYMLINK: |
61 | /* Symlinks with a mode of 0644 are actually mountpoints. */ | 65 | /* Symlinks with a mode of 0644 are actually mountpoints. */ |
@@ -67,45 +71,31 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) | |||
67 | inode->i_mode = S_IFDIR | 0555; | 71 | inode->i_mode = S_IFDIR | 0555; |
68 | inode->i_op = &afs_mntpt_inode_operations; | 72 | inode->i_op = &afs_mntpt_inode_operations; |
69 | inode->i_fop = &afs_mntpt_file_operations; | 73 | inode->i_fop = &afs_mntpt_file_operations; |
74 | inode->i_mapping->a_ops = &afs_fs_aops; | ||
70 | } else { | 75 | } else { |
71 | inode->i_mode = S_IFLNK | vnode->status.mode; | 76 | inode->i_mode = S_IFLNK | vnode->status.mode; |
72 | inode->i_op = &afs_symlink_inode_operations; | 77 | inode->i_op = &afs_symlink_inode_operations; |
78 | inode->i_mapping->a_ops = &afs_fs_aops; | ||
73 | } | 79 | } |
74 | inode_nohighmem(inode); | 80 | inode_nohighmem(inode); |
75 | break; | 81 | break; |
76 | default: | 82 | default: |
77 | printk("kAFS: AFS vnode with undefined type\n"); | 83 | printk("kAFS: AFS vnode with undefined type\n"); |
78 | read_sequnlock_excl(&vnode->cb_lock); | 84 | read_sequnlock_excl(&vnode->cb_lock); |
79 | return -EBADMSG; | 85 | return afs_protocol_error(NULL, -EBADMSG); |
80 | } | 86 | } |
81 | 87 | ||
82 | changed = (vnode->status.size != inode->i_size); | ||
83 | |||
84 | set_nlink(inode, vnode->status.nlink); | ||
85 | inode->i_uid = vnode->status.owner; | ||
86 | inode->i_gid = vnode->status.group; | ||
87 | inode->i_size = vnode->status.size; | ||
88 | inode->i_ctime.tv_sec = vnode->status.mtime_client; | ||
89 | inode->i_ctime.tv_nsec = 0; | ||
90 | inode->i_atime = inode->i_mtime = inode->i_ctime; | ||
91 | inode->i_blocks = 0; | 88 | inode->i_blocks = 0; |
92 | inode->i_generation = vnode->fid.unique; | 89 | vnode->invalid_before = vnode->status.data_version; |
93 | inode_set_iversion_raw(inode, vnode->status.data_version); | ||
94 | inode->i_mapping->a_ops = &afs_fs_aops; | ||
95 | 90 | ||
96 | read_sequnlock_excl(&vnode->cb_lock); | 91 | read_sequnlock_excl(&vnode->cb_lock); |
97 | |||
98 | #ifdef CONFIG_AFS_FSCACHE | ||
99 | if (changed) | ||
100 | fscache_attr_changed(vnode->cache); | ||
101 | #endif | ||
102 | return 0; | 92 | return 0; |
103 | } | 93 | } |
104 | 94 | ||
105 | /* | 95 | /* |
106 | * Fetch file status from the volume. | 96 | * Fetch file status from the volume. |
107 | */ | 97 | */ |
108 | int afs_fetch_status(struct afs_vnode *vnode, struct key *key) | 98 | int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode) |
109 | { | 99 | { |
110 | struct afs_fs_cursor fc; | 100 | struct afs_fs_cursor fc; |
111 | int ret; | 101 | int ret; |
@@ -119,7 +109,7 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key) | |||
119 | if (afs_begin_vnode_operation(&fc, vnode, key)) { | 109 | if (afs_begin_vnode_operation(&fc, vnode, key)) { |
120 | while (afs_select_fileserver(&fc)) { | 110 | while (afs_select_fileserver(&fc)) { |
121 | fc.cb_break = vnode->cb_break + vnode->cb_s_break; | 111 | fc.cb_break = vnode->cb_break + vnode->cb_s_break; |
122 | afs_fs_fetch_file_status(&fc, NULL); | 112 | afs_fs_fetch_file_status(&fc, NULL, new_inode); |
123 | } | 113 | } |
124 | 114 | ||
125 | afs_check_for_remote_deletion(&fc, fc.vnode); | 115 | afs_check_for_remote_deletion(&fc, fc.vnode); |
@@ -255,6 +245,11 @@ static void afs_get_inode_cache(struct afs_vnode *vnode) | |||
255 | } __packed key; | 245 | } __packed key; |
256 | struct afs_vnode_cache_aux aux; | 246 | struct afs_vnode_cache_aux aux; |
257 | 247 | ||
248 | if (vnode->status.type == AFS_FTYPE_DIR) { | ||
249 | vnode->cache = NULL; | ||
250 | return; | ||
251 | } | ||
252 | |||
258 | key.vnode_id = vnode->fid.vnode; | 253 | key.vnode_id = vnode->fid.vnode; |
259 | key.unique = vnode->fid.unique; | 254 | key.unique = vnode->fid.unique; |
260 | key.vnode_id_ext[0] = 0; | 255 | key.vnode_id_ext[0] = 0; |
@@ -307,7 +302,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key, | |||
307 | 302 | ||
308 | if (!status) { | 303 | if (!status) { |
309 | /* it's a remotely extant inode */ | 304 | /* it's a remotely extant inode */ |
310 | ret = afs_fetch_status(vnode, key); | 305 | ret = afs_fetch_status(vnode, key, true); |
311 | if (ret < 0) | 306 | if (ret < 0) |
312 | goto bad_inode; | 307 | goto bad_inode; |
313 | } else { | 308 | } else { |
@@ -331,15 +326,12 @@ struct inode *afs_iget(struct super_block *sb, struct key *key, | |||
331 | vnode->cb_expires_at += ktime_get_real_seconds(); | 326 | vnode->cb_expires_at += ktime_get_real_seconds(); |
332 | } | 327 | } |
333 | 328 | ||
334 | /* set up caching before mapping the status, as map-status reads the | 329 | ret = afs_inode_init_from_status(vnode, key); |
335 | * first page of symlinks to see if they're really mountpoints */ | ||
336 | inode->i_size = vnode->status.size; | ||
337 | afs_get_inode_cache(vnode); | ||
338 | |||
339 | ret = afs_inode_map_status(vnode, key); | ||
340 | if (ret < 0) | 330 | if (ret < 0) |
341 | goto bad_inode; | 331 | goto bad_inode; |
342 | 332 | ||
333 | afs_get_inode_cache(vnode); | ||
334 | |||
343 | /* success */ | 335 | /* success */ |
344 | clear_bit(AFS_VNODE_UNSET, &vnode->flags); | 336 | clear_bit(AFS_VNODE_UNSET, &vnode->flags); |
345 | inode->i_flags |= S_NOATIME; | 337 | inode->i_flags |= S_NOATIME; |
@@ -349,10 +341,6 @@ struct inode *afs_iget(struct super_block *sb, struct key *key, | |||
349 | 341 | ||
350 | /* failure */ | 342 | /* failure */ |
351 | bad_inode: | 343 | bad_inode: |
352 | #ifdef CONFIG_AFS_FSCACHE | ||
353 | fscache_relinquish_cookie(vnode->cache, NULL, ret == -ENOENT); | ||
354 | vnode->cache = NULL; | ||
355 | #endif | ||
356 | iget_failed(inode); | 344 | iget_failed(inode); |
357 | _leave(" = %d [bad]", ret); | 345 | _leave(" = %d [bad]", ret); |
358 | return ERR_PTR(ret); | 346 | return ERR_PTR(ret); |
@@ -407,8 +395,11 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) | |||
407 | if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { | 395 | if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { |
408 | if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) { | 396 | if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break) { |
409 | vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; | 397 | vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; |
410 | } else if (!test_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags) && | 398 | } else if (vnode->status.type == AFS_FTYPE_DIR && |
411 | !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) && | 399 | test_bit(AFS_VNODE_DIR_VALID, &vnode->flags) && |
400 | vnode->cb_expires_at - 10 > now) { | ||
401 | valid = true; | ||
402 | } else if (!test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags) && | ||
412 | vnode->cb_expires_at - 10 > now) { | 403 | vnode->cb_expires_at - 10 > now) { |
413 | valid = true; | 404 | valid = true; |
414 | } | 405 | } |
@@ -432,7 +423,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) | |||
432 | * access */ | 423 | * access */ |
433 | if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { | 424 | if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { |
434 | _debug("not promised"); | 425 | _debug("not promised"); |
435 | ret = afs_fetch_status(vnode, key); | 426 | ret = afs_fetch_status(vnode, key, false); |
436 | if (ret < 0) { | 427 | if (ret < 0) { |
437 | if (ret == -ENOENT) { | 428 | if (ret == -ENOENT) { |
438 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | 429 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
@@ -453,8 +444,6 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) | |||
453 | * different */ | 444 | * different */ |
454 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) | 445 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) |
455 | afs_zap_data(vnode); | 446 | afs_zap_data(vnode); |
456 | |||
457 | clear_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags); | ||
458 | mutex_unlock(&vnode->validate_lock); | 447 | mutex_unlock(&vnode->validate_lock); |
459 | valid: | 448 | valid: |
460 | _leave(" = 0"); | 449 | _leave(" = 0"); |
@@ -544,7 +533,7 @@ void afs_evict_inode(struct inode *inode) | |||
544 | } | 533 | } |
545 | #endif | 534 | #endif |
546 | 535 | ||
547 | afs_put_permits(vnode->permit_cache); | 536 | afs_put_permits(rcu_access_pointer(vnode->permit_cache)); |
548 | _leave(""); | 537 | _leave(""); |
549 | } | 538 | } |
550 | 539 | ||
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index a6a1d75eee41..f8086ec95e24 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -122,7 +122,8 @@ struct afs_call { | |||
122 | u32 operation_ID; /* operation ID for an incoming call */ | 122 | u32 operation_ID; /* operation ID for an incoming call */ |
123 | u32 count; /* count for use in unmarshalling */ | 123 | u32 count; /* count for use in unmarshalling */ |
124 | __be32 tmp; /* place to extract temporary data */ | 124 | __be32 tmp; /* place to extract temporary data */ |
125 | afs_dataversion_t store_version; /* updated version expected from store */ | 125 | afs_dataversion_t expected_version; /* Updated version expected from store */ |
126 | afs_dataversion_t expected_version_2; /* 2nd updated version expected from store */ | ||
126 | }; | 127 | }; |
127 | 128 | ||
128 | struct afs_call_type { | 129 | struct afs_call_type { |
@@ -173,11 +174,14 @@ struct afs_read { | |||
173 | loff_t len; /* How much we're asking for */ | 174 | loff_t len; /* How much we're asking for */ |
174 | loff_t actual_len; /* How much we're actually getting */ | 175 | loff_t actual_len; /* How much we're actually getting */ |
175 | loff_t remain; /* Amount remaining */ | 176 | loff_t remain; /* Amount remaining */ |
176 | atomic_t usage; | 177 | loff_t file_size; /* File size returned by server */ |
178 | afs_dataversion_t data_version; /* Version number returned by server */ | ||
179 | refcount_t usage; | ||
177 | unsigned int index; /* Which page we're reading into */ | 180 | unsigned int index; /* Which page we're reading into */ |
178 | unsigned int nr_pages; | 181 | unsigned int nr_pages; |
179 | void (*page_done)(struct afs_call *, struct afs_read *); | 182 | void (*page_done)(struct afs_call *, struct afs_read *); |
180 | struct page *pages[]; | 183 | struct page **pages; |
184 | struct page *array[]; | ||
181 | }; | 185 | }; |
182 | 186 | ||
183 | /* | 187 | /* |
@@ -199,6 +203,18 @@ static inline struct afs_super_info *AFS_FS_S(struct super_block *sb) | |||
199 | extern struct file_system_type afs_fs_type; | 203 | extern struct file_system_type afs_fs_type; |
200 | 204 | ||
201 | /* | 205 | /* |
206 | * Set of substitutes for @sys. | ||
207 | */ | ||
208 | struct afs_sysnames { | ||
209 | #define AFS_NR_SYSNAME 16 | ||
210 | char *subs[AFS_NR_SYSNAME]; | ||
211 | refcount_t usage; | ||
212 | unsigned short nr; | ||
213 | short error; | ||
214 | char blank[1]; | ||
215 | }; | ||
216 | |||
217 | /* | ||
202 | * AFS network namespace record. | 218 | * AFS network namespace record. |
203 | */ | 219 | */ |
204 | struct afs_net { | 220 | struct afs_net { |
@@ -245,9 +261,25 @@ struct afs_net { | |||
245 | struct mutex lock_manager_mutex; | 261 | struct mutex lock_manager_mutex; |
246 | 262 | ||
247 | /* Misc */ | 263 | /* Misc */ |
248 | struct proc_dir_entry *proc_afs; /* /proc/net/afs directory */ | 264 | struct proc_dir_entry *proc_afs; /* /proc/net/afs directory */ |
265 | struct afs_sysnames *sysnames; | ||
266 | rwlock_t sysnames_lock; | ||
267 | |||
268 | /* Statistics counters */ | ||
269 | atomic_t n_lookup; /* Number of lookups done */ | ||
270 | atomic_t n_reval; /* Number of dentries needing revalidation */ | ||
271 | atomic_t n_inval; /* Number of invalidations by the server */ | ||
272 | atomic_t n_relpg; /* Number of invalidations by releasepage */ | ||
273 | atomic_t n_read_dir; /* Number of directory pages read */ | ||
274 | atomic_t n_dir_cr; /* Number of directory entry creation edits */ | ||
275 | atomic_t n_dir_rm; /* Number of directory entry removal edits */ | ||
276 | atomic_t n_stores; /* Number of store ops */ | ||
277 | atomic_long_t n_store_bytes; /* Number of bytes stored */ | ||
278 | atomic_long_t n_fetch_bytes; /* Number of bytes fetched */ | ||
279 | atomic_t n_fetches; /* Number of data fetch ops */ | ||
249 | }; | 280 | }; |
250 | 281 | ||
282 | extern const char afs_init_sysname[]; | ||
251 | extern struct afs_net __afs_net;// Dummy AFS network namespace; TODO: replace with real netns | 283 | extern struct afs_net __afs_net;// Dummy AFS network namespace; TODO: replace with real netns |
252 | 284 | ||
253 | enum afs_cell_state { | 285 | enum afs_cell_state { |
@@ -363,6 +395,7 @@ struct afs_server { | |||
363 | #define AFS_SERVER_FL_UPDATING 4 | 395 | #define AFS_SERVER_FL_UPDATING 4 |
364 | #define AFS_SERVER_FL_PROBED 5 /* The fileserver has been probed */ | 396 | #define AFS_SERVER_FL_PROBED 5 /* The fileserver has been probed */ |
365 | #define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */ | 397 | #define AFS_SERVER_FL_PROBING 6 /* Fileserver is being probed */ |
398 | #define AFS_SERVER_FL_NO_IBULK 7 /* Fileserver doesn't support FS.InlineBulkStatus */ | ||
366 | atomic_t usage; | 399 | atomic_t usage; |
367 | u32 addr_version; /* Address list version */ | 400 | u32 addr_version; /* Address list version */ |
368 | 401 | ||
@@ -455,10 +488,11 @@ struct afs_vnode { | |||
455 | struct afs_volume *volume; /* volume on which vnode resides */ | 488 | struct afs_volume *volume; /* volume on which vnode resides */ |
456 | struct afs_fid fid; /* the file identifier for this inode */ | 489 | struct afs_fid fid; /* the file identifier for this inode */ |
457 | struct afs_file_status status; /* AFS status info for this file */ | 490 | struct afs_file_status status; /* AFS status info for this file */ |
491 | afs_dataversion_t invalid_before; /* Child dentries are invalid before this */ | ||
458 | #ifdef CONFIG_AFS_FSCACHE | 492 | #ifdef CONFIG_AFS_FSCACHE |
459 | struct fscache_cookie *cache; /* caching cookie */ | 493 | struct fscache_cookie *cache; /* caching cookie */ |
460 | #endif | 494 | #endif |
461 | struct afs_permits *permit_cache; /* cache of permits so far obtained */ | 495 | struct afs_permits __rcu *permit_cache; /* cache of permits so far obtained */ |
462 | struct mutex io_lock; /* Lock for serialising I/O on this mutex */ | 496 | struct mutex io_lock; /* Lock for serialising I/O on this mutex */ |
463 | struct mutex validate_lock; /* lock for validating this vnode */ | 497 | struct mutex validate_lock; /* lock for validating this vnode */ |
464 | spinlock_t wb_lock; /* lock for wb_keys */ | 498 | spinlock_t wb_lock; /* lock for wb_keys */ |
@@ -466,12 +500,13 @@ struct afs_vnode { | |||
466 | unsigned long flags; | 500 | unsigned long flags; |
467 | #define AFS_VNODE_CB_PROMISED 0 /* Set if vnode has a callback promise */ | 501 | #define AFS_VNODE_CB_PROMISED 0 /* Set if vnode has a callback promise */ |
468 | #define AFS_VNODE_UNSET 1 /* set if vnode attributes not yet set */ | 502 | #define AFS_VNODE_UNSET 1 /* set if vnode attributes not yet set */ |
469 | #define AFS_VNODE_DIR_MODIFIED 2 /* set if dir vnode's data modified */ | 503 | #define AFS_VNODE_DIR_VALID 2 /* Set if dir contents are valid */ |
470 | #define AFS_VNODE_ZAP_DATA 3 /* set if vnode's data should be invalidated */ | 504 | #define AFS_VNODE_ZAP_DATA 3 /* set if vnode's data should be invalidated */ |
471 | #define AFS_VNODE_DELETED 4 /* set if vnode deleted on server */ | 505 | #define AFS_VNODE_DELETED 4 /* set if vnode deleted on server */ |
472 | #define AFS_VNODE_MOUNTPOINT 5 /* set if vnode is a mountpoint symlink */ | 506 | #define AFS_VNODE_MOUNTPOINT 5 /* set if vnode is a mountpoint symlink */ |
473 | #define AFS_VNODE_AUTOCELL 6 /* set if Vnode is an auto mount point */ | 507 | #define AFS_VNODE_AUTOCELL 6 /* set if Vnode is an auto mount point */ |
474 | #define AFS_VNODE_PSEUDODIR 7 /* set if Vnode is a pseudo directory */ | 508 | #define AFS_VNODE_PSEUDODIR 7 /* set if Vnode is a pseudo directory */ |
509 | #define AFS_VNODE_NEW_CONTENT 8 /* Set if file has new content (create/trunc-0) */ | ||
475 | 510 | ||
476 | struct list_head wb_keys; /* List of keys available for writeback */ | 511 | struct list_head wb_keys; /* List of keys available for writeback */ |
477 | struct list_head pending_locks; /* locks waiting to be granted */ | 512 | struct list_head pending_locks; /* locks waiting to be granted */ |
@@ -611,7 +646,7 @@ extern struct fscache_cookie_def afs_vnode_cache_index_def; | |||
611 | */ | 646 | */ |
612 | extern void afs_init_callback_state(struct afs_server *); | 647 | extern void afs_init_callback_state(struct afs_server *); |
613 | extern void afs_break_callback(struct afs_vnode *); | 648 | extern void afs_break_callback(struct afs_vnode *); |
614 | extern void afs_break_callbacks(struct afs_server *, size_t,struct afs_callback[]); | 649 | extern void afs_break_callbacks(struct afs_server *, size_t, struct afs_callback_break*); |
615 | 650 | ||
616 | extern int afs_register_server_cb_interest(struct afs_vnode *, struct afs_server_entry *); | 651 | extern int afs_register_server_cb_interest(struct afs_vnode *, struct afs_server_entry *); |
617 | extern void afs_put_cb_interest(struct afs_net *, struct afs_cb_interest *); | 652 | extern void afs_put_cb_interest(struct afs_net *, struct afs_cb_interest *); |
@@ -646,11 +681,26 @@ extern bool afs_cm_incoming_call(struct afs_call *); | |||
646 | */ | 681 | */ |
647 | extern const struct file_operations afs_dir_file_operations; | 682 | extern const struct file_operations afs_dir_file_operations; |
648 | extern const struct inode_operations afs_dir_inode_operations; | 683 | extern const struct inode_operations afs_dir_inode_operations; |
684 | extern const struct address_space_operations afs_dir_aops; | ||
685 | extern const struct dentry_operations afs_fs_dentry_operations; | ||
686 | |||
687 | extern void afs_d_release(struct dentry *); | ||
688 | |||
689 | /* | ||
690 | * dir_edit.c | ||
691 | */ | ||
692 | extern void afs_edit_dir_add(struct afs_vnode *, struct qstr *, struct afs_fid *, | ||
693 | enum afs_edit_dir_reason); | ||
694 | extern void afs_edit_dir_remove(struct afs_vnode *, struct qstr *, enum afs_edit_dir_reason); | ||
695 | |||
696 | /* | ||
697 | * dynroot.c | ||
698 | */ | ||
649 | extern const struct file_operations afs_dynroot_file_operations; | 699 | extern const struct file_operations afs_dynroot_file_operations; |
650 | extern const struct inode_operations afs_dynroot_inode_operations; | 700 | extern const struct inode_operations afs_dynroot_inode_operations; |
651 | extern const struct dentry_operations afs_fs_dentry_operations; | 701 | extern const struct dentry_operations afs_dynroot_dentry_operations; |
652 | 702 | ||
653 | extern bool afs_dir_check_page(struct inode *, struct page *); | 703 | extern struct inode *afs_try_auto_mntpt(struct dentry *, struct inode *); |
654 | 704 | ||
655 | /* | 705 | /* |
656 | * file.c | 706 | * file.c |
@@ -680,17 +730,23 @@ extern int afs_flock(struct file *, int, struct file_lock *); | |||
680 | /* | 730 | /* |
681 | * fsclient.c | 731 | * fsclient.c |
682 | */ | 732 | */ |
683 | extern int afs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_volsync *); | 733 | #define AFS_VNODE_NOT_YET_SET 0x01 |
734 | #define AFS_VNODE_META_CHANGED 0x02 | ||
735 | #define AFS_VNODE_DATA_CHANGED 0x04 | ||
736 | extern void afs_update_inode_from_status(struct afs_vnode *, struct afs_file_status *, | ||
737 | const afs_dataversion_t *, u8); | ||
738 | |||
739 | extern int afs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_volsync *, bool); | ||
684 | extern int afs_fs_give_up_callbacks(struct afs_net *, struct afs_server *); | 740 | extern int afs_fs_give_up_callbacks(struct afs_net *, struct afs_server *); |
685 | extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *); | 741 | extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *); |
686 | extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t, | 742 | extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t, u64, |
687 | struct afs_fid *, struct afs_file_status *, struct afs_callback *); | 743 | struct afs_fid *, struct afs_file_status *, struct afs_callback *); |
688 | extern int afs_fs_remove(struct afs_fs_cursor *, const char *, bool); | 744 | extern int afs_fs_remove(struct afs_fs_cursor *, const char *, bool, u64); |
689 | extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *); | 745 | extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64); |
690 | extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, | 746 | extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, u64, |
691 | struct afs_fid *, struct afs_file_status *); | 747 | struct afs_fid *, struct afs_file_status *); |
692 | extern int afs_fs_rename(struct afs_fs_cursor *, const char *, | 748 | extern int afs_fs_rename(struct afs_fs_cursor *, const char *, |
693 | struct afs_vnode *, const char *); | 749 | struct afs_vnode *, const char *, u64, u64); |
694 | extern int afs_fs_store_data(struct afs_fs_cursor *, struct address_space *, | 750 | extern int afs_fs_store_data(struct afs_fs_cursor *, struct address_space *, |
695 | pgoff_t, pgoff_t, unsigned, unsigned); | 751 | pgoff_t, pgoff_t, unsigned, unsigned); |
696 | extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *); | 752 | extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *); |
@@ -702,11 +758,18 @@ extern int afs_fs_give_up_all_callbacks(struct afs_net *, struct afs_server *, | |||
702 | struct afs_addr_cursor *, struct key *); | 758 | struct afs_addr_cursor *, struct key *); |
703 | extern int afs_fs_get_capabilities(struct afs_net *, struct afs_server *, | 759 | extern int afs_fs_get_capabilities(struct afs_net *, struct afs_server *, |
704 | struct afs_addr_cursor *, struct key *); | 760 | struct afs_addr_cursor *, struct key *); |
761 | extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, | ||
762 | struct afs_fid *, struct afs_file_status *, | ||
763 | struct afs_callback *, unsigned int, | ||
764 | struct afs_volsync *); | ||
765 | extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, | ||
766 | struct afs_fid *, struct afs_file_status *, | ||
767 | struct afs_callback *, struct afs_volsync *); | ||
705 | 768 | ||
706 | /* | 769 | /* |
707 | * inode.c | 770 | * inode.c |
708 | */ | 771 | */ |
709 | extern int afs_fetch_status(struct afs_vnode *, struct key *); | 772 | extern int afs_fetch_status(struct afs_vnode *, struct key *, bool); |
710 | extern int afs_iget5_test(struct inode *, void *); | 773 | extern int afs_iget5_test(struct inode *, void *); |
711 | extern struct inode *afs_iget_pseudo_dir(struct super_block *, bool); | 774 | extern struct inode *afs_iget_pseudo_dir(struct super_block *, bool); |
712 | extern struct inode *afs_iget(struct super_block *, struct key *, | 775 | extern struct inode *afs_iget(struct super_block *, struct key *, |
@@ -754,6 +817,13 @@ static inline void afs_put_net(struct afs_net *net) | |||
754 | { | 817 | { |
755 | } | 818 | } |
756 | 819 | ||
820 | static inline void __afs_stat(atomic_t *s) | ||
821 | { | ||
822 | atomic_inc(s); | ||
823 | } | ||
824 | |||
825 | #define afs_stat_v(vnode, n) __afs_stat(&afs_v2net(vnode)->n) | ||
826 | |||
757 | /* | 827 | /* |
758 | * misc.c | 828 | * misc.c |
759 | */ | 829 | */ |
@@ -781,6 +851,7 @@ extern int __net_init afs_proc_init(struct afs_net *); | |||
781 | extern void __net_exit afs_proc_cleanup(struct afs_net *); | 851 | extern void __net_exit afs_proc_cleanup(struct afs_net *); |
782 | extern int afs_proc_cell_setup(struct afs_net *, struct afs_cell *); | 852 | extern int afs_proc_cell_setup(struct afs_net *, struct afs_cell *); |
783 | extern void afs_proc_cell_remove(struct afs_net *, struct afs_cell *); | 853 | extern void afs_proc_cell_remove(struct afs_net *, struct afs_cell *); |
854 | extern void afs_put_sysnames(struct afs_sysnames *); | ||
784 | 855 | ||
785 | /* | 856 | /* |
786 | * rotate.c | 857 | * rotate.c |
@@ -809,6 +880,7 @@ extern void afs_flat_call_destructor(struct afs_call *); | |||
809 | extern void afs_send_empty_reply(struct afs_call *); | 880 | extern void afs_send_empty_reply(struct afs_call *); |
810 | extern void afs_send_simple_reply(struct afs_call *, const void *, size_t); | 881 | extern void afs_send_simple_reply(struct afs_call *, const void *, size_t); |
811 | extern int afs_extract_data(struct afs_call *, void *, size_t, bool); | 882 | extern int afs_extract_data(struct afs_call *, void *, size_t, bool); |
883 | extern int afs_protocol_error(struct afs_call *, int); | ||
812 | 884 | ||
813 | static inline int afs_transfer_reply(struct afs_call *call) | 885 | static inline int afs_transfer_reply(struct afs_call *call) |
814 | { | 886 | { |
@@ -955,7 +1027,6 @@ extern int afs_writepage(struct page *, struct writeback_control *); | |||
955 | extern int afs_writepages(struct address_space *, struct writeback_control *); | 1027 | extern int afs_writepages(struct address_space *, struct writeback_control *); |
956 | extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *); | 1028 | extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *); |
957 | extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *); | 1029 | extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *); |
958 | extern int afs_flush(struct file *, fl_owner_t); | ||
959 | extern int afs_fsync(struct file *, loff_t, loff_t, int); | 1030 | extern int afs_fsync(struct file *, loff_t, loff_t, int); |
960 | extern int afs_page_mkwrite(struct vm_fault *); | 1031 | extern int afs_page_mkwrite(struct vm_fault *); |
961 | extern void afs_prune_wb_keys(struct afs_vnode *); | 1032 | extern void afs_prune_wb_keys(struct afs_vnode *); |
diff --git a/fs/afs/main.c b/fs/afs/main.c index 15a02a05ff40..d7560168b3bf 100644 --- a/fs/afs/main.c +++ b/fs/afs/main.c | |||
@@ -34,11 +34,42 @@ MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list"); | |||
34 | struct workqueue_struct *afs_wq; | 34 | struct workqueue_struct *afs_wq; |
35 | struct afs_net __afs_net; | 35 | struct afs_net __afs_net; |
36 | 36 | ||
37 | #if defined(CONFIG_ALPHA) | ||
38 | const char afs_init_sysname[] = "alpha_linux26"; | ||
39 | #elif defined(CONFIG_X86_64) | ||
40 | const char afs_init_sysname[] = "amd64_linux26"; | ||
41 | #elif defined(CONFIG_ARM) | ||
42 | const char afs_init_sysname[] = "arm_linux26"; | ||
43 | #elif defined(CONFIG_ARM64) | ||
44 | const char afs_init_sysname[] = "aarch64_linux26"; | ||
45 | #elif defined(CONFIG_X86_32) | ||
46 | const char afs_init_sysname[] = "i386_linux26"; | ||
47 | #elif defined(CONFIG_IA64) | ||
48 | const char afs_init_sysname[] = "ia64_linux26"; | ||
49 | #elif defined(CONFIG_PPC64) | ||
50 | const char afs_init_sysname[] = "ppc64_linux26"; | ||
51 | #elif defined(CONFIG_PPC32) | ||
52 | const char afs_init_sysname[] = "ppc_linux26"; | ||
53 | #elif defined(CONFIG_S390) | ||
54 | #ifdef CONFIG_64BIT | ||
55 | const char afs_init_sysname[] = "s390x_linux26"; | ||
56 | #else | ||
57 | const char afs_init_sysname[] = "s390_linux26"; | ||
58 | #endif | ||
59 | #elif defined(CONFIG_SPARC64) | ||
60 | const char afs_init_sysname[] = "sparc64_linux26"; | ||
61 | #elif defined(CONFIG_SPARC32) | ||
62 | const char afs_init_sysname[] = "sparc_linux26"; | ||
63 | #else | ||
64 | const char afs_init_sysname[] = "unknown_linux26"; | ||
65 | #endif | ||
66 | |||
37 | /* | 67 | /* |
38 | * Initialise an AFS network namespace record. | 68 | * Initialise an AFS network namespace record. |
39 | */ | 69 | */ |
40 | static int __net_init afs_net_init(struct afs_net *net) | 70 | static int __net_init afs_net_init(struct afs_net *net) |
41 | { | 71 | { |
72 | struct afs_sysnames *sysnames; | ||
42 | int ret; | 73 | int ret; |
43 | 74 | ||
44 | net->live = true; | 75 | net->live = true; |
@@ -67,6 +98,16 @@ static int __net_init afs_net_init(struct afs_net *net) | |||
67 | INIT_WORK(&net->fs_manager, afs_manage_servers); | 98 | INIT_WORK(&net->fs_manager, afs_manage_servers); |
68 | timer_setup(&net->fs_timer, afs_servers_timer, 0); | 99 | timer_setup(&net->fs_timer, afs_servers_timer, 0); |
69 | 100 | ||
101 | ret = -ENOMEM; | ||
102 | sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL); | ||
103 | if (!sysnames) | ||
104 | goto error_sysnames; | ||
105 | sysnames->subs[0] = (char *)&afs_init_sysname; | ||
106 | sysnames->nr = 1; | ||
107 | refcount_set(&sysnames->usage, 1); | ||
108 | net->sysnames = sysnames; | ||
109 | rwlock_init(&net->sysnames_lock); | ||
110 | |||
70 | /* Register the /proc stuff */ | 111 | /* Register the /proc stuff */ |
71 | ret = afs_proc_init(net); | 112 | ret = afs_proc_init(net); |
72 | if (ret < 0) | 113 | if (ret < 0) |
@@ -92,6 +133,8 @@ error_cell_init: | |||
92 | net->live = false; | 133 | net->live = false; |
93 | afs_proc_cleanup(net); | 134 | afs_proc_cleanup(net); |
94 | error_proc: | 135 | error_proc: |
136 | afs_put_sysnames(net->sysnames); | ||
137 | error_sysnames: | ||
95 | net->live = false; | 138 | net->live = false; |
96 | return ret; | 139 | return ret; |
97 | } | 140 | } |
@@ -106,6 +149,7 @@ static void __net_exit afs_net_exit(struct afs_net *net) | |||
106 | afs_purge_servers(net); | 149 | afs_purge_servers(net); |
107 | afs_close_socket(net); | 150 | afs_close_socket(net); |
108 | afs_proc_cleanup(net); | 151 | afs_proc_cleanup(net); |
152 | afs_put_sysnames(net->sysnames); | ||
109 | } | 153 | } |
110 | 154 | ||
111 | /* | 155 | /* |
diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 4508dd54f789..839a22280606 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c | |||
@@ -126,6 +126,34 @@ static const struct file_operations afs_proc_servers_fops = { | |||
126 | .release = seq_release, | 126 | .release = seq_release, |
127 | }; | 127 | }; |
128 | 128 | ||
129 | static int afs_proc_sysname_open(struct inode *inode, struct file *file); | ||
130 | static int afs_proc_sysname_release(struct inode *inode, struct file *file); | ||
131 | static void *afs_proc_sysname_start(struct seq_file *p, loff_t *pos); | ||
132 | static void *afs_proc_sysname_next(struct seq_file *p, void *v, | ||
133 | loff_t *pos); | ||
134 | static void afs_proc_sysname_stop(struct seq_file *p, void *v); | ||
135 | static int afs_proc_sysname_show(struct seq_file *m, void *v); | ||
136 | static ssize_t afs_proc_sysname_write(struct file *file, | ||
137 | const char __user *buf, | ||
138 | size_t size, loff_t *_pos); | ||
139 | |||
140 | static const struct seq_operations afs_proc_sysname_ops = { | ||
141 | .start = afs_proc_sysname_start, | ||
142 | .next = afs_proc_sysname_next, | ||
143 | .stop = afs_proc_sysname_stop, | ||
144 | .show = afs_proc_sysname_show, | ||
145 | }; | ||
146 | |||
147 | static const struct file_operations afs_proc_sysname_fops = { | ||
148 | .open = afs_proc_sysname_open, | ||
149 | .read = seq_read, | ||
150 | .llseek = seq_lseek, | ||
151 | .release = afs_proc_sysname_release, | ||
152 | .write = afs_proc_sysname_write, | ||
153 | }; | ||
154 | |||
155 | static const struct file_operations afs_proc_stats_fops; | ||
156 | |||
129 | /* | 157 | /* |
130 | * initialise the /proc/fs/afs/ directory | 158 | * initialise the /proc/fs/afs/ directory |
131 | */ | 159 | */ |
@@ -139,7 +167,9 @@ int afs_proc_init(struct afs_net *net) | |||
139 | 167 | ||
140 | if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) || | 168 | if (!proc_create("cells", 0644, net->proc_afs, &afs_proc_cells_fops) || |
141 | !proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops) || | 169 | !proc_create("rootcell", 0644, net->proc_afs, &afs_proc_rootcell_fops) || |
142 | !proc_create("servers", 0644, net->proc_afs, &afs_proc_servers_fops)) | 170 | !proc_create("servers", 0644, net->proc_afs, &afs_proc_servers_fops) || |
171 | !proc_create("stats", 0644, net->proc_afs, &afs_proc_stats_fops) || | ||
172 | !proc_create("sysname", 0644, net->proc_afs, &afs_proc_sysname_fops)) | ||
143 | goto error_tree; | 173 | goto error_tree; |
144 | 174 | ||
145 | _leave(" = 0"); | 175 | _leave(" = 0"); |
@@ -183,6 +213,7 @@ static int afs_proc_cells_open(struct inode *inode, struct file *file) | |||
183 | * first item | 213 | * first item |
184 | */ | 214 | */ |
185 | static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos) | 215 | static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos) |
216 | __acquires(rcu) | ||
186 | { | 217 | { |
187 | struct afs_net *net = afs_seq2net(m); | 218 | struct afs_net *net = afs_seq2net(m); |
188 | 219 | ||
@@ -204,6 +235,7 @@ static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos) | |||
204 | * clean up after reading from the cells list | 235 | * clean up after reading from the cells list |
205 | */ | 236 | */ |
206 | static void afs_proc_cells_stop(struct seq_file *m, void *v) | 237 | static void afs_proc_cells_stop(struct seq_file *m, void *v) |
238 | __releases(rcu) | ||
207 | { | 239 | { |
208 | rcu_read_unlock(); | 240 | rcu_read_unlock(); |
209 | } | 241 | } |
@@ -282,7 +314,8 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, | |||
282 | goto done; | 314 | goto done; |
283 | } | 315 | } |
284 | 316 | ||
285 | set_bit(AFS_CELL_FL_NO_GC, &cell->flags); | 317 | if (test_and_set_bit(AFS_CELL_FL_NO_GC, &cell->flags)) |
318 | afs_put_cell(net, cell); | ||
286 | printk("kAFS: Added new cell '%s'\n", name); | 319 | printk("kAFS: Added new cell '%s'\n", name); |
287 | } else { | 320 | } else { |
288 | goto inval; | 321 | goto inval; |
@@ -304,7 +337,40 @@ inval: | |||
304 | static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, | 337 | static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf, |
305 | size_t size, loff_t *_pos) | 338 | size_t size, loff_t *_pos) |
306 | { | 339 | { |
307 | return 0; | 340 | struct afs_cell *cell; |
341 | struct afs_net *net = afs_proc2net(file); | ||
342 | unsigned int seq = 0; | ||
343 | char name[AFS_MAXCELLNAME + 1]; | ||
344 | int len; | ||
345 | |||
346 | if (*_pos > 0) | ||
347 | return 0; | ||
348 | if (!net->ws_cell) | ||
349 | return 0; | ||
350 | |||
351 | rcu_read_lock(); | ||
352 | do { | ||
353 | read_seqbegin_or_lock(&net->cells_lock, &seq); | ||
354 | len = 0; | ||
355 | cell = rcu_dereference_raw(net->ws_cell); | ||
356 | if (cell) { | ||
357 | len = cell->name_len; | ||
358 | memcpy(name, cell->name, len); | ||
359 | } | ||
360 | } while (need_seqretry(&net->cells_lock, seq)); | ||
361 | done_seqretry(&net->cells_lock, seq); | ||
362 | rcu_read_unlock(); | ||
363 | |||
364 | if (!len) | ||
365 | return 0; | ||
366 | |||
367 | name[len++] = '\n'; | ||
368 | if (len > size) | ||
369 | len = size; | ||
370 | if (copy_to_user(buf, name, len) != 0) | ||
371 | return -EFAULT; | ||
372 | *_pos = 1; | ||
373 | return len; | ||
308 | } | 374 | } |
309 | 375 | ||
310 | /* | 376 | /* |
@@ -327,6 +393,12 @@ static ssize_t afs_proc_rootcell_write(struct file *file, | |||
327 | if (IS_ERR(kbuf)) | 393 | if (IS_ERR(kbuf)) |
328 | return PTR_ERR(kbuf); | 394 | return PTR_ERR(kbuf); |
329 | 395 | ||
396 | ret = -EINVAL; | ||
397 | if (kbuf[0] == '.') | ||
398 | goto out; | ||
399 | if (memchr(kbuf, '/', size)) | ||
400 | goto out; | ||
401 | |||
330 | /* trim to first NL */ | 402 | /* trim to first NL */ |
331 | s = memchr(kbuf, '\n', size); | 403 | s = memchr(kbuf, '\n', size); |
332 | if (s) | 404 | if (s) |
@@ -339,6 +411,7 @@ static ssize_t afs_proc_rootcell_write(struct file *file, | |||
339 | if (ret >= 0) | 411 | if (ret >= 0) |
340 | ret = size; /* consume everything, always */ | 412 | ret = size; /* consume everything, always */ |
341 | 413 | ||
414 | out: | ||
342 | kfree(kbuf); | 415 | kfree(kbuf); |
343 | _leave(" = %d", ret); | 416 | _leave(" = %d", ret); |
344 | return ret; | 417 | return ret; |
@@ -413,6 +486,7 @@ static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file) | |||
413 | * first item | 486 | * first item |
414 | */ | 487 | */ |
415 | static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) | 488 | static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos) |
489 | __acquires(cell->proc_lock) | ||
416 | { | 490 | { |
417 | struct afs_cell *cell = m->private; | 491 | struct afs_cell *cell = m->private; |
418 | 492 | ||
@@ -438,6 +512,7 @@ static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, | |||
438 | * clean up after reading from the cells list | 512 | * clean up after reading from the cells list |
439 | */ | 513 | */ |
440 | static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v) | 514 | static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v) |
515 | __releases(cell->proc_lock) | ||
441 | { | 516 | { |
442 | struct afs_cell *cell = p->private; | 517 | struct afs_cell *cell = p->private; |
443 | 518 | ||
@@ -500,6 +575,7 @@ static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file) | |||
500 | * first item | 575 | * first item |
501 | */ | 576 | */ |
502 | static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) | 577 | static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos) |
578 | __acquires(rcu) | ||
503 | { | 579 | { |
504 | struct afs_addr_list *alist; | 580 | struct afs_addr_list *alist; |
505 | struct afs_cell *cell = m->private; | 581 | struct afs_cell *cell = m->private; |
@@ -544,6 +620,7 @@ static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, | |||
544 | * clean up after reading from the cells list | 620 | * clean up after reading from the cells list |
545 | */ | 621 | */ |
546 | static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v) | 622 | static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v) |
623 | __releases(rcu) | ||
547 | { | 624 | { |
548 | rcu_read_unlock(); | 625 | rcu_read_unlock(); |
549 | } | 626 | } |
@@ -580,6 +657,7 @@ static int afs_proc_servers_open(struct inode *inode, struct file *file) | |||
580 | * first item. | 657 | * first item. |
581 | */ | 658 | */ |
582 | static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos) | 659 | static void *afs_proc_servers_start(struct seq_file *m, loff_t *_pos) |
660 | __acquires(rcu) | ||
583 | { | 661 | { |
584 | struct afs_net *net = afs_seq2net(m); | 662 | struct afs_net *net = afs_seq2net(m); |
585 | 663 | ||
@@ -601,6 +679,7 @@ static void *afs_proc_servers_next(struct seq_file *m, void *v, loff_t *_pos) | |||
601 | * clean up after reading from the cells list | 679 | * clean up after reading from the cells list |
602 | */ | 680 | */ |
603 | static void afs_proc_servers_stop(struct seq_file *p, void *v) | 681 | static void afs_proc_servers_stop(struct seq_file *p, void *v) |
682 | __releases(rcu) | ||
604 | { | 683 | { |
605 | rcu_read_unlock(); | 684 | rcu_read_unlock(); |
606 | } | 685 | } |
@@ -626,3 +705,244 @@ static int afs_proc_servers_show(struct seq_file *m, void *v) | |||
626 | &alist->addrs[alist->index].transport); | 705 | &alist->addrs[alist->index].transport); |
627 | return 0; | 706 | return 0; |
628 | } | 707 | } |
708 | |||
709 | void afs_put_sysnames(struct afs_sysnames *sysnames) | ||
710 | { | ||
711 | int i; | ||
712 | |||
713 | if (sysnames && refcount_dec_and_test(&sysnames->usage)) { | ||
714 | for (i = 0; i < sysnames->nr; i++) | ||
715 | if (sysnames->subs[i] != afs_init_sysname && | ||
716 | sysnames->subs[i] != sysnames->blank) | ||
717 | kfree(sysnames->subs[i]); | ||
718 | } | ||
719 | } | ||
720 | |||
721 | /* | ||
722 | * Handle opening of /proc/fs/afs/sysname. If it is opened for writing, we | ||
723 | * assume the caller wants to change the substitution list and we allocate a | ||
724 | * buffer to hold the list. | ||
725 | */ | ||
726 | static int afs_proc_sysname_open(struct inode *inode, struct file *file) | ||
727 | { | ||
728 | struct afs_sysnames *sysnames; | ||
729 | struct seq_file *m; | ||
730 | int ret; | ||
731 | |||
732 | ret = seq_open(file, &afs_proc_sysname_ops); | ||
733 | if (ret < 0) | ||
734 | return ret; | ||
735 | |||
736 | if (file->f_mode & FMODE_WRITE) { | ||
737 | sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL); | ||
738 | if (!sysnames) { | ||
739 | seq_release(inode, file); | ||
740 | return -ENOMEM; | ||
741 | } | ||
742 | |||
743 | refcount_set(&sysnames->usage, 1); | ||
744 | m = file->private_data; | ||
745 | m->private = sysnames; | ||
746 | } | ||
747 | |||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | /* | ||
752 | * Handle writes to /proc/fs/afs/sysname to set the @sys substitution. | ||
753 | */ | ||
754 | static ssize_t afs_proc_sysname_write(struct file *file, | ||
755 | const char __user *buf, | ||
756 | size_t size, loff_t *_pos) | ||
757 | { | ||
758 | struct afs_sysnames *sysnames; | ||
759 | struct seq_file *m = file->private_data; | ||
760 | char *kbuf = NULL, *s, *p, *sub; | ||
761 | int ret, len; | ||
762 | |||
763 | sysnames = m->private; | ||
764 | if (!sysnames) | ||
765 | return -EINVAL; | ||
766 | if (sysnames->error) | ||
767 | return sysnames->error; | ||
768 | |||
769 | if (size >= PAGE_SIZE - 1) { | ||
770 | sysnames->error = -EINVAL; | ||
771 | return -EINVAL; | ||
772 | } | ||
773 | if (size == 0) | ||
774 | return 0; | ||
775 | |||
776 | kbuf = memdup_user_nul(buf, size); | ||
777 | if (IS_ERR(kbuf)) | ||
778 | return PTR_ERR(kbuf); | ||
779 | |||
780 | inode_lock(file_inode(file)); | ||
781 | |||
782 | p = kbuf; | ||
783 | while ((s = strsep(&p, " \t\n"))) { | ||
784 | len = strlen(s); | ||
785 | if (len == 0) | ||
786 | continue; | ||
787 | ret = -ENAMETOOLONG; | ||
788 | if (len >= AFSNAMEMAX) | ||
789 | goto error; | ||
790 | |||
791 | if (len >= 4 && | ||
792 | s[len - 4] == '@' && | ||
793 | s[len - 3] == 's' && | ||
794 | s[len - 2] == 'y' && | ||
795 | s[len - 1] == 's') | ||
796 | /* Protect against recursion */ | ||
797 | goto invalid; | ||
798 | |||
799 | if (s[0] == '.' && | ||
800 | (len < 2 || (len == 2 && s[1] == '.'))) | ||
801 | goto invalid; | ||
802 | |||
803 | if (memchr(s, '/', len)) | ||
804 | goto invalid; | ||
805 | |||
806 | ret = -EFBIG; | ||
807 | if (sysnames->nr >= AFS_NR_SYSNAME) | ||
808 | goto out; | ||
809 | |||
810 | if (strcmp(s, afs_init_sysname) == 0) { | ||
811 | sub = (char *)afs_init_sysname; | ||
812 | } else { | ||
813 | ret = -ENOMEM; | ||
814 | sub = kmemdup(s, len + 1, GFP_KERNEL); | ||
815 | if (!sub) | ||
816 | goto out; | ||
817 | } | ||
818 | |||
819 | sysnames->subs[sysnames->nr] = sub; | ||
820 | sysnames->nr++; | ||
821 | } | ||
822 | |||
823 | ret = size; /* consume everything, always */ | ||
824 | out: | ||
825 | inode_unlock(file_inode(file)); | ||
826 | kfree(kbuf); | ||
827 | return ret; | ||
828 | |||
829 | invalid: | ||
830 | ret = -EINVAL; | ||
831 | error: | ||
832 | sysnames->error = ret; | ||
833 | goto out; | ||
834 | } | ||
835 | |||
836 | static int afs_proc_sysname_release(struct inode *inode, struct file *file) | ||
837 | { | ||
838 | struct afs_sysnames *sysnames, *kill = NULL; | ||
839 | struct seq_file *m = file->private_data; | ||
840 | struct afs_net *net = afs_seq2net(m); | ||
841 | |||
842 | sysnames = m->private; | ||
843 | if (sysnames) { | ||
844 | if (!sysnames->error) { | ||
845 | kill = sysnames; | ||
846 | if (sysnames->nr == 0) { | ||
847 | sysnames->subs[0] = sysnames->blank; | ||
848 | sysnames->nr++; | ||
849 | } | ||
850 | write_lock(&net->sysnames_lock); | ||
851 | kill = net->sysnames; | ||
852 | net->sysnames = sysnames; | ||
853 | write_unlock(&net->sysnames_lock); | ||
854 | } | ||
855 | afs_put_sysnames(kill); | ||
856 | } | ||
857 | |||
858 | return seq_release(inode, file); | ||
859 | } | ||
860 | |||
861 | static void *afs_proc_sysname_start(struct seq_file *m, loff_t *pos) | ||
862 | __acquires(&net->sysnames_lock) | ||
863 | { | ||
864 | struct afs_net *net = afs_seq2net(m); | ||
865 | struct afs_sysnames *names = net->sysnames; | ||
866 | |||
867 | read_lock(&net->sysnames_lock); | ||
868 | |||
869 | if (*pos >= names->nr) | ||
870 | return NULL; | ||
871 | return (void *)(unsigned long)(*pos + 1); | ||
872 | } | ||
873 | |||
874 | static void *afs_proc_sysname_next(struct seq_file *m, void *v, loff_t *pos) | ||
875 | { | ||
876 | struct afs_net *net = afs_seq2net(m); | ||
877 | struct afs_sysnames *names = net->sysnames; | ||
878 | |||
879 | *pos += 1; | ||
880 | if (*pos >= names->nr) | ||
881 | return NULL; | ||
882 | return (void *)(unsigned long)(*pos + 1); | ||
883 | } | ||
884 | |||
885 | static void afs_proc_sysname_stop(struct seq_file *m, void *v) | ||
886 | __releases(&net->sysnames_lock) | ||
887 | { | ||
888 | struct afs_net *net = afs_seq2net(m); | ||
889 | |||
890 | read_unlock(&net->sysnames_lock); | ||
891 | } | ||
892 | |||
893 | static int afs_proc_sysname_show(struct seq_file *m, void *v) | ||
894 | { | ||
895 | struct afs_net *net = afs_seq2net(m); | ||
896 | struct afs_sysnames *sysnames = net->sysnames; | ||
897 | unsigned int i = (unsigned long)v - 1; | ||
898 | |||
899 | if (i < sysnames->nr) | ||
900 | seq_printf(m, "%s\n", sysnames->subs[i]); | ||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | /* | ||
905 | * Display general per-net namespace statistics | ||
906 | */ | ||
907 | static int afs_proc_stats_show(struct seq_file *m, void *v) | ||
908 | { | ||
909 | struct afs_net *net = afs_seq2net(m); | ||
910 | |||
911 | seq_puts(m, "kAFS statistics\n"); | ||
912 | |||
913 | seq_printf(m, "dir-mgmt: look=%u reval=%u inval=%u relpg=%u\n", | ||
914 | atomic_read(&net->n_lookup), | ||
915 | atomic_read(&net->n_reval), | ||
916 | atomic_read(&net->n_inval), | ||
917 | atomic_read(&net->n_relpg)); | ||
918 | |||
919 | seq_printf(m, "dir-data: rdpg=%u\n", | ||
920 | atomic_read(&net->n_read_dir)); | ||
921 | |||
922 | seq_printf(m, "dir-edit: cr=%u rm=%u\n", | ||
923 | atomic_read(&net->n_dir_cr), | ||
924 | atomic_read(&net->n_dir_rm)); | ||
925 | |||
926 | seq_printf(m, "file-rd : n=%u nb=%lu\n", | ||
927 | atomic_read(&net->n_fetches), | ||
928 | atomic_long_read(&net->n_fetch_bytes)); | ||
929 | seq_printf(m, "file-wr : n=%u nb=%lu\n", | ||
930 | atomic_read(&net->n_stores), | ||
931 | atomic_long_read(&net->n_store_bytes)); | ||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | /* | ||
936 | * Open "/proc/fs/afs/stats" to allow reading of the stat counters. | ||
937 | */ | ||
938 | static int afs_proc_stats_open(struct inode *inode, struct file *file) | ||
939 | { | ||
940 | return single_open(file, afs_proc_stats_show, NULL); | ||
941 | } | ||
942 | |||
943 | static const struct file_operations afs_proc_stats_fops = { | ||
944 | .open = afs_proc_stats_open, | ||
945 | .read = seq_read, | ||
946 | .llseek = seq_lseek, | ||
947 | .release = single_release, | ||
948 | }; | ||
diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c index ad1328d85526..ac0feac9d746 100644 --- a/fs/afs/rotate.c +++ b/fs/afs/rotate.c | |||
@@ -21,7 +21,7 @@ | |||
21 | /* | 21 | /* |
22 | * Initialise a filesystem server cursor for iterating over FS servers. | 22 | * Initialise a filesystem server cursor for iterating over FS servers. |
23 | */ | 23 | */ |
24 | void afs_init_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode) | 24 | static void afs_init_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode) |
25 | { | 25 | { |
26 | memset(fc, 0, sizeof(*fc)); | 26 | memset(fc, 0, sizeof(*fc)); |
27 | } | 27 | } |
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index f7ae54b6a393..5c6263972ec9 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c | |||
@@ -926,3 +926,12 @@ int afs_extract_data(struct afs_call *call, void *buf, size_t count, | |||
926 | afs_set_call_complete(call, ret, remote_abort); | 926 | afs_set_call_complete(call, ret, remote_abort); |
927 | return ret; | 927 | return ret; |
928 | } | 928 | } |
929 | |||
930 | /* | ||
931 | * Log protocol error production. | ||
932 | */ | ||
933 | noinline int afs_protocol_error(struct afs_call *call, int error) | ||
934 | { | ||
935 | trace_afs_protocol_error(call, error, __builtin_return_address(0)); | ||
936 | return error; | ||
937 | } | ||
diff --git a/fs/afs/security.c b/fs/afs/security.c index b88b7d45fdaa..cea2fff313dc 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c | |||
@@ -178,18 +178,14 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, | |||
178 | } | 178 | } |
179 | } | 179 | } |
180 | 180 | ||
181 | if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break)) { | 181 | if (cb_break != (vnode->cb_break + vnode->cb_interest->server->cb_s_break)) |
182 | rcu_read_unlock(); | ||
183 | goto someone_else_changed_it; | 182 | goto someone_else_changed_it; |
184 | } | ||
185 | 183 | ||
186 | /* We need a ref on any permits list we want to copy as we'll have to | 184 | /* We need a ref on any permits list we want to copy as we'll have to |
187 | * drop the lock to do memory allocation. | 185 | * drop the lock to do memory allocation. |
188 | */ | 186 | */ |
189 | if (permits && !refcount_inc_not_zero(&permits->usage)) { | 187 | if (permits && !refcount_inc_not_zero(&permits->usage)) |
190 | rcu_read_unlock(); | ||
191 | goto someone_else_changed_it; | 188 | goto someone_else_changed_it; |
192 | } | ||
193 | 189 | ||
194 | rcu_read_unlock(); | 190 | rcu_read_unlock(); |
195 | 191 | ||
@@ -278,6 +274,7 @@ someone_else_changed_it: | |||
278 | /* Someone else changed the cache under us - don't recheck at this | 274 | /* Someone else changed the cache under us - don't recheck at this |
279 | * time. | 275 | * time. |
280 | */ | 276 | */ |
277 | rcu_read_unlock(); | ||
281 | return; | 278 | return; |
282 | } | 279 | } |
283 | 280 | ||
@@ -296,8 +293,6 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key, | |||
296 | _enter("{%x:%u},%x", | 293 | _enter("{%x:%u},%x", |
297 | vnode->fid.vid, vnode->fid.vnode, key_serial(key)); | 294 | vnode->fid.vid, vnode->fid.vnode, key_serial(key)); |
298 | 295 | ||
299 | permits = vnode->permit_cache; | ||
300 | |||
301 | /* check the permits to see if we've got one yet */ | 296 | /* check the permits to see if we've got one yet */ |
302 | if (key == vnode->volume->cell->anonymous_key) { | 297 | if (key == vnode->volume->cell->anonymous_key) { |
303 | _debug("anon"); | 298 | _debug("anon"); |
@@ -327,7 +322,7 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key, | |||
327 | */ | 322 | */ |
328 | _debug("no valid permit"); | 323 | _debug("no valid permit"); |
329 | 324 | ||
330 | ret = afs_fetch_status(vnode, key); | 325 | ret = afs_fetch_status(vnode, key, false); |
331 | if (ret < 0) { | 326 | if (ret < 0) { |
332 | *_access = 0; | 327 | *_access = 0; |
333 | _leave(" = %d", ret); | 328 | _leave(" = %d", ret); |
diff --git a/fs/afs/server.c b/fs/afs/server.c index a43ef77dabae..e23be63998a8 100644 --- a/fs/afs/server.c +++ b/fs/afs/server.c | |||
@@ -59,7 +59,8 @@ struct afs_server *afs_find_server(struct afs_net *net, | |||
59 | alist = rcu_dereference(server->addresses); | 59 | alist = rcu_dereference(server->addresses); |
60 | for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { | 60 | for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) { |
61 | b = &alist->addrs[i].transport.sin6; | 61 | b = &alist->addrs[i].transport.sin6; |
62 | diff = (u16)a->sin6_port - (u16)b->sin6_port; | 62 | diff = ((u16 __force)a->sin6_port - |
63 | (u16 __force)b->sin6_port); | ||
63 | if (diff == 0) | 64 | if (diff == 0) |
64 | diff = memcmp(&a->sin6_addr, | 65 | diff = memcmp(&a->sin6_addr, |
65 | &b->sin6_addr, | 66 | &b->sin6_addr, |
@@ -79,10 +80,11 @@ struct afs_server *afs_find_server(struct afs_net *net, | |||
79 | alist = rcu_dereference(server->addresses); | 80 | alist = rcu_dereference(server->addresses); |
80 | for (i = 0; i < alist->nr_ipv4; i++) { | 81 | for (i = 0; i < alist->nr_ipv4; i++) { |
81 | b = &alist->addrs[i].transport.sin6; | 82 | b = &alist->addrs[i].transport.sin6; |
82 | diff = (u16)a->sin6_port - (u16)b->sin6_port; | 83 | diff = ((u16 __force)a->sin6_port - |
84 | (u16 __force)b->sin6_port); | ||
83 | if (diff == 0) | 85 | if (diff == 0) |
84 | diff = ((u32)a->sin6_addr.s6_addr32[3] - | 86 | diff = ((u32 __force)a->sin6_addr.s6_addr32[3] - |
85 | (u32)b->sin6_addr.s6_addr32[3]); | 87 | (u32 __force)b->sin6_addr.s6_addr32[3]); |
86 | if (diff == 0) | 88 | if (diff == 0) |
87 | goto found; | 89 | goto found; |
88 | if (diff < 0) { | 90 | if (diff < 0) { |
@@ -381,7 +383,7 @@ static void afs_server_rcu(struct rcu_head *rcu) | |||
381 | { | 383 | { |
382 | struct afs_server *server = container_of(rcu, struct afs_server, rcu); | 384 | struct afs_server *server = container_of(rcu, struct afs_server, rcu); |
383 | 385 | ||
384 | afs_put_addrlist(server->addresses); | 386 | afs_put_addrlist(rcu_access_pointer(server->addresses)); |
385 | kfree(server); | 387 | kfree(server); |
386 | } | 388 | } |
387 | 389 | ||
@@ -390,7 +392,7 @@ static void afs_server_rcu(struct rcu_head *rcu) | |||
390 | */ | 392 | */ |
391 | static void afs_destroy_server(struct afs_net *net, struct afs_server *server) | 393 | static void afs_destroy_server(struct afs_net *net, struct afs_server *server) |
392 | { | 394 | { |
393 | struct afs_addr_list *alist = server->addresses; | 395 | struct afs_addr_list *alist = rcu_access_pointer(server->addresses); |
394 | struct afs_addr_cursor ac = { | 396 | struct afs_addr_cursor ac = { |
395 | .alist = alist, | 397 | .alist = alist, |
396 | .addr = &alist->addrs[0], | 398 | .addr = &alist->addrs[0], |
diff --git a/fs/afs/super.c b/fs/afs/super.c index 3623c952b6ff..65081ec3c36e 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -154,7 +154,7 @@ static int afs_show_devname(struct seq_file *m, struct dentry *root) | |||
154 | seq_puts(m, "none"); | 154 | seq_puts(m, "none"); |
155 | return 0; | 155 | return 0; |
156 | } | 156 | } |
157 | 157 | ||
158 | switch (volume->type) { | 158 | switch (volume->type) { |
159 | case AFSVL_RWVOL: | 159 | case AFSVL_RWVOL: |
160 | break; | 160 | break; |
@@ -269,7 +269,7 @@ static int afs_parse_device_name(struct afs_mount_params *params, | |||
269 | int cellnamesz; | 269 | int cellnamesz; |
270 | 270 | ||
271 | _enter(",%s", name); | 271 | _enter(",%s", name); |
272 | 272 | ||
273 | if (!name) { | 273 | if (!name) { |
274 | printk(KERN_ERR "kAFS: no volume name specified\n"); | 274 | printk(KERN_ERR "kAFS: no volume name specified\n"); |
275 | return -EINVAL; | 275 | return -EINVAL; |
@@ -418,7 +418,10 @@ static int afs_fill_super(struct super_block *sb, | |||
418 | if (!sb->s_root) | 418 | if (!sb->s_root) |
419 | goto error; | 419 | goto error; |
420 | 420 | ||
421 | sb->s_d_op = &afs_fs_dentry_operations; | 421 | if (params->dyn_root) |
422 | sb->s_d_op = &afs_dynroot_dentry_operations; | ||
423 | else | ||
424 | sb->s_d_op = &afs_fs_dentry_operations; | ||
422 | 425 | ||
423 | _leave(" = 0"); | 426 | _leave(" = 0"); |
424 | return 0; | 427 | return 0; |
@@ -676,7 +679,7 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
676 | buf->f_bfree = 0; | 679 | buf->f_bfree = 0; |
677 | return 0; | 680 | return 0; |
678 | } | 681 | } |
679 | 682 | ||
680 | key = afs_request_key(vnode->volume->cell); | 683 | key = afs_request_key(vnode->volume->cell); |
681 | if (IS_ERR(key)) | 684 | if (IS_ERR(key)) |
682 | return PTR_ERR(key); | 685 | return PTR_ERR(key); |
diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c index 5d8562f1ad4a..1ed7e2fd2f35 100644 --- a/fs/afs/vlclient.c +++ b/fs/afs/vlclient.c | |||
@@ -303,7 +303,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net, | |||
303 | r->uuid.clock_seq_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved); | 303 | r->uuid.clock_seq_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved); |
304 | r->uuid.clock_seq_low = htonl(u->clock_seq_low); | 304 | r->uuid.clock_seq_low = htonl(u->clock_seq_low); |
305 | for (i = 0; i < 6; i++) | 305 | for (i = 0; i < 6; i++) |
306 | r->uuid.node[i] = ntohl(u->node[i]); | 306 | r->uuid.node[i] = htonl(u->node[i]); |
307 | 307 | ||
308 | trace_afs_make_vl_call(call); | 308 | trace_afs_make_vl_call(call); |
309 | return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false); | 309 | return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false); |
@@ -450,7 +450,7 @@ again: | |||
450 | call->count2 = ntohl(*bp); /* Type or next count */ | 450 | call->count2 = ntohl(*bp); /* Type or next count */ |
451 | 451 | ||
452 | if (call->count > YFS_MAXENDPOINTS) | 452 | if (call->count > YFS_MAXENDPOINTS) |
453 | return -EBADMSG; | 453 | return afs_protocol_error(call, -EBADMSG); |
454 | 454 | ||
455 | alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT); | 455 | alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT); |
456 | if (!alist) | 456 | if (!alist) |
@@ -474,7 +474,7 @@ again: | |||
474 | size = sizeof(__be32) * (1 + 4 + 1); | 474 | size = sizeof(__be32) * (1 + 4 + 1); |
475 | break; | 475 | break; |
476 | default: | 476 | default: |
477 | return -EBADMSG; | 477 | return afs_protocol_error(call, -EBADMSG); |
478 | } | 478 | } |
479 | 479 | ||
480 | size += sizeof(__be32); | 480 | size += sizeof(__be32); |
@@ -487,24 +487,24 @@ again: | |||
487 | switch (call->count2) { | 487 | switch (call->count2) { |
488 | case YFS_ENDPOINT_IPV4: | 488 | case YFS_ENDPOINT_IPV4: |
489 | if (ntohl(bp[0]) != sizeof(__be32) * 2) | 489 | if (ntohl(bp[0]) != sizeof(__be32) * 2) |
490 | return -EBADMSG; | 490 | return afs_protocol_error(call, -EBADMSG); |
491 | afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2])); | 491 | afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2])); |
492 | bp += 3; | 492 | bp += 3; |
493 | break; | 493 | break; |
494 | case YFS_ENDPOINT_IPV6: | 494 | case YFS_ENDPOINT_IPV6: |
495 | if (ntohl(bp[0]) != sizeof(__be32) * 5) | 495 | if (ntohl(bp[0]) != sizeof(__be32) * 5) |
496 | return -EBADMSG; | 496 | return afs_protocol_error(call, -EBADMSG); |
497 | afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5])); | 497 | afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5])); |
498 | bp += 6; | 498 | bp += 6; |
499 | break; | 499 | break; |
500 | default: | 500 | default: |
501 | return -EBADMSG; | 501 | return afs_protocol_error(call, -EBADMSG); |
502 | } | 502 | } |
503 | 503 | ||
504 | /* Got either the type of the next entry or the count of | 504 | /* Got either the type of the next entry or the count of |
505 | * volEndpoints if no more fsEndpoints. | 505 | * volEndpoints if no more fsEndpoints. |
506 | */ | 506 | */ |
507 | call->count2 = htonl(*bp++); | 507 | call->count2 = ntohl(*bp++); |
508 | 508 | ||
509 | call->offset = 0; | 509 | call->offset = 0; |
510 | call->count--; | 510 | call->count--; |
@@ -517,7 +517,7 @@ again: | |||
517 | if (!call->count) | 517 | if (!call->count) |
518 | goto end; | 518 | goto end; |
519 | if (call->count > YFS_MAXENDPOINTS) | 519 | if (call->count > YFS_MAXENDPOINTS) |
520 | return -EBADMSG; | 520 | return afs_protocol_error(call, -EBADMSG); |
521 | 521 | ||
522 | call->unmarshall = 3; | 522 | call->unmarshall = 3; |
523 | 523 | ||
@@ -531,7 +531,7 @@ again: | |||
531 | return ret; | 531 | return ret; |
532 | 532 | ||
533 | bp = call->buffer; | 533 | bp = call->buffer; |
534 | call->count2 = htonl(*bp++); | 534 | call->count2 = ntohl(*bp++); |
535 | call->offset = 0; | 535 | call->offset = 0; |
536 | call->unmarshall = 4; | 536 | call->unmarshall = 4; |
537 | 537 | ||
@@ -545,7 +545,7 @@ again: | |||
545 | size = sizeof(__be32) * (1 + 4 + 1); | 545 | size = sizeof(__be32) * (1 + 4 + 1); |
546 | break; | 546 | break; |
547 | default: | 547 | default: |
548 | return -EBADMSG; | 548 | return afs_protocol_error(call, -EBADMSG); |
549 | } | 549 | } |
550 | 550 | ||
551 | if (call->count > 1) | 551 | if (call->count > 1) |
@@ -558,16 +558,16 @@ again: | |||
558 | switch (call->count2) { | 558 | switch (call->count2) { |
559 | case YFS_ENDPOINT_IPV4: | 559 | case YFS_ENDPOINT_IPV4: |
560 | if (ntohl(bp[0]) != sizeof(__be32) * 2) | 560 | if (ntohl(bp[0]) != sizeof(__be32) * 2) |
561 | return -EBADMSG; | 561 | return afs_protocol_error(call, -EBADMSG); |
562 | bp += 3; | 562 | bp += 3; |
563 | break; | 563 | break; |
564 | case YFS_ENDPOINT_IPV6: | 564 | case YFS_ENDPOINT_IPV6: |
565 | if (ntohl(bp[0]) != sizeof(__be32) * 5) | 565 | if (ntohl(bp[0]) != sizeof(__be32) * 5) |
566 | return -EBADMSG; | 566 | return afs_protocol_error(call, -EBADMSG); |
567 | bp += 6; | 567 | bp += 6; |
568 | break; | 568 | break; |
569 | default: | 569 | default: |
570 | return -EBADMSG; | 570 | return afs_protocol_error(call, -EBADMSG); |
571 | } | 571 | } |
572 | 572 | ||
573 | /* Got either the type of the next entry or the count of | 573 | /* Got either the type of the next entry or the count of |
@@ -576,7 +576,7 @@ again: | |||
576 | call->offset = 0; | 576 | call->offset = 0; |
577 | call->count--; | 577 | call->count--; |
578 | if (call->count > 0) { | 578 | if (call->count > 0) { |
579 | call->count2 = htonl(*bp++); | 579 | call->count2 = ntohl(*bp++); |
580 | goto again; | 580 | goto again; |
581 | } | 581 | } |
582 | 582 | ||
diff --git a/fs/afs/write.c b/fs/afs/write.c index dbc3c0b0142d..c164698dc304 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c | |||
@@ -42,10 +42,11 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key, | |||
42 | if (!req) | 42 | if (!req) |
43 | return -ENOMEM; | 43 | return -ENOMEM; |
44 | 44 | ||
45 | atomic_set(&req->usage, 1); | 45 | refcount_set(&req->usage, 1); |
46 | req->pos = pos; | 46 | req->pos = pos; |
47 | req->len = len; | 47 | req->len = len; |
48 | req->nr_pages = 1; | 48 | req->nr_pages = 1; |
49 | req->pages = req->array; | ||
49 | req->pages[0] = page; | 50 | req->pages[0] = page; |
50 | get_page(page); | 51 | get_page(page); |
51 | 52 | ||
@@ -124,7 +125,12 @@ try_again: | |||
124 | page->index, priv); | 125 | page->index, priv); |
125 | goto flush_conflicting_write; | 126 | goto flush_conflicting_write; |
126 | } | 127 | } |
127 | if (to < f || from > t) | 128 | /* If the file is being filled locally, allow inter-write |
129 | * spaces to be merged into writes. If it's not, only write | ||
130 | * back what the user gives us. | ||
131 | */ | ||
132 | if (!test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags) && | ||
133 | (to < f || from > t)) | ||
128 | goto flush_conflicting_write; | 134 | goto flush_conflicting_write; |
129 | if (from < f) | 135 | if (from < f) |
130 | f = from; | 136 | f = from; |
@@ -355,6 +361,12 @@ found_key: | |||
355 | } | 361 | } |
356 | 362 | ||
357 | switch (ret) { | 363 | switch (ret) { |
364 | case 0: | ||
365 | afs_stat_v(vnode, n_stores); | ||
366 | atomic_long_add((last * PAGE_SIZE + to) - | ||
367 | (first * PAGE_SIZE + offset), | ||
368 | &afs_v2net(vnode)->n_store_bytes); | ||
369 | break; | ||
358 | case -EACCES: | 370 | case -EACCES: |
359 | case -EPERM: | 371 | case -EPERM: |
360 | case -ENOKEY: | 372 | case -ENOKEY: |
@@ -412,7 +424,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, | |||
412 | trace_afs_page_dirty(vnode, tracepoint_string("WARN"), | 424 | trace_afs_page_dirty(vnode, tracepoint_string("WARN"), |
413 | primary_page->index, priv); | 425 | primary_page->index, priv); |
414 | 426 | ||
415 | if (start >= final_page || to < PAGE_SIZE) | 427 | if (start >= final_page || |
428 | (to < PAGE_SIZE && !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags))) | ||
416 | goto no_more; | 429 | goto no_more; |
417 | 430 | ||
418 | start++; | 431 | start++; |
@@ -433,9 +446,10 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, | |||
433 | } | 446 | } |
434 | 447 | ||
435 | for (loop = 0; loop < n; loop++) { | 448 | for (loop = 0; loop < n; loop++) { |
436 | if (to != PAGE_SIZE) | ||
437 | break; | ||
438 | page = pages[loop]; | 449 | page = pages[loop]; |
450 | if (to != PAGE_SIZE && | ||
451 | !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags)) | ||
452 | break; | ||
439 | if (page->index > final_page) | 453 | if (page->index > final_page) |
440 | break; | 454 | break; |
441 | if (!trylock_page(page)) | 455 | if (!trylock_page(page)) |
@@ -448,7 +462,8 @@ static int afs_write_back_from_locked_page(struct address_space *mapping, | |||
448 | priv = page_private(page); | 462 | priv = page_private(page); |
449 | f = priv & AFS_PRIV_MAX; | 463 | f = priv & AFS_PRIV_MAX; |
450 | t = priv >> AFS_PRIV_SHIFT; | 464 | t = priv >> AFS_PRIV_SHIFT; |
451 | if (f != 0) { | 465 | if (f != 0 && |
466 | !test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags)) { | ||
452 | unlock_page(page); | 467 | unlock_page(page); |
453 | break; | 468 | break; |
454 | } | 469 | } |
@@ -735,20 +750,6 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) | |||
735 | } | 750 | } |
736 | 751 | ||
737 | /* | 752 | /* |
738 | * Flush out all outstanding writes on a file opened for writing when it is | ||
739 | * closed. | ||
740 | */ | ||
741 | int afs_flush(struct file *file, fl_owner_t id) | ||
742 | { | ||
743 | _enter(""); | ||
744 | |||
745 | if ((file->f_mode & FMODE_WRITE) == 0) | ||
746 | return 0; | ||
747 | |||
748 | return vfs_fsync(file, 0); | ||
749 | } | ||
750 | |||
751 | /* | ||
752 | * notification that a previously read-only page is about to become writable | 753 | * notification that a previously read-only page is about to become writable |
753 | * - if it returns an error, the caller will deliver a bus error signal | 754 | * - if it returns an error, the caller will deliver a bus error signal |
754 | */ | 755 | */ |
diff --git a/fs/afs/xdr_fs.h b/fs/afs/xdr_fs.h new file mode 100644 index 000000000000..aa21f3068d52 --- /dev/null +++ b/fs/afs/xdr_fs.h | |||
@@ -0,0 +1,103 @@ | |||
1 | /* AFS fileserver XDR types | ||
2 | * | ||
3 | * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef XDR_FS_H | ||
13 | #define XDR_FS_H | ||
14 | |||
15 | struct afs_xdr_AFSFetchStatus { | ||
16 | __be32 if_version; | ||
17 | #define AFS_FSTATUS_VERSION 1 | ||
18 | __be32 type; | ||
19 | __be32 nlink; | ||
20 | __be32 size_lo; | ||
21 | __be32 data_version_lo; | ||
22 | __be32 author; | ||
23 | __be32 owner; | ||
24 | __be32 caller_access; | ||
25 | __be32 anon_access; | ||
26 | __be32 mode; | ||
27 | __be32 parent_vnode; | ||
28 | __be32 parent_unique; | ||
29 | __be32 seg_size; | ||
30 | __be32 mtime_client; | ||
31 | __be32 mtime_server; | ||
32 | __be32 group; | ||
33 | __be32 sync_counter; | ||
34 | __be32 data_version_hi; | ||
35 | __be32 lock_count; | ||
36 | __be32 size_hi; | ||
37 | __be32 abort_code; | ||
38 | } __packed; | ||
39 | |||
40 | #define AFS_DIR_HASHTBL_SIZE 128 | ||
41 | #define AFS_DIR_DIRENT_SIZE 32 | ||
42 | #define AFS_DIR_SLOTS_PER_BLOCK 64 | ||
43 | #define AFS_DIR_BLOCK_SIZE 2048 | ||
44 | #define AFS_DIR_BLOCKS_PER_PAGE (PAGE_SIZE / AFS_DIR_BLOCK_SIZE) | ||
45 | #define AFS_DIR_MAX_SLOTS 65536 | ||
46 | #define AFS_DIR_BLOCKS_WITH_CTR 128 | ||
47 | #define AFS_DIR_MAX_BLOCKS 1023 | ||
48 | #define AFS_DIR_RESV_BLOCKS 1 | ||
49 | #define AFS_DIR_RESV_BLOCKS0 13 | ||
50 | |||
51 | /* | ||
52 | * Directory entry structure. | ||
53 | */ | ||
54 | union afs_xdr_dirent { | ||
55 | struct { | ||
56 | u8 valid; | ||
57 | u8 unused[1]; | ||
58 | __be16 hash_next; | ||
59 | __be32 vnode; | ||
60 | __be32 unique; | ||
61 | u8 name[16]; | ||
62 | u8 overflow[4]; /* if any char of the name (inc | ||
63 | * NUL) reaches here, consume | ||
64 | * the next dirent too */ | ||
65 | } u; | ||
66 | u8 extended_name[32]; | ||
67 | } __packed; | ||
68 | |||
69 | /* | ||
70 | * Directory block header (one at the beginning of every 2048-byte block). | ||
71 | */ | ||
72 | struct afs_xdr_dir_hdr { | ||
73 | __be16 npages; | ||
74 | __be16 magic; | ||
75 | #define AFS_DIR_MAGIC htons(1234) | ||
76 | u8 reserved; | ||
77 | u8 bitmap[8]; | ||
78 | u8 pad[19]; | ||
79 | } __packed; | ||
80 | |||
81 | /* | ||
82 | * Directory block layout | ||
83 | */ | ||
84 | union afs_xdr_dir_block { | ||
85 | struct afs_xdr_dir_hdr hdr; | ||
86 | |||
87 | struct { | ||
88 | struct afs_xdr_dir_hdr hdr; | ||
89 | u8 alloc_ctrs[AFS_DIR_MAX_BLOCKS]; | ||
90 | __be16 hashtable[AFS_DIR_HASHTBL_SIZE]; | ||
91 | } meta; | ||
92 | |||
93 | union afs_xdr_dirent dirents[AFS_DIR_SLOTS_PER_BLOCK]; | ||
94 | } __packed; | ||
95 | |||
96 | /* | ||
97 | * Directory layout on a linux VM page. | ||
98 | */ | ||
99 | struct afs_xdr_dir_page { | ||
100 | union afs_xdr_dir_block blocks[AFS_DIR_BLOCKS_PER_PAGE]; | ||
101 | }; | ||
102 | |||
103 | #endif /* XDR_FS_H */ | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index 92efaf1f8977..5d93995743b5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1667,7 +1667,7 @@ typedef int (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64, | |||
1667 | unsigned); | 1667 | unsigned); |
1668 | 1668 | ||
1669 | struct dir_context { | 1669 | struct dir_context { |
1670 | const filldir_t actor; | 1670 | filldir_t actor; |
1671 | loff_t pos; | 1671 | loff_t pos; |
1672 | }; | 1672 | }; |
1673 | 1673 | ||
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 63815f66b274..f0820554caa9 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h | |||
@@ -49,6 +49,7 @@ enum afs_fs_operation { | |||
49 | afs_FS_ExtendLock = 157, /* AFS Extend a file lock */ | 49 | afs_FS_ExtendLock = 157, /* AFS Extend a file lock */ |
50 | afs_FS_ReleaseLock = 158, /* AFS Release a file lock */ | 50 | afs_FS_ReleaseLock = 158, /* AFS Release a file lock */ |
51 | afs_FS_Lookup = 161, /* AFS lookup file in directory */ | 51 | afs_FS_Lookup = 161, /* AFS lookup file in directory */ |
52 | afs_FS_InlineBulkStatus = 65536, /* AFS Fetch multiple file statuses with errors */ | ||
52 | afs_FS_FetchData64 = 65537, /* AFS Fetch file data */ | 53 | afs_FS_FetchData64 = 65537, /* AFS Fetch file data */ |
53 | afs_FS_StoreData64 = 65538, /* AFS Store file data */ | 54 | afs_FS_StoreData64 = 65538, /* AFS Store file data */ |
54 | afs_FS_GiveUpAllCallBacks = 65539, /* AFS Give up all our callbacks on a server */ | 55 | afs_FS_GiveUpAllCallBacks = 65539, /* AFS Give up all our callbacks on a server */ |
@@ -62,6 +63,27 @@ enum afs_vl_operation { | |||
62 | afs_VL_GetCapabilities = 65537, /* AFS Get VL server capabilities */ | 63 | afs_VL_GetCapabilities = 65537, /* AFS Get VL server capabilities */ |
63 | }; | 64 | }; |
64 | 65 | ||
66 | enum afs_edit_dir_op { | ||
67 | afs_edit_dir_create, | ||
68 | afs_edit_dir_create_error, | ||
69 | afs_edit_dir_create_inval, | ||
70 | afs_edit_dir_create_nospc, | ||
71 | afs_edit_dir_delete, | ||
72 | afs_edit_dir_delete_error, | ||
73 | afs_edit_dir_delete_inval, | ||
74 | afs_edit_dir_delete_noent, | ||
75 | }; | ||
76 | |||
77 | enum afs_edit_dir_reason { | ||
78 | afs_edit_dir_for_create, | ||
79 | afs_edit_dir_for_link, | ||
80 | afs_edit_dir_for_mkdir, | ||
81 | afs_edit_dir_for_rename, | ||
82 | afs_edit_dir_for_rmdir, | ||
83 | afs_edit_dir_for_symlink, | ||
84 | afs_edit_dir_for_unlink, | ||
85 | }; | ||
86 | |||
65 | #endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */ | 87 | #endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */ |
66 | 88 | ||
67 | /* | 89 | /* |
@@ -93,6 +115,7 @@ enum afs_vl_operation { | |||
93 | EM(afs_FS_ExtendLock, "FS.ExtendLock") \ | 115 | EM(afs_FS_ExtendLock, "FS.ExtendLock") \ |
94 | EM(afs_FS_ReleaseLock, "FS.ReleaseLock") \ | 116 | EM(afs_FS_ReleaseLock, "FS.ReleaseLock") \ |
95 | EM(afs_FS_Lookup, "FS.Lookup") \ | 117 | EM(afs_FS_Lookup, "FS.Lookup") \ |
118 | EM(afs_FS_InlineBulkStatus, "FS.InlineBulkStatus") \ | ||
96 | EM(afs_FS_FetchData64, "FS.FetchData64") \ | 119 | EM(afs_FS_FetchData64, "FS.FetchData64") \ |
97 | EM(afs_FS_StoreData64, "FS.StoreData64") \ | 120 | EM(afs_FS_StoreData64, "FS.StoreData64") \ |
98 | EM(afs_FS_GiveUpAllCallBacks, "FS.GiveUpAllCallBacks") \ | 121 | EM(afs_FS_GiveUpAllCallBacks, "FS.GiveUpAllCallBacks") \ |
@@ -104,6 +127,25 @@ enum afs_vl_operation { | |||
104 | EM(afs_YFSVL_GetEndpoints, "YFSVL.GetEndpoints") \ | 127 | EM(afs_YFSVL_GetEndpoints, "YFSVL.GetEndpoints") \ |
105 | E_(afs_VL_GetCapabilities, "VL.GetCapabilities") | 128 | E_(afs_VL_GetCapabilities, "VL.GetCapabilities") |
106 | 129 | ||
130 | #define afs_edit_dir_ops \ | ||
131 | EM(afs_edit_dir_create, "create") \ | ||
132 | EM(afs_edit_dir_create_error, "c_fail") \ | ||
133 | EM(afs_edit_dir_create_inval, "c_invl") \ | ||
134 | EM(afs_edit_dir_create_nospc, "c_nspc") \ | ||
135 | EM(afs_edit_dir_delete, "delete") \ | ||
136 | EM(afs_edit_dir_delete_error, "d_err ") \ | ||
137 | EM(afs_edit_dir_delete_inval, "d_invl") \ | ||
138 | E_(afs_edit_dir_delete_noent, "d_nent") | ||
139 | |||
140 | #define afs_edit_dir_reasons \ | ||
141 | EM(afs_edit_dir_for_create, "Create") \ | ||
142 | EM(afs_edit_dir_for_link, "Link ") \ | ||
143 | EM(afs_edit_dir_for_mkdir, "MkDir ") \ | ||
144 | EM(afs_edit_dir_for_rename, "Rename") \ | ||
145 | EM(afs_edit_dir_for_rmdir, "RmDir ") \ | ||
146 | EM(afs_edit_dir_for_symlink, "Symlnk") \ | ||
147 | E_(afs_edit_dir_for_unlink, "Unlink") | ||
148 | |||
107 | 149 | ||
108 | /* | 150 | /* |
109 | * Export enum symbols via userspace. | 151 | * Export enum symbols via userspace. |
@@ -116,6 +158,8 @@ enum afs_vl_operation { | |||
116 | afs_call_traces; | 158 | afs_call_traces; |
117 | afs_fs_operations; | 159 | afs_fs_operations; |
118 | afs_vl_operations; | 160 | afs_vl_operations; |
161 | afs_edit_dir_ops; | ||
162 | afs_edit_dir_reasons; | ||
119 | 163 | ||
120 | /* | 164 | /* |
121 | * Now redefine the EM() and E_() macros to map the enums to the strings that | 165 | * Now redefine the EM() and E_() macros to map the enums to the strings that |
@@ -462,6 +506,75 @@ TRACE_EVENT(afs_call_state, | |||
462 | __entry->ret, __entry->abort) | 506 | __entry->ret, __entry->abort) |
463 | ); | 507 | ); |
464 | 508 | ||
509 | TRACE_EVENT(afs_edit_dir, | ||
510 | TP_PROTO(struct afs_vnode *dvnode, | ||
511 | enum afs_edit_dir_reason why, | ||
512 | enum afs_edit_dir_op op, | ||
513 | unsigned int block, | ||
514 | unsigned int slot, | ||
515 | unsigned int f_vnode, | ||
516 | unsigned int f_unique, | ||
517 | const char *name), | ||
518 | |||
519 | TP_ARGS(dvnode, why, op, block, slot, f_vnode, f_unique, name), | ||
520 | |||
521 | TP_STRUCT__entry( | ||
522 | __field(unsigned int, vnode ) | ||
523 | __field(unsigned int, unique ) | ||
524 | __field(enum afs_edit_dir_reason, why ) | ||
525 | __field(enum afs_edit_dir_op, op ) | ||
526 | __field(unsigned int, block ) | ||
527 | __field(unsigned short, slot ) | ||
528 | __field(unsigned int, f_vnode ) | ||
529 | __field(unsigned int, f_unique ) | ||
530 | __array(char, name, 18 ) | ||
531 | ), | ||
532 | |||
533 | TP_fast_assign( | ||
534 | int __len = strlen(name); | ||
535 | __len = min(__len, 17); | ||
536 | __entry->vnode = dvnode->fid.vnode; | ||
537 | __entry->unique = dvnode->fid.unique; | ||
538 | __entry->why = why; | ||
539 | __entry->op = op; | ||
540 | __entry->block = block; | ||
541 | __entry->slot = slot; | ||
542 | __entry->f_vnode = f_vnode; | ||
543 | __entry->f_unique = f_unique; | ||
544 | memcpy(__entry->name, name, __len); | ||
545 | __entry->name[__len] = 0; | ||
546 | ), | ||
547 | |||
548 | TP_printk("d=%x:%x %s %s %u[%u] f=%x:%x %s", | ||
549 | __entry->vnode, __entry->unique, | ||
550 | __print_symbolic(__entry->why, afs_edit_dir_reasons), | ||
551 | __print_symbolic(__entry->op, afs_edit_dir_ops), | ||
552 | __entry->block, __entry->slot, | ||
553 | __entry->f_vnode, __entry->f_unique, | ||
554 | __entry->name) | ||
555 | ); | ||
556 | |||
557 | TRACE_EVENT(afs_protocol_error, | ||
558 | TP_PROTO(struct afs_call *call, int error, const void *where), | ||
559 | |||
560 | TP_ARGS(call, error, where), | ||
561 | |||
562 | TP_STRUCT__entry( | ||
563 | __field(unsigned int, call ) | ||
564 | __field(int, error ) | ||
565 | __field(const void *, where ) | ||
566 | ), | ||
567 | |||
568 | TP_fast_assign( | ||
569 | __entry->call = call ? call->debug_id : 0; | ||
570 | __entry->error = error; | ||
571 | __entry->where = where; | ||
572 | ), | ||
573 | |||
574 | TP_printk("c=%08x r=%d sp=%pSR", | ||
575 | __entry->call, __entry->error, __entry->where) | ||
576 | ); | ||
577 | |||
465 | #endif /* _TRACE_AFS_H */ | 578 | #endif /* _TRACE_AFS_H */ |
466 | 579 | ||
467 | /* This part must be outside protection */ | 580 | /* This part must be outside protection */ |