- unsigned long offset;
- unsigned short rec_len;
- struct page *page;
- struct ext2_dir_entry_2 * de, * de1;
- struct super_block * sb;
-
- ENTRY;
- *err = -EINVAL;
- *res_dir = NULL;
- if (!dir || !dir->i_nlink) {
- CDEBUG(D_INODE, "bad directory\n");
- EXIT;
- return NULL;
- }
- sb = dir->i_sb;
-
- if (!namelen) {
- CDEBUG(D_INODE, "bad directory\n");
- EXIT;
- return NULL;
- }
- /*
- * Is this a busy deleted directory? Can't create new files if so
- */
- if (dir->i_size == 0)
- {
- OIDEBUG(dir);
- *err = -ENOENT;
- EXIT;
- return NULL;
- }
- page = obdfs_getpage(dir, 0, 0, LOCKED);
- if (!page) {
- EXIT;
- return NULL;
- }
- rec_len = EXT2_DIR_REC_LEN(namelen);
- /* CDEBUG(D_INFO, "reclen: %d\n", rec_len); */
- /* PDEBUG(page, "starting search"); */
- offset = 0;
- de = (struct ext2_dir_entry_2 *) page_address(page);
- *err = -ENOSPC;
- while (1) {
- /* CDEBUG(D_INFO,
- "Entry at %p, (page at %#lx - %#lx), offset %ld\n",
- de, page_address(page), page_address(page) + PAGE_SIZE,
- offset); */
- if ((char *)de >= PAGE_SIZE + (char *)page_address(page)) {
- UnlockPage(page);
- page_cache_release(page);
- page = obdfs_getpage(dir, offset, 1, LOCKED);
- if (!page) {
- EXIT;
- return NULL;
- }
- /* PDEBUG(page, "new directory page"); */
- if (dir->i_size <= offset) {
- if (dir->i_size == 0) {
- *err = -ENOENT;
- EXIT;
- return NULL;
- }
-
- CDEBUG(D_INFO, "creating next block\n");
-
- de = (struct ext2_dir_entry_2 *) page_address(page);
- de->inode = 0;
- de->rec_len = cpu_to_le16(PAGE_SIZE);
- dir->i_size = offset + PAGE_SIZE;
- dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
- mark_inode_dirty(dir);
- } else {
-
- CDEBUG(D_INFO, "skipping to next block\n");
-
- de = (struct ext2_dir_entry_2 *) page_address(page);
- }
- }
- if (!obdfs_check_dir_entry ("ext2_add_entry", dir, de, page,
- offset)) {
- *err = -ENOENT;
- UnlockPage(page);
- page_cache_release(page);
- EXIT;
- return NULL;
- }
- CDEBUG(D_INFO, "\n");
- if (ext2_match (namelen, name, de)) {
- *err = -EEXIST;
- UnlockPage(page);
- page_cache_release(page);
- EXIT;
- return NULL;
- }
- /* CDEBUG(D_INFO, "Testing for enough space at de %p\n", de);*/
- if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
- (le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
- offset += le16_to_cpu(de->rec_len);
- /* CDEBUG(D_INFO,
- "Found enough space de %p, offset %#lx\n",
- de, offset); */
- if (le32_to_cpu(de->inode)) {
- /*CDEBUG(D_INFO, "Insert new in %p\n", de);*/
- de1 = (struct ext2_dir_entry_2 *) ((char *) de +
- EXT2_DIR_REC_LEN(de->name_len));
- /*CDEBUG(D_INFO, "-- de1 at %p\n", de1);*/
- de1->rec_len = cpu_to_le16(le16_to_cpu(de->rec_len) -
- EXT2_DIR_REC_LEN(de->name_len));
- de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
- de = de1;
- }
- /* CDEBUG(D_INFO,
- "Reclen adjusted; copy %d bytes to %p, "
- "page at %#lx EOP at %#lx\n",
- namelen, de->name, page_address(page),
- page_address(page) + PAGE_SIZE); */
- de->inode = 0;
- de->name_len = namelen;
- de->file_type = 0;
- memcpy (de->name, name, namelen);
- /*
- * XXX shouldn't update any times until successful
- * completion of syscall, but too many callers depend
- * on this.
- *
- * XXX similarly, too many callers depend on
- * ext2_new_inode() setting the times, but error
- * recovery deletes the inode, so the worst that can
- * happen is that the times are slightly out of date
- * and/or different from the directory change time.
- */
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
- dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
- mark_inode_dirty(dir);
- dir->i_version = ++event;
- *res_dir = de;
- *err = 0;
- /* PDEBUG(page, "add_entry"); */
- /* XXX unlock page here */
- EXIT;
- return page;
- }
- offset += le16_to_cpu(de->rec_len);
- de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
- }
-
- UnlockPage(page);
- page_cache_release(page);
- /* PDEBUG(page, "add_entry"); */
- EXIT;
- return NULL;
+ unsigned long offset;
+ unsigned short rec_len;
+ struct page *page;
+ struct ext2_dir_entry_2 * de, * de1;
+ struct super_block * sb;
+
+ ENTRY;
+ *err = -EINVAL;
+ *res_dir = NULL;
+ if (!dir || !dir->i_nlink) {
+ CDEBUG(D_INODE, "bad directory\n");
+ EXIT;
+ return NULL;
+ }
+ sb = dir->i_sb;
+
+ if (!namelen) {
+ CDEBUG(D_INODE, "bad directory\n");
+ EXIT;
+ return NULL;
+ }
+ /*
+ * Is this a busy deleted directory? Can't create new files if so
+ */
+ if (dir->i_size == 0)
+ {
+ OIDEBUG(dir);
+ *err = -ENOENT;
+ EXIT;
+ return NULL;
+ }
+ page = obdfs_getpage(dir, 0, 0, LOCKED);
+ if (!page) {
+ EXIT;
+ return NULL;
+ }
+ rec_len = EXT2_DIR_REC_LEN(namelen);
+ /* CDEBUG(D_INFO, "reclen: %d\n", rec_len); */
+ /* PDEBUG(page, "starting search"); */
+ offset = 0;
+ de = (struct ext2_dir_entry_2 *) page_address(page);
+ *err = -ENOSPC;
+ while (1) {
+ /* CDEBUG(D_INFO,
+ "Entry at %p, (page at %#lx - %#lx), offset %ld\n",
+ de, page_address(page), page_address(page) + PAGE_SIZE,
+ offset); */
+ if ((char *)de >= PAGE_SIZE + (char *)page_address(page)) {
+ obd_unlock_page(page);
+ page_cache_release(page);
+ page = obdfs_getpage(dir, offset, 1, LOCKED);
+ if (!page) {
+ EXIT;
+ return NULL;
+ }
+ /* PDEBUG(page, "new directory page"); */
+ if (dir->i_size <= offset) {
+ if (dir->i_size == 0) {
+ *err = -ENOENT;
+ EXIT;
+ return NULL;
+ }
+
+ CDEBUG(D_INFO, "creating next block\n");
+
+ de = (struct ext2_dir_entry_2 *) page_address(page);
+ de->inode = 0;
+ de->rec_len = cpu_to_le16(PAGE_SIZE);
+ dir->i_size = offset + PAGE_SIZE;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
+ mark_inode_dirty(dir);
+ } else {
+
+ CDEBUG(D_INFO, "skipping to next block\n");
+
+ de = (struct ext2_dir_entry_2 *) page_address(page);
+ }
+ }
+ if (!obdfs_check_dir_entry ("ext2_add_entry", dir, de, page,
+ offset)) {
+ *err = -ENOENT;
+ obd_unlock_page(page);
+ page_cache_release(page);
+ EXIT;
+ return NULL;
+ }
+ CDEBUG(D_INFO, "\n");
+ if (ext2_match (namelen, name, de)) {
+ *err = -EEXIST;
+ obd_unlock_page(page);
+ page_cache_release(page);
+ EXIT;
+ return NULL;
+ }
+ /* CDEBUG(D_INFO, "Testing for enough space at de %p\n", de);*/
+ if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
+ (le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
+ offset += le16_to_cpu(de->rec_len);
+ /* CDEBUG(D_INFO,
+ "Found enough space de %p, offset %#lx\n",
+ de, offset); */
+ if (le32_to_cpu(de->inode)) {
+ /*CDEBUG(D_INFO, "Insert new in %p\n", de);*/
+ de1 = (struct ext2_dir_entry_2 *) ((char *) de +
+ EXT2_DIR_REC_LEN(de->name_len));
+ /*CDEBUG(D_INFO, "-- de1 at %p\n", de1);*/
+ de1->rec_len = cpu_to_le16(le16_to_cpu(de->rec_len) -
+ EXT2_DIR_REC_LEN(de->name_len));
+ de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
+ de = de1;
+ }
+ /* CDEBUG(D_INFO,
+ "Reclen adjusted; copy %d bytes to %p, "
+ "page at %#lx EOP at %#lx\n",
+ namelen, de->name, page_address(page),
+ page_address(page) + PAGE_SIZE); */
+ de->inode = 0;
+ de->name_len = namelen;
+ de->file_type = 0;
+ memcpy (de->name, name, namelen);
+ /*
+ * XXX shouldn't update any times until successful
+ * completion of syscall, but too many callers depend
+ * on this.
+ *
+ * XXX similarly, too many callers depend on
+ * ext2_new_inode() setting the times, but error
+ * recovery deletes the inode, so the worst that can
+ * happen is that the times are slightly out of date
+ * and/or different from the directory change time.
+ */
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
+ mark_inode_dirty(dir);
+ dir->i_version = ++event;
+ *res_dir = de;
+ *err = 0;
+ PDEBUG(page, "add_entry");
+ /* XXX unlock page here */
+ EXIT;
+ return page;
+ }
+ offset += le16_to_cpu(de->rec_len);
+ de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+ }
+
+ obd_unlock_page(page);
+ page_cache_release(page);
+ /* PDEBUG(page, "add_entry"); */
+ EXIT;
+ return NULL;