Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[linux-block.git] / fs / sysv / dir.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  linux/fs/sysv/dir.c
4  *
5  *  minix/dir.c
6  *  Copyright (C) 1991, 1992  Linus Torvalds
7  *
8  *  coh/dir.c
9  *  Copyright (C) 1993  Pascal Haible, Bruno Haible
10  *
11  *  sysv/dir.c
12  *  Copyright (C) 1993  Bruno Haible
13  *
14  *  SystemV/Coherent directory handling functions
15  */
16
17 #include <linux/pagemap.h>
18 #include <linux/highmem.h>
19 #include <linux/swap.h>
20 #include "sysv.h"
21
22 static int sysv_readdir(struct file *, struct dir_context *);
23
24 const struct file_operations sysv_dir_operations = {
25         .llseek         = generic_file_llseek,
26         .read           = generic_read_dir,
27         .iterate_shared = sysv_readdir,
28         .fsync          = generic_file_fsync,
29 };
30
31 static void dir_commit_chunk(struct folio *folio, loff_t pos, unsigned len)
32 {
33         struct address_space *mapping = folio->mapping;
34         struct inode *dir = mapping->host;
35
36         block_write_end(NULL, mapping, pos, len, len, folio, NULL);
37         if (pos+len > dir->i_size) {
38                 i_size_write(dir, pos+len);
39                 mark_inode_dirty(dir);
40         }
41         folio_unlock(folio);
42 }
43
44 static int sysv_handle_dirsync(struct inode *dir)
45 {
46         int err;
47
48         err = filemap_write_and_wait(dir->i_mapping);
49         if (!err)
50                 err = sync_inode_metadata(dir, 1);
51         return err;
52 }
53
54 /*
55  * Calls to dir_get_folio()/folio_release_kmap() must be nested according to the
56  * rules documented in mm/highmem.rst.
57  *
58  * NOTE: sysv_find_entry() and sysv_dotdot() act as calls to dir_get_folio()
59  * and must be treated accordingly for nesting purposes.
60  */
61 static void *dir_get_folio(struct inode *dir, unsigned long n,
62                 struct folio **foliop)
63 {
64         struct folio *folio = read_mapping_folio(dir->i_mapping, n, NULL);
65
66         if (IS_ERR(folio))
67                 return ERR_CAST(folio);
68         *foliop = folio;
69         return kmap_local_folio(folio, 0);
70 }
71
72 static int sysv_readdir(struct file *file, struct dir_context *ctx)
73 {
74         unsigned long pos = ctx->pos;
75         struct inode *inode = file_inode(file);
76         struct super_block *sb = inode->i_sb;
77         unsigned long npages = dir_pages(inode);
78         unsigned offset;
79         unsigned long n;
80
81         ctx->pos = pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1);
82         if (pos >= inode->i_size)
83                 return 0;
84
85         offset = pos & ~PAGE_MASK;
86         n = pos >> PAGE_SHIFT;
87
88         for ( ; n < npages; n++, offset = 0) {
89                 char *kaddr, *limit;
90                 struct sysv_dir_entry *de;
91                 struct folio *folio;
92
93                 kaddr = dir_get_folio(inode, n, &folio);
94                 if (IS_ERR(kaddr))
95                         continue;
96                 de = (struct sysv_dir_entry *)(kaddr+offset);
97                 limit = kaddr + PAGE_SIZE - SYSV_DIRSIZE;
98                 for ( ;(char*)de <= limit; de++, ctx->pos += sizeof(*de)) {
99                         char *name = de->name;
100
101                         if (!de->inode)
102                                 continue;
103
104                         if (!dir_emit(ctx, name, strnlen(name,SYSV_NAMELEN),
105                                         fs16_to_cpu(SYSV_SB(sb), de->inode),
106                                         DT_UNKNOWN)) {
107                                 folio_release_kmap(folio, kaddr);
108                                 return 0;
109                         }
110                 }
111                 folio_release_kmap(folio, kaddr);
112         }
113         return 0;
114 }
115
116 /* compare strings: name[0..len-1] (not zero-terminated) and
117  * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1])
118  */
119 static inline int namecompare(int len, int maxlen,
120         const char * name, const char * buffer)
121 {
122         if (len < maxlen && buffer[len])
123                 return 0;
124         return !memcmp(name, buffer, len);
125 }
126
127 /*
128  *      sysv_find_entry()
129  *
130  * finds an entry in the specified directory with the wanted name.
131  * It does NOT read the inode of the
132  * entry - you'll have to do that yourself if you want to.
133  *
134  * On Success folio_release_kmap() should be called on *foliop.
135  *
136  * sysv_find_entry() acts as a call to dir_get_folio() and must be treated
137  * accordingly for nesting purposes.
138  */
139 struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct folio **foliop)
140 {
141         const char * name = dentry->d_name.name;
142         int namelen = dentry->d_name.len;
143         struct inode * dir = d_inode(dentry->d_parent);
144         unsigned long start, n;
145         unsigned long npages = dir_pages(dir);
146         struct sysv_dir_entry *de;
147
148         start = SYSV_I(dir)->i_dir_start_lookup;
149         if (start >= npages)
150                 start = 0;
151         n = start;
152
153         do {
154                 char *kaddr = dir_get_folio(dir, n, foliop);
155
156                 if (!IS_ERR(kaddr)) {
157                         de = (struct sysv_dir_entry *)kaddr;
158                         kaddr += folio_size(*foliop) - SYSV_DIRSIZE;
159                         for ( ; (char *) de <= kaddr ; de++) {
160                                 if (!de->inode)
161                                         continue;
162                                 if (namecompare(namelen, SYSV_NAMELEN,
163                                                         name, de->name))
164                                         goto found;
165                         }
166                         folio_release_kmap(*foliop, kaddr);
167                 }
168
169                 if (++n >= npages)
170                         n = 0;
171         } while (n != start);
172
173         return NULL;
174
175 found:
176         SYSV_I(dir)->i_dir_start_lookup = n;
177         return de;
178 }
179
180 int sysv_add_link(struct dentry *dentry, struct inode *inode)
181 {
182         struct inode *dir = d_inode(dentry->d_parent);
183         const char * name = dentry->d_name.name;
184         int namelen = dentry->d_name.len;
185         struct folio *folio = NULL;
186         struct sysv_dir_entry * de;
187         unsigned long npages = dir_pages(dir);
188         unsigned long n;
189         char *kaddr;
190         loff_t pos;
191         int err;
192
193         /* We take care of directory expansion in the same loop */
194         for (n = 0; n <= npages; n++) {
195                 kaddr = dir_get_folio(dir, n, &folio);
196                 if (IS_ERR(kaddr))
197                         return PTR_ERR(kaddr);
198                 de = (struct sysv_dir_entry *)kaddr;
199                 kaddr += PAGE_SIZE - SYSV_DIRSIZE;
200                 while ((char *)de <= kaddr) {
201                         if (!de->inode)
202                                 goto got_it;
203                         err = -EEXIST;
204                         if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) 
205                                 goto out_folio;
206                         de++;
207                 }
208                 folio_release_kmap(folio, kaddr);
209         }
210         BUG();
211         return -EINVAL;
212
213 got_it:
214         pos = folio_pos(folio) + offset_in_folio(folio, de);
215         folio_lock(folio);
216         err = sysv_prepare_chunk(folio, pos, SYSV_DIRSIZE);
217         if (err)
218                 goto out_unlock;
219         memcpy (de->name, name, namelen);
220         memset (de->name + namelen, 0, SYSV_DIRSIZE - namelen - 2);
221         de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
222         dir_commit_chunk(folio, pos, SYSV_DIRSIZE);
223         inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
224         mark_inode_dirty(dir);
225         err = sysv_handle_dirsync(dir);
226 out_folio:
227         folio_release_kmap(folio, kaddr);
228         return err;
229 out_unlock:
230         folio_unlock(folio);
231         goto out_folio;
232 }
233
234 int sysv_delete_entry(struct sysv_dir_entry *de, struct folio *folio)
235 {
236         struct inode *inode = folio->mapping->host;
237         loff_t pos = folio_pos(folio) + offset_in_folio(folio, de);
238         int err;
239
240         folio_lock(folio);
241         err = sysv_prepare_chunk(folio, pos, SYSV_DIRSIZE);
242         if (err) {
243                 folio_unlock(folio);
244                 return err;
245         }
246         de->inode = 0;
247         dir_commit_chunk(folio, pos, SYSV_DIRSIZE);
248         inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
249         mark_inode_dirty(inode);
250         return sysv_handle_dirsync(inode);
251 }
252
253 int sysv_make_empty(struct inode *inode, struct inode *dir)
254 {
255         struct folio *folio = filemap_grab_folio(inode->i_mapping, 0);
256         struct sysv_dir_entry * de;
257         char *kaddr;
258         int err;
259
260         if (IS_ERR(folio))
261                 return PTR_ERR(folio);
262         err = sysv_prepare_chunk(folio, 0, 2 * SYSV_DIRSIZE);
263         if (err) {
264                 folio_unlock(folio);
265                 goto fail;
266         }
267         kaddr = kmap_local_folio(folio, 0);
268         memset(kaddr, 0, folio_size(folio));
269
270         de = (struct sysv_dir_entry *)kaddr;
271         de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
272         strcpy(de->name,".");
273         de++;
274         de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), dir->i_ino);
275         strcpy(de->name,"..");
276
277         kunmap_local(kaddr);
278         dir_commit_chunk(folio, 0, 2 * SYSV_DIRSIZE);
279         err = sysv_handle_dirsync(inode);
280 fail:
281         folio_put(folio);
282         return err;
283 }
284
285 /*
286  * routine to check that the specified directory is empty (for rmdir)
287  */
288 int sysv_empty_dir(struct inode * inode)
289 {
290         struct super_block *sb = inode->i_sb;
291         struct folio *folio = NULL;
292         unsigned long i, npages = dir_pages(inode);
293         char *kaddr;
294
295         for (i = 0; i < npages; i++) {
296                 struct sysv_dir_entry *de;
297
298                 kaddr = dir_get_folio(inode, i, &folio);
299                 if (IS_ERR(kaddr))
300                         continue;
301
302                 de = (struct sysv_dir_entry *)kaddr;
303                 kaddr += folio_size(folio) - SYSV_DIRSIZE;
304
305                 for ( ;(char *)de <= kaddr; de++) {
306                         if (!de->inode)
307                                 continue;
308                         /* check for . and .. */
309                         if (de->name[0] != '.')
310                                 goto not_empty;
311                         if (!de->name[1]) {
312                                 if (de->inode == cpu_to_fs16(SYSV_SB(sb),
313                                                         inode->i_ino))
314                                         continue;
315                                 goto not_empty;
316                         }
317                         if (de->name[1] != '.' || de->name[2])
318                                 goto not_empty;
319                 }
320                 folio_release_kmap(folio, kaddr);
321         }
322         return 1;
323
324 not_empty:
325         folio_release_kmap(folio, kaddr);
326         return 0;
327 }
328
329 /* Releases the page */
330 int sysv_set_link(struct sysv_dir_entry *de, struct folio *folio,
331                 struct inode *inode)
332 {
333         struct inode *dir = folio->mapping->host;
334         loff_t pos = folio_pos(folio) + offset_in_folio(folio, de);
335         int err;
336
337         folio_lock(folio);
338         err = sysv_prepare_chunk(folio, pos, SYSV_DIRSIZE);
339         if (err) {
340                 folio_unlock(folio);
341                 return err;
342         }
343         de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
344         dir_commit_chunk(folio, pos, SYSV_DIRSIZE);
345         inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
346         mark_inode_dirty(dir);
347         return sysv_handle_dirsync(inode);
348 }
349
350 /*
351  * Calls to dir_get_folio()/folio_release_kmap() must be nested according to the
352  * rules documented in mm/highmem.rst.
353  *
354  * sysv_dotdot() acts as a call to dir_get_folio() and must be treated
355  * accordingly for nesting purposes.
356  */
357 struct sysv_dir_entry *sysv_dotdot(struct inode *dir, struct folio **foliop)
358 {
359         struct sysv_dir_entry *de = dir_get_folio(dir, 0, foliop);
360
361         if (IS_ERR(de))
362                 return NULL;
363         /* ".." is the second directory entry */
364         return de + 1;
365 }
366
367 ino_t sysv_inode_by_name(struct dentry *dentry)
368 {
369         struct folio *folio;
370         struct sysv_dir_entry *de = sysv_find_entry (dentry, &folio);
371         ino_t res = 0;
372         
373         if (de) {
374                 res = fs16_to_cpu(SYSV_SB(dentry->d_sb), de->inode);
375                 folio_release_kmap(folio, de);
376         }
377         return res;
378 }