static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err) { #ifdef EXT2FS_DEBUG static unsigned long alloc_hits = 0, alloc_attempts = 0; #endif unsigned long result; #ifdef EXT2_PREALLOCATE /* Writer: ->i_prealloc* */ if (inode->u.ext2_i.i_prealloc_count && (goal == inode->u.ext2_i.i_prealloc_block || goal + 1 == inode->u.ext2_i.i_prealloc_block)) { result = inode->u.ext2_i.i_prealloc_block++; inode->u.ext2_i.i_prealloc_count--; /* Writer: end */ ext2_debug ("preallocation hit (%lu/%lu).\n", ++alloc_hits, ++alloc_attempts); } else { ext2_discard_prealloc (inode); ext2_debug ("preallocation miss (%lu/%lu).\n", alloc_hits, ++alloc_attempts); if (S_ISREG(inode->i_mode)) result = ext2_new_block (inode, goal, &inode->u.ext2_i.i_prealloc_count, &inode->u.ext2_i.i_prealloc_block, err); else result = ext2_new_block (inode, goal, 0, 0, err); } #else result = ext2_new_block (inode, goal, 0, 0, err); #endif return result; }
/* * COMP3301 Addition * Write immediate files data to the inode. Covert back to * Regular files when the data exceeds the limit. */ ssize_t do_immediate_write (struct file* flip, const char __user* buf, size_t len, loff_t *ppos, int need_to_encrypt) { struct ext2_inode_info *inode_info = EXT2_I(flip->f_dentry->d_inode); struct inode *inode = flip->f_dentry->d_inode; char *data = (char *)inode_info->i_data; char *copy; char *ext_inode_data = (char *) (EXT2_I(inode)->i_data); int err; ssize_t result; if (*ppos + len >= IMMEDIATE_FILE_SIZE) { // Convert to regular file copy = (char *) kmalloc(sizeof(char) * strlen(ext_inode_data) + 1, GFP_KERNEL); memset(copy, 0, strlen(ext_inode_data) + 1); memcpy(copy, ext_inode_data, strlen(ext_inode_data)); copy[strlen(ext_inode_data)] = 0; inode->i_mode &= ~(S_IF_IMMEDIATE & S_IFMT); inode->i_mode |= S_IFREG & S_IFMT; inode_info->i_data[0] = ext2_new_block(inode, 0, &err); mark_inode_dirty(inode); flip->f_pos = 0; result = write_encrypt(flip, copy, strlen(copy), &flip->f_pos); result = write_encrypt(flip, buf, len, ppos); kfree(copy); return result; } if (need_to_encrypt) { encrypt(buf, len); } if (copy_from_user(data + *ppos, buf, len)) { return -1; } *ppos += len; flip->f_pos = *ppos; inode->i_size += len; mark_inode_dirty(inode); return len; }
/* * This function zeros out the allocated block, and updates all of the * appropriate filesystem records. */ bool ext2_alloc_block(PEXT2_FILESYS fs, ULONG goal, ULONG *ret) { bool retval; ULONG block; char *buf = NULL; buf = (char *)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize); if (!buf) return false; if (!fs->block_map) { retval = ext2_read_block_bitmap(fs); if (!retval) goto fail; } retval = ext2_new_block(fs, goal, 0, &block); if (!retval) goto fail; retval = NT_SUCCESS(Ext2WriteDisk( fs, ((LONGLONG)block * fs->blocksize), fs->blocksize, (unsigned char *)buf)); if (!retval) { goto fail; } ext2_block_alloc_stats(fs, block, +1); *ret = block; if (buf) { RtlFreeHeap(RtlGetProcessHeap(), 0, buf); } return true; fail: if (buf) { RtlFreeHeap(RtlGetProcessHeap(), 0, buf); } return false; }
static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err) { #ifdef EXT2FS_DEBUG static unsigned long alloc_hits, alloc_attempts; #endif unsigned long result; #ifdef EXT2_PREALLOCATE struct ext2_inode_info *ei = EXT2_I(inode); write_lock(&ei->i_meta_lock); if (ei->i_prealloc_count && (goal == ei->i_prealloc_block || goal + 1 == ei->i_prealloc_block)) { result = ei->i_prealloc_block++; ei->i_prealloc_count--; write_unlock(&ei->i_meta_lock); ext2_debug ("preallocation hit (%lu/%lu).\n", ++alloc_hits, ++alloc_attempts); } else { write_unlock(&ei->i_meta_lock); ext2_discard_prealloc (inode); ext2_debug ("preallocation miss (%lu/%lu).\n", alloc_hits, ++alloc_attempts); if (S_ISREG(inode->i_mode)) result = ext2_new_block (inode, goal, &ei->i_prealloc_count, &ei->i_prealloc_block, err); else result = ext2_new_block(inode, goal, NULL, NULL, err); } #else result = ext2_new_block (inode, goal, 0, 0, err); #endif return result; }
/* * Allocate a block in the file system. * * this takes the framework from ffs_alloc. To implement the * actual allocation, it calls ext2_new_block, the ported version * of the same Linux routine. * * we note that this is always called in connection with ext2_blkpref * * preallocation is done as Linux does it */ int ext2_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, int size, struct ucred *cred, daddr_t *bnp) { struct ext2_sb_info *fs; daddr_t bno; #if QUOTA int error; #endif *bnp = 0; fs = ip->i_e2fs; #if DIAGNOSTIC if ((u_int)size > fs->s_blocksize || blkoff(fs, size) != 0) { kprintf("dev = %s, bsize = %lu, size = %d, fs = %s\n", devtoname(ip->i_dev), fs->s_blocksize, size, fs->fs_fsmnt); panic("ext2_alloc: bad size"); } if (cred == NOCRED) panic("ext2_alloc: missing credential"); #endif /* DIAGNOSTIC */ if (size == fs->s_blocksize && fs->s_es->s_free_blocks_count == 0) goto nospace; if (cred->cr_uid != 0 && fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count) goto nospace; #if QUOTA if ((error = ext2_chkdq(ip, (long)btodb(size), cred, 0)) != 0) return (error); #endif if (bpref >= fs->s_es->s_blocks_count) bpref = 0; /* call the Linux code */ #ifdef EXT2_PREALLOCATE /* To have a preallocation hit, we must * - have at least one block preallocated * - and our preferred block must have that block number or one below */ if (ip->i_prealloc_count && (bpref == ip->i_prealloc_block || bpref + 1 == ip->i_prealloc_block)) { bno = ip->i_prealloc_block++; ip->i_prealloc_count--; /* ext2_debug ("preallocation hit (%lu/%lu).\n", ++alloc_hits, ++alloc_attempts); */ /* Linux gets, clears, and releases the buffer at this point - we don't have to that; we leave it to the caller */ } else { ext2_discard_prealloc (ip); /* ext2_debug ("preallocation miss (%lu/%lu).\n", alloc_hits, ++alloc_attempts); */ if (S_ISREG(ip->i_mode)) bno = ext2_new_block (ITOV(ip)->v_mount, bpref, &ip->i_prealloc_count, &ip->i_prealloc_block); else bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount, bpref, 0, 0); } #else bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount, bpref, 0, 0); #endif if (bno > 0) { /* set next_alloc fields as done in block_getblk */ ip->i_next_alloc_block = lbn; ip->i_next_alloc_goal = bno; ip->i_blocks += btodb(size); ip->i_flag |= IN_CHANGE | IN_UPDATE; *bnp = bno; return (0); } #if QUOTA /* * Restore user's disk quota because allocation failed. */ ext2_chkdq(ip, (long)-btodb(size), cred, FORCE); #endif nospace: ext2_fserr(fs, cred->cr_uid, "file system full"); uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); return (ENOSPC); }