diff options
Diffstat (limited to 'fs/ufs/util.c')
-rw-r--r-- | fs/ufs/util.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/fs/ufs/util.c b/fs/ufs/util.c new file mode 100644 index 000000000000..59acc8f073ac --- /dev/null +++ b/fs/ufs/util.c @@ -0,0 +1,257 @@ +/* + * linux/fs/ufs/util.c + * + * Copyright (C) 1998 + * Daniel Pirkl <daniel.pirkl@email.cz> + * Charles University, Faculty of Mathematics and Physics + */ + +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/ufs_fs.h> +#include <linux/buffer_head.h> + +#include "swab.h" +#include "util.h" + +#undef UFS_UTILS_DEBUG + +#ifdef UFS_UTILS_DEBUG +#define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; +#else +#define UFSD(x) +#endif + + +struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi, + struct super_block *sb, u64 fragment, u64 size) +{ + struct ufs_buffer_head * ubh; + unsigned i, j ; + u64 count = 0; + if (size & ~uspi->s_fmask) + return NULL; + count = size >> uspi->s_fshift; + if (count > UFS_MAXFRAG) + return NULL; + ubh = (struct ufs_buffer_head *) + kmalloc (sizeof (struct ufs_buffer_head), GFP_KERNEL); + if (!ubh) + return NULL; + ubh->fragment = fragment; + ubh->count = count; + for (i = 0; i < count; i++) + if (!(ubh->bh[i] = sb_bread(sb, fragment + i))) + goto failed; + for (; i < UFS_MAXFRAG; i++) + ubh->bh[i] = NULL; + return ubh; +failed: + for (j = 0; j < i; j++) + brelse (ubh->bh[j]); + kfree(ubh); + return NULL; +} + +struct ufs_buffer_head * ubh_bread_uspi (struct ufs_sb_private_info * uspi, + struct super_block *sb, u64 fragment, u64 size) +{ + unsigned i, j; + u64 count = 0; + if (size & ~uspi->s_fmask) + return NULL; + count = size >> uspi->s_fshift; + if (count <= 0 || count > UFS_MAXFRAG) + return NULL; + USPI_UBH->fragment = fragment; + USPI_UBH->count = count; + for (i = 0; i < count; i++) + if (!(USPI_UBH->bh[i] = sb_bread(sb, fragment + i))) + goto failed; + for (; i < UFS_MAXFRAG; i++) + USPI_UBH->bh[i] = NULL; + return USPI_UBH; +failed: + for (j = 0; j < i; j++) + brelse (USPI_UBH->bh[j]); + return NULL; +} + +void ubh_brelse (struct ufs_buffer_head * ubh) +{ + unsigned i; + if (!ubh) + return; + for (i = 0; i < ubh->count; i++) + brelse (ubh->bh[i]); + kfree (ubh); +} + +void ubh_brelse_uspi (struct ufs_sb_private_info * uspi) +{ + unsigned i; + if (!USPI_UBH) + return; + for ( i = 0; i < USPI_UBH->count; i++ ) { + brelse (USPI_UBH->bh[i]); + USPI_UBH->bh[i] = NULL; + } +} + +void ubh_mark_buffer_dirty (struct ufs_buffer_head * ubh) +{ + unsigned i; + if (!ubh) + return; + for ( i = 0; i < ubh->count; i++ ) + mark_buffer_dirty (ubh->bh[i]); +} + +void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag) +{ + unsigned i; + if (!ubh) + return; + if (flag) { + for ( i = 0; i < ubh->count; i++ ) + set_buffer_uptodate (ubh->bh[i]); + } else { + for ( i = 0; i < ubh->count; i++ ) + clear_buffer_uptodate (ubh->bh[i]); + } +} + +void ubh_ll_rw_block (int rw, unsigned nr, struct ufs_buffer_head * ubh[]) +{ + unsigned i; + if (!ubh) + return; + for ( i = 0; i < nr; i++ ) + ll_rw_block (rw, ubh[i]->count, ubh[i]->bh); +} + +void ubh_wait_on_buffer (struct ufs_buffer_head * ubh) +{ + unsigned i; + if (!ubh) + return; + for ( i = 0; i < ubh->count; i++ ) + wait_on_buffer (ubh->bh[i]); +} + +unsigned ubh_max_bcount (struct ufs_buffer_head * ubh) +{ + unsigned i; + unsigned max = 0; + if (!ubh) + return 0; + for ( i = 0; i < ubh->count; i++ ) + if ( atomic_read(&ubh->bh[i]->b_count) > max ) + max = atomic_read(&ubh->bh[i]->b_count); + return max; +} + +void ubh_bforget (struct ufs_buffer_head * ubh) +{ + unsigned i; + if (!ubh) + return; + for ( i = 0; i < ubh->count; i++ ) if ( ubh->bh[i] ) + bforget (ubh->bh[i]); +} + +int ubh_buffer_dirty (struct ufs_buffer_head * ubh) +{ + unsigned i; + unsigned result = 0; + if (!ubh) + return 0; + for ( i = 0; i < ubh->count; i++ ) + result |= buffer_dirty(ubh->bh[i]); + return result; +} + +void _ubh_ubhcpymem_(struct ufs_sb_private_info * uspi, + unsigned char * mem, struct ufs_buffer_head * ubh, unsigned size) +{ + unsigned len, bhno; + if (size > (ubh->count << uspi->s_fshift)) + size = ubh->count << uspi->s_fshift; + bhno = 0; + while (size) { + len = min_t(unsigned int, size, uspi->s_fsize); + memcpy (mem, ubh->bh[bhno]->b_data, len); + mem += uspi->s_fsize; + size -= len; + bhno++; + } +} + +void _ubh_memcpyubh_(struct ufs_sb_private_info * uspi, + struct ufs_buffer_head * ubh, unsigned char * mem, unsigned size) +{ + unsigned len, bhno; + if (size > (ubh->count << uspi->s_fshift)) + size = ubh->count << uspi->s_fshift; + bhno = 0; + while (size) { + len = min_t(unsigned int, size, uspi->s_fsize); + memcpy (ubh->bh[bhno]->b_data, mem, len); + mem += uspi->s_fsize; + size -= len; + bhno++; + } +} + +dev_t +ufs_get_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi) +{ + __fs32 fs32; + dev_t dev; + + if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86) + fs32 = ufsi->i_u1.i_data[1]; + else + fs32 = ufsi->i_u1.i_data[0]; + fs32 = fs32_to_cpu(sb, fs32); + switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { + case UFS_ST_SUNx86: + case UFS_ST_SUN: + if ((fs32 & 0xffff0000) == 0 || + (fs32 & 0xffff0000) == 0xffff0000) + dev = old_decode_dev(fs32 & 0x7fff); + else + dev = MKDEV(sysv_major(fs32), sysv_minor(fs32)); + break; + + default: + dev = old_decode_dev(fs32); + break; + } + return dev; +} + +void +ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev) +{ + __fs32 fs32; + + switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { + case UFS_ST_SUNx86: + case UFS_ST_SUN: + fs32 = sysv_encode_dev(dev); + if ((fs32 & 0xffff8000) == 0) { + fs32 = old_encode_dev(dev); + } + break; + + default: + fs32 = old_encode_dev(dev); + break; + } + fs32 = cpu_to_fs32(sb, fs32); + if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86) + ufsi->i_u1.i_data[1] = fs32; + else + ufsi->i_u1.i_data[0] = fs32; +} |