#include <asm/segment.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/mm.h>
static int ext2_update_inode(struct inode * inode, int do_sync);
void ext2_put_inode (struct inode * inode)
{
/*
najpierw wyrzućmy bloki,
które były wcześniej dla tego i-węzła zaalokowane
*/
ext2_discard_prealloc (inode);
if (inode->i_nlink || inode->i_ino
== EXT2_ACL_IDX_INO ||
inode->i_ino == EXT2_ACL_DATA_INO)
return;
/*
- ustawmy
czas odłożenia i-węzła na dysk
- zaznaczmy,
że i-węzeł "brudny"
- zrzućmy
i-węzeł na dysk
*/
inode->u.ext2_i.i_dtime
= CURRENT_TIME;
inode->i_dirt = 1;
ext2_update_inode(inode,
IS_SYNC(inode));
/*
jeżeli i-węzeł ma jeszcze
jakieś bloki zaalokowane dla siebie - zwolnij je
*/
inode->i_size = 0;
if (inode->i_blocks)
ext2_truncate (inode);
/*
zwolnij i-ramkę
*/
ext2_free_inode (inode);
}
/*
makro inode_bmap zwraca blok o numerze
nr z tablicy bloków i-węzła
*/
#define inode_bmap(inode, nr) ((inode)->u.ext2_i.i_data[(nr)])
/*
block_bmap odpowiada
za odczyt z bufora zawierającego tablicę bloków i-węzła bloku (elementu
tej tablicy) o numerze nr
*/
static inline int block_bmap (struct buffer_head
* bh, int nr)
{
int tmp;
if (!bh)
return 0;
tmp = ((u32 *) bh->b_data)[nr];
brelse (bh);
return tmp;
}
/*
* ext2_discard_prealloc and ext2_alloc_block are atomic wrt.
the
* superblock in the same manner as are ext2_free_blocks and
* ext2_new_block. We just wait on the super rather than
locking it
* here, since ext2_new_block will do the necessary locking and
we
* can't block until then.
*/
void ext2_discard_prealloc (struct
inode * inode)
{
#ifdef EXT2_PREALLOCATE
unsigned short total;
/*
działamy jedynie, gdy
istnieją jakieś bloki zaalokowane z wyprzedzeniem
*/
if (inode->u.ext2_i.i_prealloc_count)
{
total = inode->u.ext2_i.i_prealloc_count;
inode->u.ext2_i.i_prealloc_count = 0;
/*
nakazujemy zwolnienie
wszystkich zaalokowanych z wyprzedzeniem bloków (total)
*/
ext2_free_blocks (inode, inode->u.ext2_i.i_prealloc_block, total);
}
#endif
}
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;
struct buffer_head * bh;
wait_on_super (inode->i_sb);
#ifdef EXT2_PREALLOCATE
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--;
ext2_debug ("preallocation hit (%lu/%lu).\n",
++alloc_hits, ++alloc_attempts);
/* It doesn't matter if we block in getblk() since
we have already atomically allocated the block, and
are only clearing it now. */
if (!(bh = getblk (inode->i_sb->s_dev, result,
inode->i_sb->s_blocksize))) {
ext2_error (inode->i_sb, "ext2_alloc_block",
"cannot get block %lu", result);
return 0;
}
memset(bh->b_data, 0, inode->i_sb->s_blocksize);
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 1);
brelse (bh);
} 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;
}
int ext2_bmap (struct inode * inode, int block)
{
int i;
int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
// ile adresów bloków na dysku mieści się w jednym
bloku
int addr_per_block_bits
= EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb); //
ile bitów zajmuje tak naprawdę addr_per_block
/*
jeżeli:
- numer
bloku jest niepoprawny (<0)
- lub
numer ten jest większy od liczby możliwych do zaadresowania bloków (także
przy użyciu pośrednich)
to wypisz uwagę i zwróć
0.
*/
if (block < 0) {
ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
return 0;
}
if (block >= EXT2_NDIR_BLOCKS
+ addr_per_block +
(1 << (addr_per_block_bits * 2)) +
((1 << (addr_per_block_bits * 2)) << addr_per_block_bits))
{
ext2_warning (inode->i_sb, "ext2_bmap", "block > big");
return 0;
}
/*
blok jest bezpośredni
- zwróć jego adres korzystając z informacji w inode
*/
if (block < EXT2_NDIR_BLOCKS)
return inode_bmap (inode, block);
block -= EXT2_NDIR_BLOCKS;
// blok nie jest bezpośredni - pomijamy wszystkie
bezpośrednie
if (block < addr_per_block)
{
/*
blok jest pojedynczo
pośredni
tzn. jego fizyczny
adres znajduje się w bloku o adresie będącym elementem numer EXT2_IND_BLOCK
w tablicy bloków i-węzła
*/
// odczytaj adres bloku
pojedynczo pośredniego z inode
i = inode_bmap (inode, EXT2_IND_BLOCK);
// jeżeli ten blok nie był
zaalokowany - zwróć 0
if (!i)
return 0;
// wczytaj blok pośredni z
dysku, a następnie wybierz z niego adres interesującego nas bloku i go
zwróć
return block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize), block);
}
/*
blok jest podwójnie
pośredni
*/
block -= addr_per_block;
// pomiń bloki pojedynczo pośrednie
if (block < (1 <<
(addr_per_block_bits * 2))) {
// odczytaj adres bloku podwójnie pośredniego na dysku
i = inode_bmap (inode, EXT2_DIND_BLOCK);
// jeżeli nie jest zaalokowany -
zwróć zero
if (!i)
return 0;
// odczytaj z bloku podwójnie pośredniego adres
bloku pojedynczo pośredniego
i = block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize),
block >> addr_per_block_bits);
// jeżeli nie zaalokowany -
zwróć zero
if (!i)
return 0;
// wczytaj z dysku blok pojedynczo pośredni i zwróć
adres bloku, o który nam chodzi
return block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize),
block & (addr_per_block - 1));
}
/*
jeżeli blok jest potrójnie
pośredni
*/
// pomiń bloki podwójnie pośrednie
block -= (1 << (addr_per_block_bits
* 2));
// znajdź adres bloku potrójnie pośredniego
i = inode_bmap (inode, EXT2_TIND_BLOCK);
// jeżeli nie zaalokowany - zwróć zero
if (!i)
return 0;
// wczytaj z dysku blok potrójnie pośredni i wysupłaj
z niego interesujący nas adres bloku podwójnie pośredniego
i = block_bmap (bread (inode->i_dev,
i, inode->i_sb->s_blocksize),
block >> (addr_per_block_bits * 2));
// jeżeli nie zaalokowany ten blok podwójnie
pośredni - zwróć 0
if (!i)
return 0;
// wczytaj z dysku blok podwójnie pośredni i
wysupłaj z niego adres bloku pojedynczo pośredniego
i = block_bmap (bread (inode->i_dev,
i, inode->i_sb->s_blocksize),
(block >> addr_per_block_bits) & (addr_per_block - 1));
// jeżeli pojedynczo pośredni nie zaalokowany
- zwróć 0
if (!i)
return 0;
// zwróć fizyczny adres szukanego bloku na dysku,
wysupłując go z odczytanego z dysku bloku pojedynczo pośredniego
return block_bmap (bread
(inode->i_dev, i, inode->i_sb->s_blocksize),
block & (addr_per_block - 1));
}
static struct buffer_head * inode_getblk (struct inode * inode, int
nr,
int create, int new_block, int * err)
{
u32 * p;
int tmp, goal = 0;
struct buffer_head * result;
int blocks = inode->i_sb->s_blocksize
/ 512;
p = inode->u.ext2_i.i_data
+ nr;
repeat:
tmp = *p;
if (tmp) {
result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
if (tmp == *p)
return result;
brelse (result);
goto repeat;
}
if (!create || new_block
>=
(current->rlim[RLIMIT_FSIZE].rlim_cur >>
EXT2_BLOCK_SIZE_BITS(inode->i_sb))) {
*err = -EFBIG;
return NULL;
}
if (inode->u.ext2_i.i_next_alloc_block
== new_block)
goal = inode->u.ext2_i.i_next_alloc_goal;
ext2_debug ("hint = %d,", goal);
if (!goal) {
for (tmp = nr - 1; tmp >= 0; tmp--) {
if (inode->u.ext2_i.i_data[tmp]) {
goal = inode->u.ext2_i.i_data[tmp];
break;
}
}
if (!goal)
goal = (inode->u.ext2_i.i_block_group *
EXT2_BLOCKS_PER_GROUP(inode->i_sb)) +
inode->i_sb->u.ext2_sb.s_es->s_first_data_block;
}
ext2_debug ("goal = %d.\n", goal);
tmp = ext2_alloc_block (inode,
goal, err);
if (!tmp)
return NULL;
result = getblk (inode->i_dev,
tmp, inode->i_sb->s_blocksize);
if (*p) {
ext2_free_blocks (inode, tmp, 1);
brelse (result);
goto repeat;
}
*p = tmp;
inode->u.ext2_i.i_next_alloc_block
= new_block;
inode->u.ext2_i.i_next_alloc_goal
= tmp;
inode->i_ctime = CURRENT_TIME;
inode->i_blocks += blocks;
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
ext2_sync_inode (inode);
else
inode->i_dirt = 1;
return result;
}
static struct buffer_head * block_getblk (struct inode * inode,
struct buffer_head * bh, int nr,
int create, int blocksize,
int new_block, int * err)
{
int tmp, goal = 0;
u32 * p;
struct buffer_head * result;
int blocks = inode->i_sb->s_blocksize
/ 512;
if (!bh)
return NULL;
if (!buffer_uptodate(bh))
{
ll_rw_block (READ, 1, &bh);
wait_on_buffer (bh);
if (!buffer_uptodate(bh)) {
brelse (bh);
return NULL;
}
}
p = (u32 *) bh->b_data +
nr;
repeat:
tmp = *p;
if (tmp) {
result = getblk (bh->b_dev, tmp, blocksize);
if (tmp == *p) {
brelse (bh);
return result;
}
brelse (result);
goto repeat;
}
if (!create || new_block
>=
(current->rlim[RLIMIT_FSIZE].rlim_cur >>
EXT2_BLOCK_SIZE_BITS(inode->i_sb))) {
brelse (bh);
*err = -EFBIG;
return NULL;
}
if (inode->u.ext2_i.i_next_alloc_block
== new_block)
goal = inode->u.ext2_i.i_next_alloc_goal;
if (!goal) {
for (tmp = nr - 1; tmp >= 0; tmp--) {
if (((u32 *) bh->b_data)[tmp]) {
goal = ((u32 *)bh->b_data)[tmp];
break;
}
}
if (!goal)
goal = bh->b_blocknr;
}
tmp = ext2_alloc_block (inode,
goal, err);
if (!tmp) {
brelse (bh);
return NULL;
}
result = getblk (bh->b_dev,
tmp, blocksize);
if (*p) {
ext2_free_blocks (inode, tmp, 1);
brelse (result);
goto repeat;
}
*p = tmp;
mark_buffer_dirty(bh, 1);
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
{
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
inode->i_ctime = CURRENT_TIME;
inode->i_blocks += blocks;
inode->i_dirt = 1;
inode->u.ext2_i.i_next_alloc_block
= new_block;
inode->u.ext2_i.i_next_alloc_goal
= tmp;
brelse (bh);
return result;
}
struct buffer_head * ext2_getblk (struct inode
* inode, long block,
int create, int * err)
{
struct buffer_head * bh;
unsigned long b;
unsigned long addr_per_block
= EXT2_ADDR_PER_BLOCK(inode->i_sb);
int addr_per_block_bits
= EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
/*sprawdzenie poprawnosci
adresu bloku*/
*err = -EIO;
if (block < 0) {
ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
return NULL;
}
if (block > EXT2_NDIR_BLOCKS
+ addr_per_block +
(1 << (addr_per_block_bits * 2)) +
((1 << (addr_per_block_bits * 2)) << addr_per_block_bits))
{
ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
return NULL;
}
/*
* If this is a sequential
block allocation, set the next_alloc_block
* to this block now
so that all the indblock and data block
* allocations use
the same goal zone
*/
ext2_debug ("block %lu, next
%lu, goal %lu.\n", block,
inode->u.ext2_i.i_next_alloc_block,
inode->u.ext2_i.i_next_alloc_goal);
if (block == inode->u.ext2_i.i_next_alloc_block
+ 1) {
inode->u.ext2_i.i_next_alloc_block++;
inode->u.ext2_i.i_next_alloc_goal++;
}
*err = -ENOSPC;
b = block;
if (block < EXT2_NDIR_BLOCKS)
return inode_getblk (inode, block, create, b, err);
block -= EXT2_NDIR_BLOCKS;
if (block < addr_per_block)
{
bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err);
return block_getblk (inode, bh, block, create,
inode->i_sb->s_blocksize, b, err);
}
block -= addr_per_block;
if (block < (1 <<
(addr_per_block_bits * 2))) {
bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err);
bh = block_getblk (inode, bh, block >> addr_per_block_bits,
create, inode->i_sb->s_blocksize, b, err);
return block_getblk (inode, bh, block & (addr_per_block - 1),
create, inode->i_sb->s_blocksize, b, err);
}
block -= (1 << (addr_per_block_bits
* 2));
bh = inode_getblk (inode,
EXT2_TIND_BLOCK, create, b, err);
bh = block_getblk (inode,
bh, block >> (addr_per_block_bits * 2),
create, inode->i_sb->s_blocksize, b, err);
bh = block_getblk (inode,
bh, (block >> addr_per_block_bits) & (addr_per_block - 1),
create, inode->i_sb->s_blocksize, b, err);
return block_getblk (inode,
bh, block & (addr_per_block - 1), create,
inode->i_sb->s_blocksize, b, err);
}
struct buffer_head * ext2_bread (struct inode
* inode, int block,
int create, int *err)
{
struct buffer_head * bh;
/*chce adres do bufora który
odpowiada zadanym danym(inode, block) */
bh = ext2_getblk (inode,
block, create, err);
/*nie dostalismy żadnego
bufora(nawet czystego) bądz dostalismy z aktualnymi danymi
*/
if (!bh || buffer_uptodate(bh))
return bh;
/*transfer z urządzenia
dyskowego*/
ll_rw_block (READ, 1, &bh);
wait_on_buffer (bh);
if (buffer_uptodate(bh))
return bh;
/*niepowodzenie: zwolnij
bufor */
brelse (bh);
*err = -EIO;
return NULL;
}
void ext2_read_inode (struct inode * inode)
{
struct buffer_head * bh;
struct ext2_inode * raw_inode;
unsigned long block_group;
unsigned long group_desc;
unsigned long desc;
unsigned long block;
unsigned long offset;
struct ext2_group_desc *
gdp;
/* gdy i-węzeł do aktualizacji
jest węzłem korzenia systemu plików lub znajduje się poza
grupą, do której ma należeć, wtedy błąd */
if ((inode->i_ino != EXT2_ROOT_INO
&& inode->i_ino != EXT2_ACL_IDX_INO &&
inode->i_ino != EXT2_ACL_DATA_INO &&
inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) {
ext2_error (inode->i_sb, "ext2_read_inode",
"bad inode number: %lu", inode->i_ino);
return;
}
/* obliczamy w której
grupie ma się znajdować nasz i-węzeł */
block_group = (inode->i_ino
- 1) / EXT2_INODES_PER_GROUP(inode->i_sb);
/* jeżeli numer grupy jest
poza dozwolonym przedziałem - błąd */
if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count)
ext2_panic (inode->i_sb, "ext2_read_inode",
"group >= groups count");
/* ładujemy deskryptor
grupy, w której występuje dany i-węzeł, do bufora bh, a potem pod
zmienną gdp */
group_desc = block_group
>> EXT2_DESC_PER_BLOCK_BITS(inode->i_sb);
desc = block_group &
(EXT2_DESC_PER_BLOCK(inode->i_sb) - 1);
bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc];
/* jeżeli
nie udało się wczytanie żądanego deskryptora do bufora - idz do etykiety
błąd */
if (!bh) {
ext2_error (inode->i_sb, "ext2_read_inode",
"Descriptor not loaded");
goto bad_inode;
}
gdp = (struct ext2_group_desc
*) bh->b_data;
/*
* Figure out the offset
within the block group inode table
*/
/* obliczamy:
offset : przesunięcie i-węzła licząc od początku tablicy
i-węzłów
block : w
którym konkretnie bloku znajduje się nasz i-węzeł */
offset = ((inode->i_ino
- 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) *
EXT2_INODE_SIZE(inode->i_sb);
block = gdp[desc].bg_inode_table
+
(offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
/* - odczytujemy zawartość
i-węzła z dysku do bufora bh - jeżeli to się nie udało -
zlaszamy błąd i idziemy do etykiety bad_inode(niepoprawny i-wezel), r*/
if (!(bh = bread (inode->i_dev,
block, inode->i_sb->s_blocksize))) {
ext2_error (inode->i_sb, "ext2_read_inode",
"unable to read inode block - "
"inode=%lu, block=%lu", inode->i_ino, block);
goto bad_inode;
}
/* raw_inode:
wczytany i-węzeł z dysku */
offset &= (EXT2_BLOCK_SIZE(inode->i_sb)
- 1);
raw_inode = (struct ext2_inode
*) (bh->b_data + offset);
/* zapełniamy strukturę inode(w
pamieci operacyjnej) danymi
z raw_inode( pochodzacymi
z podręcznej pamięci buforowej ) */
inode->i_mode = raw_inode->i_mode;
inode->i_uid = raw_inode->i_uid;
inode->i_gid = raw_inode->i_gid;
inode->i_nlink = raw_inode->i_links_count;
inode->i_size = raw_inode->i_size;
inode->i_atime = raw_inode->i_atime;
inode->i_ctime = raw_inode->i_ctime;
inode->i_mtime = raw_inode->i_mtime;
inode->u.ext2_i.i_dtime
= raw_inode->i_dtime;
inode->i_blksize = PAGE_SIZE;
/* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = raw_inode->i_blocks;
inode->i_version = ++event;
inode->u.ext2_i.i_new_inode
= 0;
inode->u.ext2_i.i_flags
= raw_inode->i_flags;
inode->u.ext2_i.i_faddr
= raw_inode->i_faddr;
inode->u.ext2_i.i_frag_no
= raw_inode->i_frag;
inode->u.ext2_i.i_frag_size
= raw_inode->i_fsize;
inode->u.ext2_i.i_osync
= 0;
inode->u.ext2_i.i_file_acl
= raw_inode->i_file_acl;
inode->u.ext2_i.i_dir_acl
= raw_inode->i_dir_acl;
inode->u.ext2_i.i_version
= raw_inode->i_version;
inode->u.ext2_i.i_block_group
= block_group;
inode->u.ext2_i.i_next_alloc_block
= 0;
inode->u.ext2_i.i_next_alloc_goal
= 0;
if (inode->u.ext2_i.i_prealloc_count)
ext2_error (inode->i_sb, "ext2_read_inode",
"New inode has non-zero prealloc count!");
/* ustaw tablicę i_node_mode:
- jeżeli i-węzeł określa urządzenie znakowe lub
blokowe - zapisz numer rzeczywistego urządzenia - w przeciwnym przypadku:
zapełnij ją
normalnie */
if (S_ISCHR(inode->i_mode)
|| S_ISBLK(inode->i_mode))
inode->i_rdev = to_kdev_t(raw_inode->i_block[0]);
else for (block = 0; block
< EXT2_N_BLOCKS; block++)
inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
brelse (bh);
inode->i_op = NULL;
if (inode->i_ino == EXT2_ACL_IDX_INO
||
inode->i_ino == EXT2_ACL_DATA_INO)
/* Nothing to do */ ;
/* W zależności
od rodzaju urzśdzenia na ktore wskazuje i-węzeł
(urządzenie znakowe, urządzenie
blokowe, katalog,link, fifo) przypisz
do i-węzła odpowiedni
zestaw funkcji , tj.podstaw wskaznik
do odpowiedniej struktury
inode_operations */
else if (S_ISREG(inode->i_mode))
inode->i_op = &ext2_file_inode_operations;
else if (S_ISDIR(inode->i_mode))
inode->i_op = &ext2_dir_inode_operations;
else if (S_ISLNK(inode->i_mode))
inode->i_op = &ext2_symlink_inode_operations;
else if (S_ISCHR(inode->i_mode))
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
/*ustaw flagi */
if (inode->u.ext2_i.i_flags
& EXT2_SYNC_FL)
inode->i_flags |= MS_SYNCHRONOUS;
if (inode->u.ext2_i.i_flags
& EXT2_APPEND_FL)
inode->i_flags |= S_APPEND;
if (inode->u.ext2_i.i_flags
& EXT2_IMMUTABLE_FL)
inode->i_flags |= S_IMMUTABLE;
if (inode->u.ext2_i.i_flags
& EXT2_NOATIME_FL)
inode->i_flags |= MS_NOATIME;
return;
bad_inode: /*przypadek bledu */
make_bad_inode(inode);
return;
}
static int ext2_update_inode(struct
inode * inode, int do_sync)
{
struct buffer_head * bh;
struct ext2_inode * raw_inode;
unsigned long block_group;
unsigned long group_desc;
unsigned long desc;
unsigned long block;
unsigned long offset;
int err = 0;
struct ext2_group_desc *
gdp;
/*
gdy i-węzeł do aktualizacji
jest węzłem korzenia systemu plików lub znajduje się poza grupą, do której
ma należeć, wtedy błąd (??? - dlaczego nie można zaktualizować
korzenia ?)
*/
if ((inode->i_ino != EXT2_ROOT_INO
&&
inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) {
ext2_error (inode->i_sb, "ext2_write_inode",
"bad inode number: %lu", inode->i_ino);
return 0;
}
/*
obliczamy w której grupie ma się
znajdować nasz i-węzeł
*/
block_group = (inode->i_ino -
1) / EXT2_INODES_PER_GROUP(inode->i_sb);
/*
jeżeli numer grupy jest poza dozwolonym przedziałem
- błąd
*/
if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count)
ext2_panic (inode->i_sb, "ext2_write_inode",
"group >= groups count");
/*
ładujemy deskryptor grupy, w której występuje
dany i-węzeł, do bufora bh, a potem pod zmienną gdp
*/
group_desc = block_group
>> EXT2_DESC_PER_BLOCK_BITS(inode->i_sb);
desc = block_group &
(EXT2_DESC_PER_BLOCK(inode->i_sb) - 1);
bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc];
// jeżeli
nie udało się wczytanie żądanego deskryptora do bufora - błąd
if (!bh)
ext2_panic (inode->i_sb, "ext2_write_inode",
"Descriptor not loaded");
gdp = (struct ext2_group_desc
*) bh->b_data;
/*
obliczamy:
offset : przesunięcie i-węzła licząc od
początku tablicy i-węzłów
block : w którym konkretnie bloku znajduje
się nasz i-węzeł
*/
offset = ((inode->i_ino
- 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) *
EXT2_INODE_SIZE(inode->i_sb);
block = gdp[desc].bg_inode_table
+
(offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
/*
- odczytujemy zawartość
i-węzła z dysku do bufora bh
- jeżeli to się nie udało
- powstała dziwna sytuacja - ktoś zarządził zapis i-węzła na dysk, ale
nie udało się go z dysku odczytać -> błąd(EIO), ale zaznaczamy i-węzeł
w pamięci jako "czysty", czyli zgodny z reprezentacją na dysku
*/
if (!(bh = bread (inode->i_dev,
block, inode->i_sb->s_blocksize))) {
ext2_error (inode->i_sb, "ext2_write_inode",
"unable to read inode block - "
"inode=%lu, block=%lu", inode->i_ino, block);
/*
* Unfortunately we're in a lose-lose situation. I think that
* keeping the inode in-core with the dirty bit set is
* the worse option, since that will soak up inodes until
* the end of the world. Clearing the dirty bit is nasty if
* we haven't succeeded in writing out, but it's less nasty
* than the alternative. -- sct
*/
inode->i_dirt = 0;
return -EIO;
}
/*
raw_inode:
wczytany i-węzeł z dysku
*/
offset &= EXT2_BLOCK_SIZE(inode->i_sb)
- 1;
raw_inode = (struct ext2_inode
*) (bh->b_data + offset);
/*
zapełniamy strukturę raw_inode
*/
raw_inode->i_mode = inode->i_mode;
raw_inode->i_uid = inode->i_uid;
raw_inode->i_gid = inode->i_gid;
raw_inode->i_links_count
= inode->i_nlink;
raw_inode->i_size = inode->i_size;
raw_inode->i_atime = inode->i_atime;
raw_inode->i_ctime = inode->i_ctime;
raw_inode->i_mtime = inode->i_mtime;
raw_inode->i_blocks = inode->i_blocks;
raw_inode->i_dtime = inode->u.ext2_i.i_dtime;
raw_inode->i_flags = inode->u.ext2_i.i_flags;
raw_inode->i_faddr = inode->u.ext2_i.i_faddr;
raw_inode->i_frag = inode->u.ext2_i.i_frag_no;
raw_inode->i_fsize = inode->u.ext2_i.i_frag_size;
raw_inode->i_file_acl =
inode->u.ext2_i.i_file_acl;
raw_inode->i_dir_acl = inode->u.ext2_i.i_dir_acl;
raw_inode->i_version = inode->u.ext2_i.i_version;
/*
aktualizuj tablicę i_block raw_inode:
- jeżeli i-węzeł określa urządzenie
znakowe lub blokowe - zapisz numer rzeczywistego urządzenia
- w przeciwnym przypadku: zapełnij
ją normalnie
*/
if (S_ISCHR(inode->i_mode)
|| S_ISBLK(inode->i_mode))
raw_inode->i_block[0] = kdev_t_to_nr(inode->i_rdev);
else for (block = 0; block
< EXT2_N_BLOCKS; block++)
raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
/*
- zaznacz, że trzeba zapisać
na dysk bufor bh ,który zawiera teraz zaktualizowanego i-węzła
- zaznacz i-węzeł - "czysty"
- jeżeli było żądanie synchronizacji
(do_sync) zażądaj zapisu na dysk i poczekaj, aż będzie wykonany
*/
mark_buffer_dirty(bh, 1);
inode->i_dirt = 0;
if (do_sync) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
if (buffer_req(bh) && !buffer_uptodate(bh)) {
ext2_error (inode->i_sb,
"IO error syncing ext2 inode ["
"%s:%08lx]\n",
kdevname(inode->i_dev), inode->i_ino);
err = -EIO;
}
}
// zwolnij bufor
brelse (bh);
return err;
}
void ext2_write_inode (struct inode *
inode)
{
ext2_update_inode (inode,
0); //
zero oznacza, że nie wymuszamy synchronizacji
}
int ext2_sync_inode (struct inode *inode)
{
return ext2_update_inode
(inode, 1); //
jeden - synchronizacja jest wymuszona
}