1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/fs/minix/dir.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * minix directory handling functions
8939b00dfSAndries Brouwer *
9939b00dfSAndries Brouwer * Updated to filesystem version 3 by Daniel Aragones
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds #include "minix.h"
134a66af9eSNick Piggin #include <linux/buffer_head.h>
141da177e4SLinus Torvalds #include <linux/highmem.h>
154a66af9eSNick Piggin #include <linux/swap.h>
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds typedef struct minix_dir_entry minix_dirent;
18939b00dfSAndries Brouwer typedef struct minix3_dir_entry minix3_dirent;
191da177e4SLinus Torvalds
2080886298SAl Viro static int minix_readdir(struct file *, struct dir_context *);
211da177e4SLinus Torvalds
224b6f5d20SArjan van de Ven const struct file_operations minix_dir_operations = {
23cc46759aSAl Viro .llseek = generic_file_llseek,
241da177e4SLinus Torvalds .read = generic_read_dir,
253b0a3c1aSAl Viro .iterate_shared = minix_readdir,
261b061d92SChristoph Hellwig .fsync = generic_file_fsync,
271da177e4SLinus Torvalds };
281da177e4SLinus Torvalds
dir_put_page(struct page * page)291da177e4SLinus Torvalds static inline void dir_put_page(struct page *page)
301da177e4SLinus Torvalds {
311da177e4SLinus Torvalds kunmap(page);
3209cbfeafSKirill A. Shutemov put_page(page);
331da177e4SLinus Torvalds }
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds /*
361da177e4SLinus Torvalds * Return the offset into page `page_nr' of the last valid
371da177e4SLinus Torvalds * byte in that page, plus one.
381da177e4SLinus Torvalds */
391da177e4SLinus Torvalds static unsigned
minix_last_byte(struct inode * inode,unsigned long page_nr)401da177e4SLinus Torvalds minix_last_byte(struct inode *inode, unsigned long page_nr)
411da177e4SLinus Torvalds {
4209cbfeafSKirill A. Shutemov unsigned last_byte = PAGE_SIZE;
431da177e4SLinus Torvalds
4409cbfeafSKirill A. Shutemov if (page_nr == (inode->i_size >> PAGE_SHIFT))
4509cbfeafSKirill A. Shutemov last_byte = inode->i_size & (PAGE_SIZE - 1);
461da177e4SLinus Torvalds return last_byte;
471da177e4SLinus Torvalds }
481da177e4SLinus Torvalds
dir_commit_chunk(struct page * page,loff_t pos,unsigned len)49f556e776SChristoph Hellwig static void dir_commit_chunk(struct page *page, loff_t pos, unsigned len)
501da177e4SLinus Torvalds {
514a66af9eSNick Piggin struct address_space *mapping = page->mapping;
524a66af9eSNick Piggin struct inode *dir = mapping->host;
53f556e776SChristoph Hellwig
544a66af9eSNick Piggin block_write_end(NULL, mapping, pos, len, len, page, NULL);
554a66af9eSNick Piggin
564a66af9eSNick Piggin if (pos+len > dir->i_size) {
574a66af9eSNick Piggin i_size_write(dir, pos+len);
584a66af9eSNick Piggin mark_inode_dirty(dir);
594a66af9eSNick Piggin }
601da177e4SLinus Torvalds unlock_page(page);
61f556e776SChristoph Hellwig }
62f556e776SChristoph Hellwig
minix_handle_dirsync(struct inode * dir)63f556e776SChristoph Hellwig static int minix_handle_dirsync(struct inode *dir)
64f556e776SChristoph Hellwig {
65f556e776SChristoph Hellwig int err;
66f556e776SChristoph Hellwig
67f556e776SChristoph Hellwig err = filemap_write_and_wait(dir->i_mapping);
68f556e776SChristoph Hellwig if (!err)
69f556e776SChristoph Hellwig err = sync_inode_metadata(dir, 1);
701da177e4SLinus Torvalds return err;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds
dir_get_page(struct inode * dir,unsigned long n)731da177e4SLinus Torvalds static struct page * dir_get_page(struct inode *dir, unsigned long n)
741da177e4SLinus Torvalds {
751da177e4SLinus Torvalds struct address_space *mapping = dir->i_mapping;
76090d2b18SPekka Enberg struct page *page = read_mapping_page(mapping, n, NULL);
7749837a80SAl Viro if (!IS_ERR(page))
781da177e4SLinus Torvalds kmap(page);
791da177e4SLinus Torvalds return page;
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds
minix_next_entry(void * de,struct minix_sb_info * sbi)821da177e4SLinus Torvalds static inline void *minix_next_entry(void *de, struct minix_sb_info *sbi)
831da177e4SLinus Torvalds {
841da177e4SLinus Torvalds return (void*)((char*)de + sbi->s_dirsize);
851da177e4SLinus Torvalds }
861da177e4SLinus Torvalds
minix_readdir(struct file * file,struct dir_context * ctx)8780886298SAl Viro static int minix_readdir(struct file *file, struct dir_context *ctx)
881da177e4SLinus Torvalds {
8980886298SAl Viro struct inode *inode = file_inode(file);
901da177e4SLinus Torvalds struct super_block *sb = inode->i_sb;
911da177e4SLinus Torvalds struct minix_sb_info *sbi = minix_sb(sb);
921da177e4SLinus Torvalds unsigned chunk_size = sbi->s_dirsize;
9380886298SAl Viro unsigned long npages = dir_pages(inode);
9480886298SAl Viro unsigned long pos = ctx->pos;
9580886298SAl Viro unsigned offset;
9680886298SAl Viro unsigned long n;
971da177e4SLinus Torvalds
98642b704cSDan Carpenter ctx->pos = pos = ALIGN(pos, chunk_size);
991da177e4SLinus Torvalds if (pos >= inode->i_size)
10080886298SAl Viro return 0;
10180886298SAl Viro
10209cbfeafSKirill A. Shutemov offset = pos & ~PAGE_MASK;
10309cbfeafSKirill A. Shutemov n = pos >> PAGE_SHIFT;
1041da177e4SLinus Torvalds
1051da177e4SLinus Torvalds for ( ; n < npages; n++, offset = 0) {
1061da177e4SLinus Torvalds char *p, *kaddr, *limit;
1071da177e4SLinus Torvalds struct page *page = dir_get_page(inode, n);
1081da177e4SLinus Torvalds
1091da177e4SLinus Torvalds if (IS_ERR(page))
1101da177e4SLinus Torvalds continue;
1111da177e4SLinus Torvalds kaddr = (char *)page_address(page);
1121da177e4SLinus Torvalds p = kaddr+offset;
1131da177e4SLinus Torvalds limit = kaddr + minix_last_byte(inode, n) - chunk_size;
1141da177e4SLinus Torvalds for ( ; p <= limit; p = minix_next_entry(p, sbi)) {
11580886298SAl Viro const char *name;
11680886298SAl Viro __u32 inumber;
117939b00dfSAndries Brouwer if (sbi->s_version == MINIX_V3) {
118939b00dfSAndries Brouwer minix3_dirent *de3 = (minix3_dirent *)p;
119939b00dfSAndries Brouwer name = de3->name;
120939b00dfSAndries Brouwer inumber = de3->inode;
121939b00dfSAndries Brouwer } else {
1221da177e4SLinus Torvalds minix_dirent *de = (minix_dirent *)p;
123939b00dfSAndries Brouwer name = de->name;
124939b00dfSAndries Brouwer inumber = de->inode;
125939b00dfSAndries Brouwer }
126939b00dfSAndries Brouwer if (inumber) {
127939b00dfSAndries Brouwer unsigned l = strnlen(name, sbi->s_namelen);
12880886298SAl Viro if (!dir_emit(ctx, name, l,
12980886298SAl Viro inumber, DT_UNKNOWN)) {
1301da177e4SLinus Torvalds dir_put_page(page);
13180886298SAl Viro return 0;
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds }
13480886298SAl Viro ctx->pos += chunk_size;
1351da177e4SLinus Torvalds }
1361da177e4SLinus Torvalds dir_put_page(page);
1371da177e4SLinus Torvalds }
1381da177e4SLinus Torvalds return 0;
1391da177e4SLinus Torvalds }
1401da177e4SLinus Torvalds
namecompare(int len,int maxlen,const char * name,const char * buffer)1411da177e4SLinus Torvalds static inline int namecompare(int len, int maxlen,
1421da177e4SLinus Torvalds const char * name, const char * buffer)
1431da177e4SLinus Torvalds {
1441da177e4SLinus Torvalds if (len < maxlen && buffer[len])
1451da177e4SLinus Torvalds return 0;
1461da177e4SLinus Torvalds return !memcmp(name, buffer, len);
1471da177e4SLinus Torvalds }
1481da177e4SLinus Torvalds
1491da177e4SLinus Torvalds /*
1501da177e4SLinus Torvalds * minix_find_entry()
1511da177e4SLinus Torvalds *
1521da177e4SLinus Torvalds * finds an entry in the specified directory with the wanted name. It
1531da177e4SLinus Torvalds * returns the cache buffer in which the entry was found, and the entry
1541da177e4SLinus Torvalds * itself (as a parameter - res_dir). It does NOT read the inode of the
1551da177e4SLinus Torvalds * entry - you'll have to do that yourself if you want to.
1561da177e4SLinus Torvalds */
minix_find_entry(struct dentry * dentry,struct page ** res_page)1571da177e4SLinus Torvalds minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page)
1581da177e4SLinus Torvalds {
1591da177e4SLinus Torvalds const char * name = dentry->d_name.name;
1601da177e4SLinus Torvalds int namelen = dentry->d_name.len;
1612b0143b5SDavid Howells struct inode * dir = d_inode(dentry->d_parent);
1621da177e4SLinus Torvalds struct super_block * sb = dir->i_sb;
1631da177e4SLinus Torvalds struct minix_sb_info * sbi = minix_sb(sb);
1641da177e4SLinus Torvalds unsigned long n;
1651da177e4SLinus Torvalds unsigned long npages = dir_pages(dir);
1661da177e4SLinus Torvalds struct page *page = NULL;
167939b00dfSAndries Brouwer char *p;
1681da177e4SLinus Torvalds
169939b00dfSAndries Brouwer char *namx;
170939b00dfSAndries Brouwer __u32 inumber;
1711da177e4SLinus Torvalds *res_page = NULL;
1721da177e4SLinus Torvalds
1731da177e4SLinus Torvalds for (n = 0; n < npages; n++) {
174939b00dfSAndries Brouwer char *kaddr, *limit;
175939b00dfSAndries Brouwer
1761da177e4SLinus Torvalds page = dir_get_page(dir, n);
1771da177e4SLinus Torvalds if (IS_ERR(page))
1781da177e4SLinus Torvalds continue;
1791da177e4SLinus Torvalds
1801da177e4SLinus Torvalds kaddr = (char*)page_address(page);
181939b00dfSAndries Brouwer limit = kaddr + minix_last_byte(dir, n) - sbi->s_dirsize;
182939b00dfSAndries Brouwer for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) {
183939b00dfSAndries Brouwer if (sbi->s_version == MINIX_V3) {
184939b00dfSAndries Brouwer minix3_dirent *de3 = (minix3_dirent *)p;
185939b00dfSAndries Brouwer namx = de3->name;
186939b00dfSAndries Brouwer inumber = de3->inode;
187939b00dfSAndries Brouwer } else {
188939b00dfSAndries Brouwer minix_dirent *de = (minix_dirent *)p;
189939b00dfSAndries Brouwer namx = de->name;
190939b00dfSAndries Brouwer inumber = de->inode;
191939b00dfSAndries Brouwer }
192939b00dfSAndries Brouwer if (!inumber)
1931da177e4SLinus Torvalds continue;
194939b00dfSAndries Brouwer if (namecompare(namelen, sbi->s_namelen, name, namx))
1951da177e4SLinus Torvalds goto found;
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds dir_put_page(page);
1981da177e4SLinus Torvalds }
1991da177e4SLinus Torvalds return NULL;
2001da177e4SLinus Torvalds
2011da177e4SLinus Torvalds found:
2021da177e4SLinus Torvalds *res_page = page;
203939b00dfSAndries Brouwer return (minix_dirent *)p;
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds
minix_add_link(struct dentry * dentry,struct inode * inode)2061da177e4SLinus Torvalds int minix_add_link(struct dentry *dentry, struct inode *inode)
2071da177e4SLinus Torvalds {
2082b0143b5SDavid Howells struct inode *dir = d_inode(dentry->d_parent);
2091da177e4SLinus Torvalds const char * name = dentry->d_name.name;
2101da177e4SLinus Torvalds int namelen = dentry->d_name.len;
2111da177e4SLinus Torvalds struct super_block * sb = dir->i_sb;
2121da177e4SLinus Torvalds struct minix_sb_info * sbi = minix_sb(sb);
2131da177e4SLinus Torvalds struct page *page = NULL;
2141da177e4SLinus Torvalds unsigned long npages = dir_pages(dir);
2151da177e4SLinus Torvalds unsigned long n;
216939b00dfSAndries Brouwer char *kaddr, *p;
217939b00dfSAndries Brouwer minix_dirent *de;
218939b00dfSAndries Brouwer minix3_dirent *de3;
2194a66af9eSNick Piggin loff_t pos;
2201da177e4SLinus Torvalds int err;
221939b00dfSAndries Brouwer char *namx = NULL;
222939b00dfSAndries Brouwer __u32 inumber;
2231da177e4SLinus Torvalds
2241da177e4SLinus Torvalds /*
2251da177e4SLinus Torvalds * We take care of directory expansion in the same loop
2261da177e4SLinus Torvalds * This code plays outside i_size, so it locks the page
2271da177e4SLinus Torvalds * to protect that region.
2281da177e4SLinus Torvalds */
2291da177e4SLinus Torvalds for (n = 0; n <= npages; n++) {
230939b00dfSAndries Brouwer char *limit, *dir_end;
2311da177e4SLinus Torvalds
2321da177e4SLinus Torvalds page = dir_get_page(dir, n);
2331da177e4SLinus Torvalds err = PTR_ERR(page);
2341da177e4SLinus Torvalds if (IS_ERR(page))
2351da177e4SLinus Torvalds goto out;
2361da177e4SLinus Torvalds lock_page(page);
2371da177e4SLinus Torvalds kaddr = (char*)page_address(page);
2381da177e4SLinus Torvalds dir_end = kaddr + minix_last_byte(dir, n);
23909cbfeafSKirill A. Shutemov limit = kaddr + PAGE_SIZE - sbi->s_dirsize;
240939b00dfSAndries Brouwer for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) {
241939b00dfSAndries Brouwer de = (minix_dirent *)p;
242939b00dfSAndries Brouwer de3 = (minix3_dirent *)p;
243939b00dfSAndries Brouwer if (sbi->s_version == MINIX_V3) {
244939b00dfSAndries Brouwer namx = de3->name;
245939b00dfSAndries Brouwer inumber = de3->inode;
246939b00dfSAndries Brouwer } else {
247939b00dfSAndries Brouwer namx = de->name;
248939b00dfSAndries Brouwer inumber = de->inode;
249939b00dfSAndries Brouwer }
250939b00dfSAndries Brouwer if (p == dir_end) {
2511da177e4SLinus Torvalds /* We hit i_size */
252939b00dfSAndries Brouwer if (sbi->s_version == MINIX_V3)
253939b00dfSAndries Brouwer de3->inode = 0;
254939b00dfSAndries Brouwer else
2551da177e4SLinus Torvalds de->inode = 0;
2561da177e4SLinus Torvalds goto got_it;
2571da177e4SLinus Torvalds }
258939b00dfSAndries Brouwer if (!inumber)
2591da177e4SLinus Torvalds goto got_it;
2601da177e4SLinus Torvalds err = -EEXIST;
261939b00dfSAndries Brouwer if (namecompare(namelen, sbi->s_namelen, name, namx))
2621da177e4SLinus Torvalds goto out_unlock;
2631da177e4SLinus Torvalds }
2641da177e4SLinus Torvalds unlock_page(page);
2651da177e4SLinus Torvalds dir_put_page(page);
2661da177e4SLinus Torvalds }
2671da177e4SLinus Torvalds BUG();
2681da177e4SLinus Torvalds return -EINVAL;
2691da177e4SLinus Torvalds
2701da177e4SLinus Torvalds got_it:
271d6b54841SEvgeniy Dushistov pos = page_offset(page) + p - (char *)page_address(page);
272f4e420dcSChristoph Hellwig err = minix_prepare_chunk(page, pos, sbi->s_dirsize);
2731da177e4SLinus Torvalds if (err)
2741da177e4SLinus Torvalds goto out_unlock;
275939b00dfSAndries Brouwer memcpy (namx, name, namelen);
276939b00dfSAndries Brouwer if (sbi->s_version == MINIX_V3) {
277939b00dfSAndries Brouwer memset (namx + namelen, 0, sbi->s_dirsize - namelen - 4);
278939b00dfSAndries Brouwer de3->inode = inode->i_ino;
279939b00dfSAndries Brouwer } else {
280939b00dfSAndries Brouwer memset (namx + namelen, 0, sbi->s_dirsize - namelen - 2);
2811da177e4SLinus Torvalds de->inode = inode->i_ino;
282939b00dfSAndries Brouwer }
283f556e776SChristoph Hellwig dir_commit_chunk(page, pos, sbi->s_dirsize);
284*f7f43858SJeff Layton dir->i_mtime = inode_set_ctime_current(dir);
2851da177e4SLinus Torvalds mark_inode_dirty(dir);
286f556e776SChristoph Hellwig err = minix_handle_dirsync(dir);
2871da177e4SLinus Torvalds out_put:
2881da177e4SLinus Torvalds dir_put_page(page);
2891da177e4SLinus Torvalds out:
2901da177e4SLinus Torvalds return err;
2911da177e4SLinus Torvalds out_unlock:
2921da177e4SLinus Torvalds unlock_page(page);
2931da177e4SLinus Torvalds goto out_put;
2941da177e4SLinus Torvalds }
2951da177e4SLinus Torvalds
minix_delete_entry(struct minix_dir_entry * de,struct page * page)2961da177e4SLinus Torvalds int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
2971da177e4SLinus Torvalds {
298f4e420dcSChristoph Hellwig struct inode *inode = page->mapping->host;
2991da177e4SLinus Torvalds char *kaddr = page_address(page);
3004a66af9eSNick Piggin loff_t pos = page_offset(page) + (char*)de - kaddr;
3019f6c1333SDoug Graham struct minix_sb_info *sbi = minix_sb(inode->i_sb);
3029f6c1333SDoug Graham unsigned len = sbi->s_dirsize;
3031da177e4SLinus Torvalds int err;
3041da177e4SLinus Torvalds
3051da177e4SLinus Torvalds lock_page(page);
306f4e420dcSChristoph Hellwig err = minix_prepare_chunk(page, pos, len);
307b61d15d5SChristoph Hellwig if (err) {
308b61d15d5SChristoph Hellwig unlock_page(page);
309b61d15d5SChristoph Hellwig return err;
310b61d15d5SChristoph Hellwig }
3119f6c1333SDoug Graham if (sbi->s_version == MINIX_V3)
3129f6c1333SDoug Graham ((minix3_dirent *)de)->inode = 0;
3139f6c1333SDoug Graham else
3141da177e4SLinus Torvalds de->inode = 0;
315f556e776SChristoph Hellwig dir_commit_chunk(page, pos, len);
316*f7f43858SJeff Layton inode->i_mtime = inode_set_ctime_current(inode);
3171da177e4SLinus Torvalds mark_inode_dirty(inode);
318f556e776SChristoph Hellwig return minix_handle_dirsync(inode);
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds
minix_make_empty(struct inode * inode,struct inode * dir)3211da177e4SLinus Torvalds int minix_make_empty(struct inode *inode, struct inode *dir)
3221da177e4SLinus Torvalds {
323f4e420dcSChristoph Hellwig struct page *page = grab_cache_page(inode->i_mapping, 0);
3241da177e4SLinus Torvalds struct minix_sb_info *sbi = minix_sb(inode->i_sb);
3251da177e4SLinus Torvalds char *kaddr;
3261da177e4SLinus Torvalds int err;
3271da177e4SLinus Torvalds
3281da177e4SLinus Torvalds if (!page)
3291da177e4SLinus Torvalds return -ENOMEM;
330f4e420dcSChristoph Hellwig err = minix_prepare_chunk(page, 0, 2 * sbi->s_dirsize);
3311da177e4SLinus Torvalds if (err) {
3321da177e4SLinus Torvalds unlock_page(page);
3331da177e4SLinus Torvalds goto fail;
3341da177e4SLinus Torvalds }
3351da177e4SLinus Torvalds
33627a6d5c7SCong Wang kaddr = kmap_atomic(page);
33709cbfeafSKirill A. Shutemov memset(kaddr, 0, PAGE_SIZE);
3381da177e4SLinus Torvalds
339939b00dfSAndries Brouwer if (sbi->s_version == MINIX_V3) {
340939b00dfSAndries Brouwer minix3_dirent *de3 = (minix3_dirent *)kaddr;
341939b00dfSAndries Brouwer
342939b00dfSAndries Brouwer de3->inode = inode->i_ino;
343939b00dfSAndries Brouwer strcpy(de3->name, ".");
344939b00dfSAndries Brouwer de3 = minix_next_entry(de3, sbi);
345939b00dfSAndries Brouwer de3->inode = dir->i_ino;
346939b00dfSAndries Brouwer strcpy(de3->name, "..");
347939b00dfSAndries Brouwer } else {
348939b00dfSAndries Brouwer minix_dirent *de = (minix_dirent *)kaddr;
349939b00dfSAndries Brouwer
3501da177e4SLinus Torvalds de->inode = inode->i_ino;
3511da177e4SLinus Torvalds strcpy(de->name, ".");
3521da177e4SLinus Torvalds de = minix_next_entry(de, sbi);
3531da177e4SLinus Torvalds de->inode = dir->i_ino;
3541da177e4SLinus Torvalds strcpy(de->name, "..");
355939b00dfSAndries Brouwer }
35627a6d5c7SCong Wang kunmap_atomic(kaddr);
3571da177e4SLinus Torvalds
358f556e776SChristoph Hellwig dir_commit_chunk(page, 0, 2 * sbi->s_dirsize);
359f556e776SChristoph Hellwig err = minix_handle_dirsync(inode);
3601da177e4SLinus Torvalds fail:
36109cbfeafSKirill A. Shutemov put_page(page);
3621da177e4SLinus Torvalds return err;
3631da177e4SLinus Torvalds }
3641da177e4SLinus Torvalds
3651da177e4SLinus Torvalds /*
3661da177e4SLinus Torvalds * routine to check that the specified directory is empty (for rmdir)
3671da177e4SLinus Torvalds */
minix_empty_dir(struct inode * inode)3681da177e4SLinus Torvalds int minix_empty_dir(struct inode * inode)
3691da177e4SLinus Torvalds {
3701da177e4SLinus Torvalds struct page *page = NULL;
3711da177e4SLinus Torvalds unsigned long i, npages = dir_pages(inode);
3721da177e4SLinus Torvalds struct minix_sb_info *sbi = minix_sb(inode->i_sb);
373939b00dfSAndries Brouwer char *name;
374939b00dfSAndries Brouwer __u32 inumber;
3751da177e4SLinus Torvalds
3761da177e4SLinus Torvalds for (i = 0; i < npages; i++) {
377939b00dfSAndries Brouwer char *p, *kaddr, *limit;
3781da177e4SLinus Torvalds
379939b00dfSAndries Brouwer page = dir_get_page(inode, i);
3801da177e4SLinus Torvalds if (IS_ERR(page))
3811da177e4SLinus Torvalds continue;
3821da177e4SLinus Torvalds
3831da177e4SLinus Torvalds kaddr = (char *)page_address(page);
384939b00dfSAndries Brouwer limit = kaddr + minix_last_byte(inode, i) - sbi->s_dirsize;
385939b00dfSAndries Brouwer for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) {
386939b00dfSAndries Brouwer if (sbi->s_version == MINIX_V3) {
387939b00dfSAndries Brouwer minix3_dirent *de3 = (minix3_dirent *)p;
388939b00dfSAndries Brouwer name = de3->name;
389939b00dfSAndries Brouwer inumber = de3->inode;
390939b00dfSAndries Brouwer } else {
391939b00dfSAndries Brouwer minix_dirent *de = (minix_dirent *)p;
392939b00dfSAndries Brouwer name = de->name;
393939b00dfSAndries Brouwer inumber = de->inode;
394939b00dfSAndries Brouwer }
3951da177e4SLinus Torvalds
396939b00dfSAndries Brouwer if (inumber != 0) {
3971da177e4SLinus Torvalds /* check for . and .. */
398939b00dfSAndries Brouwer if (name[0] != '.')
3991da177e4SLinus Torvalds goto not_empty;
400939b00dfSAndries Brouwer if (!name[1]) {
401939b00dfSAndries Brouwer if (inumber != inode->i_ino)
4021da177e4SLinus Torvalds goto not_empty;
403939b00dfSAndries Brouwer } else if (name[1] != '.')
4041da177e4SLinus Torvalds goto not_empty;
405939b00dfSAndries Brouwer else if (name[2])
4061da177e4SLinus Torvalds goto not_empty;
4071da177e4SLinus Torvalds }
4081da177e4SLinus Torvalds }
4091da177e4SLinus Torvalds dir_put_page(page);
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds return 1;
4121da177e4SLinus Torvalds
4131da177e4SLinus Torvalds not_empty:
4141da177e4SLinus Torvalds dir_put_page(page);
4151da177e4SLinus Torvalds return 0;
4161da177e4SLinus Torvalds }
4171da177e4SLinus Torvalds
4181da177e4SLinus Torvalds /* Releases the page */
minix_set_link(struct minix_dir_entry * de,struct page * page,struct inode * inode)4192d1a9d59SChristoph Hellwig int minix_set_link(struct minix_dir_entry *de, struct page *page,
4201da177e4SLinus Torvalds struct inode *inode)
4211da177e4SLinus Torvalds {
422f4e420dcSChristoph Hellwig struct inode *dir = page->mapping->host;
4231da177e4SLinus Torvalds struct minix_sb_info *sbi = minix_sb(dir->i_sb);
4244a66af9eSNick Piggin loff_t pos = page_offset(page) +
4254a66af9eSNick Piggin (char *)de-(char*)page_address(page);
4261da177e4SLinus Torvalds int err;
4271da177e4SLinus Torvalds
4281da177e4SLinus Torvalds lock_page(page);
429f4e420dcSChristoph Hellwig err = minix_prepare_chunk(page, pos, sbi->s_dirsize);
4302d1a9d59SChristoph Hellwig if (err) {
4312d1a9d59SChristoph Hellwig unlock_page(page);
4322d1a9d59SChristoph Hellwig return err;
4332d1a9d59SChristoph Hellwig }
4349f6c1333SDoug Graham if (sbi->s_version == MINIX_V3)
4359f6c1333SDoug Graham ((minix3_dirent *)de)->inode = inode->i_ino;
4369f6c1333SDoug Graham else
4371da177e4SLinus Torvalds de->inode = inode->i_ino;
438f556e776SChristoph Hellwig dir_commit_chunk(page, pos, sbi->s_dirsize);
439*f7f43858SJeff Layton dir->i_mtime = inode_set_ctime_current(dir);
4401da177e4SLinus Torvalds mark_inode_dirty(dir);
441f556e776SChristoph Hellwig return minix_handle_dirsync(dir);
4421da177e4SLinus Torvalds }
4431da177e4SLinus Torvalds
minix_dotdot(struct inode * dir,struct page ** p)4441da177e4SLinus Torvalds struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p)
4451da177e4SLinus Torvalds {
4461da177e4SLinus Torvalds struct page *page = dir_get_page(dir, 0);
4471da177e4SLinus Torvalds struct minix_sb_info *sbi = minix_sb(dir->i_sb);
4481da177e4SLinus Torvalds struct minix_dir_entry *de = NULL;
4491da177e4SLinus Torvalds
4501da177e4SLinus Torvalds if (!IS_ERR(page)) {
4511da177e4SLinus Torvalds de = minix_next_entry(page_address(page), sbi);
4521da177e4SLinus Torvalds *p = page;
4531da177e4SLinus Torvalds }
4541da177e4SLinus Torvalds return de;
4551da177e4SLinus Torvalds }
4561da177e4SLinus Torvalds
minix_inode_by_name(struct dentry * dentry)4571da177e4SLinus Torvalds ino_t minix_inode_by_name(struct dentry *dentry)
4581da177e4SLinus Torvalds {
4591da177e4SLinus Torvalds struct page *page;
4601da177e4SLinus Torvalds struct minix_dir_entry *de = minix_find_entry(dentry, &page);
4611da177e4SLinus Torvalds ino_t res = 0;
4621da177e4SLinus Torvalds
4631da177e4SLinus Torvalds if (de) {
4649f6c1333SDoug Graham struct address_space *mapping = page->mapping;
4659f6c1333SDoug Graham struct inode *inode = mapping->host;
4669f6c1333SDoug Graham struct minix_sb_info *sbi = minix_sb(inode->i_sb);
4679f6c1333SDoug Graham
4689f6c1333SDoug Graham if (sbi->s_version == MINIX_V3)
4699f6c1333SDoug Graham res = ((minix3_dirent *) de)->inode;
4709f6c1333SDoug Graham else
4711da177e4SLinus Torvalds res = de->inode;
4721da177e4SLinus Torvalds dir_put_page(page);
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds return res;
4751da177e4SLinus Torvalds }
476