All of lore.kernel.org
 help / color / mirror / Atom feed
* VFAT i_pos value
@ 2011-11-30 22:33 Kai Meyer
  2011-11-30 23:22 ` Abhijit Hoskeri
  2011-12-01 14:38 ` OGAWA Hirofumi
  0 siblings, 2 replies; 10+ messages in thread
From: Kai Meyer @ 2011-11-30 22:33 UTC (permalink / raw)
  To: kernelnewbies

I'm getting this error:
FAT: Filesystem error (dev sblsnap0)
     fat_get_cluster: invalid cluster chain (i_pos 523791)

I'm wondering if there was a way to figure out what sector is causing 
the error? I would like to try and track down what is changing that 
sector and fix the problem. Is there a straight forward way to convert 
i_pos to a sector value? I've been staring at the fat.c and fat.h code 
all morning, and I'm having trouble grok'ing the flow.

-Kai Meyer

^ permalink raw reply	[flat|nested] 10+ messages in thread

* VFAT i_pos value
  2011-11-30 22:33 VFAT i_pos value Kai Meyer
@ 2011-11-30 23:22 ` Abhijit Hoskeri
  2011-12-01 14:38 ` OGAWA Hirofumi
  1 sibling, 0 replies; 10+ messages in thread
From: Abhijit Hoskeri @ 2011-11-30 23:22 UTC (permalink / raw)
  To: kernelnewbies

On Wed, Nov 30, 2011 at 2:33 PM, Kai Meyer <kai@gnukai.com> wrote:
> I'm getting this error:
> FAT: Filesystem error (dev sblsnap0)
> ? ? fat_get_cluster: invalid cluster chain (i_pos 523791)

Do you know what file this error is related to?

If you do, then you could see which blocks belong to the file and
calculate the block based on the above offset and the filesystem block size.

Regards,
Abhijit

^ permalink raw reply	[flat|nested] 10+ messages in thread

* VFAT i_pos value
  2011-11-30 22:33 VFAT i_pos value Kai Meyer
  2011-11-30 23:22 ` Abhijit Hoskeri
@ 2011-12-01 14:38 ` OGAWA Hirofumi
  2011-12-01 16:38   ` Kai Meyer
  1 sibling, 1 reply; 10+ messages in thread
From: OGAWA Hirofumi @ 2011-12-01 14:38 UTC (permalink / raw)
  To: kernelnewbies

Kai Meyer <kai@gnukai.com> writes:

> I'm getting this error:
> FAT: Filesystem error (dev sblsnap0)
>      fat_get_cluster: invalid cluster chain (i_pos 523791)
>
> I'm wondering if there was a way to figure out what sector is causing 
> the error? I would like to try and track down what is changing that 
> sector and fix the problem. Is there a straight forward way to convert 
> i_pos to a sector value? I've been staring at the fat.c and fat.h code 
> all morning, and I'm having trouble grok'ing the flow.

The i_pos means directory entry (contains inode information in unix-fs)
position,

    block number == i_pos / (logical-blocksize / 32)
    offset       == i_pos & (logical-blocksize / 32)

the above position's directory entry contains information for
problematic file. This is how to use i_pos information.

FWIW, in this error case, the cluster chain in FAT table which is
pointed by that entry, it has invalid cluster value.

Thanks.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* VFAT i_pos value
  2011-12-01 14:38 ` OGAWA Hirofumi
@ 2011-12-01 16:38   ` Kai Meyer
  2011-12-01 19:20     ` OGAWA Hirofumi
  0 siblings, 1 reply; 10+ messages in thread
From: Kai Meyer @ 2011-12-01 16:38 UTC (permalink / raw)
  To: kernelnewbies

On 12/01/2011 07:38 AM, OGAWA Hirofumi wrote:
> Kai Meyer<kai@gnukai.com>  writes:
>
>> I'm getting this error:
>> FAT: Filesystem error (dev sblsnap0)
>>       fat_get_cluster: invalid cluster chain (i_pos 523791)
>>
>> I'm wondering if there was a way to figure out what sector is causing
>> the error? I would like to try and track down what is changing that
>> sector and fix the problem. Is there a straight forward way to convert
>> i_pos to a sector value? I've been staring at the fat.c and fat.h code
>> all morning, and I'm having trouble grok'ing the flow.
> The i_pos means directory entry (contains inode information in unix-fs)
> position,
>
>      block number == i_pos / (logical-blocksize / 32)
>      offset       == i_pos&  (logical-blocksize / 32)
>
> the above position's directory entry contains information for
> problematic file. This is how to use i_pos information.
>
> FWIW, in this error case, the cluster chain in FAT table which is
> pointed by that entry, it has invalid cluster value.
>
> Thanks.

If you would verify my math for me, I would appreciate it.

In this case, my logical block size is 4096, because byte 13 of the 8Gb 
file system is 8, and I take that to be 8 * 512, which is 4096. So:

block_number = 523791 / (4096 / 32) = 4092
offset = 523791 % (4096 / 32) = 15  // I assume you meant modulo in your 
original post, and not binary AND.

So if the block_number is 4092, I would multiply that by 8 (sectors per 
logical block) to get the sector number:
32736

Does the error indicate that sector contains the corrupted data? Or is 
it the sector that contains the information that points to the corrupted 
data? Or is it something entirely different?

-Kai Meyer

^ permalink raw reply	[flat|nested] 10+ messages in thread

* VFAT i_pos value
  2011-12-01 16:38   ` Kai Meyer
@ 2011-12-01 19:20     ` OGAWA Hirofumi
  2011-12-01 20:46       ` Kai Meyer
  0 siblings, 1 reply; 10+ messages in thread
From: OGAWA Hirofumi @ 2011-12-01 19:20 UTC (permalink / raw)
  To: kernelnewbies

Kai Meyer <kai@gnukai.com> writes:

>> The i_pos means directory entry (contains inode information in unix-fs)
>> position,
>>
>>      block number == i_pos / (logical-blocksize / 32)
>>      offset       == i_pos&  (logical-blocksize / 32)
>>
>> the above position's directory entry contains information for
>> problematic file. This is how to use i_pos information.
>>
>> FWIW, in this error case, the cluster chain in FAT table which is
>> pointed by that entry, it has invalid cluster value.
>>
>> Thanks.
>
> If you would verify my math for me, I would appreciate it.
>
> In this case, my logical block size is 4096, because byte 13 of the 8Gb 
> file system is 8, and I take that to be 8 * 512, which is 4096. So:
>
> block_number = 523791 / (4096 / 32) = 4092
> offset = 523791 % (4096 / 32) = 15  // I assume you meant modulo in your 
> original post, and not binary AND.

Whoops, you are right. (I forgot "-1")

> So if the block_number is 4092, I would multiply that by 8 (sectors per 
> logical block) to get the sector number:
> 32736

Right.

> Does the error indicate that sector contains the corrupted data?

No.

> Or is it the sector that contains the information that points to the
> corrupted data?

Right.

The i_pos is pointing a directory entry (include/linux/msdos_fs.h:
struct msdos_dir_entry).

And starthi (if FAT32) and start contain the pointer to next cluster
number. That message was outputted when walking in cluster chain.

If you want to see actual corrupted data, you can check the cluster
chain by pointing from that directory entry.

Thanks.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* VFAT i_pos value
  2011-12-01 19:20     ` OGAWA Hirofumi
@ 2011-12-01 20:46       ` Kai Meyer
  2011-12-03  6:20         ` OGAWA Hirofumi
  0 siblings, 1 reply; 10+ messages in thread
From: Kai Meyer @ 2011-12-01 20:46 UTC (permalink / raw)
  To: kernelnewbies



On 12/01/2011 12:20 PM, OGAWA Hirofumi wrote:
> Kai Meyer<kai@gnukai.com>  writes:
>
>>> The i_pos means directory entry (contains inode information in unix-fs)
>>> position,
>>>
>>>       block number == i_pos / (logical-blocksize / 32)
>>>       offset       == i_pos&   (logical-blocksize / 32)
>>>
>>> the above position's directory entry contains information for
>>> problematic file. This is how to use i_pos information.
>>>
>>> FWIW, in this error case, the cluster chain in FAT table which is
>>> pointed by that entry, it has invalid cluster value.
>>>
>>> Thanks.
>> If you would verify my math for me, I would appreciate it.
>>
>> In this case, my logical block size is 4096, because byte 13 of the 8Gb
>> file system is 8, and I take that to be 8 * 512, which is 4096. So:
>>
>> block_number = 523791 / (4096 / 32) = 4092
>> offset = 523791 % (4096 / 32) = 15  // I assume you meant modulo in your
>> original post, and not binary AND.
> Whoops, you are right. (I forgot "-1")
>
>> So if the block_number is 4092, I would multiply that by 8 (sectors per
>> logical block) to get the sector number:
>> 32736
> Right.
>
>> Does the error indicate that sector contains the corrupted data?
> No.
>
>> Or is it the sector that contains the information that points to the
>> corrupted data?
> Right.
>
> The i_pos is pointing a directory entry (include/linux/msdos_fs.h:
> struct msdos_dir_entry).
>
> And starthi (if FAT32) and start contain the pointer to next cluster
> number. That message was outputted when walking in cluster chain.
>
> If you want to see actual corrupted data, you can check the cluster
> chain by pointing from that directory entry.
>
> Thanks.

Thanks for the helpful response. I'm not entirely sure I understand the 
next part though. I hacked a dirty entry dumper tool:

#include <stdio.h>
#include <linux/msdos_fs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char** argv)
{
         off_t pos = atoi(argv[2]);
         unsigned long block;
         off_t sector;
         unsigned int offset;
         int fd = open(argv[1], O_RDONLY);
         char buf[512];
         struct msdos_dir_entry dirent;
         block = pos / (4096 / 32);
         sector = block * 8;
         offset = pos % (4096 / 32);
         printf("block %lu, sector %lu, offset %u\n", block, sector, 
offset);
         lseek(fd, sector * 512, SEEK_SET);
         if (read(fd, buf, 512) < 0) {
                 fprintf(stderr, "Unable to read from device %s\n", 
argv[1]);
                 return -1;
         }
         memcpy(&dirent, buf + offset, sizeof(dirent));
         printf("name      %s\n", dirent.name);
         printf("attr      %u\n", dirent.attr);
         printf("lcase     %u\n", dirent.lcase);
         printf("ctime_cs  %u\n", dirent.ctime_cs);
         printf("ctime     %u\n", dirent.ctime);
         printf("cdate     %u\n", dirent.cdate);
         printf("adate     %u\n", dirent.adate);
         printf("starthi   %u\n", dirent.starthi);
         printf("time      %u\n", dirent.time);
         printf("date      %u\n", dirent.date);
         printf("start     %u\n", dirent.start);
         printf("size      %u\n", dirent.size);
}

Here's what it outputs:

./vfat_entry /dev/sblsnap0 523793
block 4092, sector 32736, offset 17
name
attr      255
lcase     255
ctime_cs  255
ctime     12799
cdate     12670
adate     8224
starthi   8224
time      23072
date      21061
start     32
size      2171155456

So, I take starthi, and shift 16 bits left, then and in the start value. 
That should give me the byte address of the first cluster of the file, 
correct?

Then I need to follow the cluster chain until I get a bad value.

Thanks

^ permalink raw reply	[flat|nested] 10+ messages in thread

* VFAT i_pos value
  2011-12-01 20:46       ` Kai Meyer
@ 2011-12-03  6:20         ` OGAWA Hirofumi
  2011-12-03  6:23           ` OGAWA Hirofumi
  0 siblings, 1 reply; 10+ messages in thread
From: OGAWA Hirofumi @ 2011-12-03  6:20 UTC (permalink / raw)
  To: kernelnewbies

Kai Meyer <kai@gnukai.com> writes:

> Thanks for the helpful response. I'm not entirely sure I understand the 
> next part though. I hacked a dirty entry dumper tool:
>
> #include <stdio.h>
> #include <linux/msdos_fs.h>
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> #include <unistd.h>
> #include <string.h>
>
> int main(int argc, char** argv)
> {
>          off_t pos = atoi(argv[2]);
>          unsigned long block;
>          off_t sector;
>          unsigned int offset;
>          int fd = open(argv[1], O_RDONLY);
>          char buf[512];
>          struct msdos_dir_entry dirent;
>          block = pos / (4096 / 32);
>          sector = block * 8;
>          offset = pos % (4096 / 32);
>          printf("block %lu, sector %lu, offset %u\n", block, sector, 
> offset);
>          lseek(fd, sector * 512, SEEK_SET);
>          if (read(fd, buf, 512) < 0) {
>                  fprintf(stderr, "Unable to read from device %s\n", 
> argv[1]);
>                  return -1;
>          }
>          memcpy(&dirent, buf + offset, sizeof(dirent));
>          printf("name      %s\n", dirent.name);
>          printf("attr      %u\n", dirent.attr);
>          printf("lcase     %u\n", dirent.lcase);
>          printf("ctime_cs  %u\n", dirent.ctime_cs);
>          printf("ctime     %u\n", dirent.ctime);
>          printf("cdate     %u\n", dirent.cdate);
>          printf("adate     %u\n", dirent.adate);
>          printf("starthi   %u\n", dirent.starthi);
>          printf("time      %u\n", dirent.time);
>          printf("date      %u\n", dirent.date);
>          printf("start     %u\n", dirent.start);
>          printf("size      %u\n", dirent.size);
> }
>
> Here's what it outputs:
>
> ./vfat_entry /dev/sblsnap0 523793
> block 4092, sector 32736, offset 17
> name
> attr      255
> lcase     255
> ctime_cs  255
> ctime     12799
> cdate     12670
> adate     8224
> starthi   8224
> time      23072
> date      21061
> start     32
> size      2171155456
>
> So, I take starthi, and shift 16 bits left, then and in the start value. 
> That should give me the byte address of the first cluster of the file, 
> correct?
>
> Then I need to follow the cluster chain until I get a bad value.

It looks like wrong as dirent. Did you use 523793 really? If so, I think
523791 is correct value. :)
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* VFAT i_pos value
  2011-12-03  6:20         ` OGAWA Hirofumi
@ 2011-12-03  6:23           ` OGAWA Hirofumi
  2011-12-08 21:35             ` Kai Meyer
  0 siblings, 1 reply; 10+ messages in thread
From: OGAWA Hirofumi @ 2011-12-03  6:23 UTC (permalink / raw)
  To: kernelnewbies

OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> writes:

> Kai Meyer <kai@gnukai.com> writes:
>
>> Thanks for the helpful response. I'm not entirely sure I understand the 
>> next part though. I hacked a dirty entry dumper tool:
>>
>> #include <stdio.h>
>> #include <linux/msdos_fs.h>
>> #include <sys/types.h>
>> #include <sys/stat.h>
>> #include <fcntl.h>
>> #include <unistd.h>
>> #include <string.h>
>>
>> int main(int argc, char** argv)
>> {
>>          off_t pos = atoi(argv[2]);
>>          unsigned long block;
>>          off_t sector;
>>          unsigned int offset;
>>          int fd = open(argv[1], O_RDONLY);
>>          char buf[512];
>>          struct msdos_dir_entry dirent;
>>          block = pos / (4096 / 32);
>>          sector = block * 8;
>>          offset = pos % (4096 / 32);
>>          printf("block %lu, sector %lu, offset %u\n", block, sector, 
>> offset);
>>          lseek(fd, sector * 512, SEEK_SET);
>>          if (read(fd, buf, 512) < 0) {
>>                  fprintf(stderr, "Unable to read from device %s\n", 
>> argv[1]);
>>                  return -1;
>>          }
>>          memcpy(&dirent, buf + offset, sizeof(dirent));
>>          printf("name      %s\n", dirent.name);
>>          printf("attr      %u\n", dirent.attr);
>>          printf("lcase     %u\n", dirent.lcase);
>>          printf("ctime_cs  %u\n", dirent.ctime_cs);
>>          printf("ctime     %u\n", dirent.ctime);
>>          printf("cdate     %u\n", dirent.cdate);
>>          printf("adate     %u\n", dirent.adate);
>>          printf("starthi   %u\n", dirent.starthi);
>>          printf("time      %u\n", dirent.time);
>>          printf("date      %u\n", dirent.date);
>>          printf("start     %u\n", dirent.start);
>>          printf("size      %u\n", dirent.size);
>> }
>>
>> Here's what it outputs:
>>
>> ./vfat_entry /dev/sblsnap0 523793
>> block 4092, sector 32736, offset 17
>> name
>> attr      255
>> lcase     255
>> ctime_cs  255
>> ctime     12799
>> cdate     12670
>> adate     8224
>> starthi   8224
>> time      23072
>> date      21061
>> start     32
>> size      2171155456
>>
>> So, I take starthi, and shift 16 bits left, then and in the start value. 
>> That should give me the byte address of the first cluster of the file, 
>> correct?
>>
>> Then I need to follow the cluster chain until I get a bad value.
>
> It looks like wrong as dirent. Did you use 523793 really? If so, I think
> 523791 is correct value. :)

And I didn't mention about offset correctly. offset means number of
entries, not bytes offset. So, bytes offset is "buf + offset * 32".
(32 == sizeof(struct msdos_dir_entry))

Thanks.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* VFAT i_pos value
  2011-12-03  6:23           ` OGAWA Hirofumi
@ 2011-12-08 21:35             ` Kai Meyer
  2011-12-09 11:01               ` OGAWA Hirofumi
  0 siblings, 1 reply; 10+ messages in thread
From: Kai Meyer @ 2011-12-08 21:35 UTC (permalink / raw)
  To: kernelnewbies



On 12/02/2011 11:23 PM, OGAWA Hirofumi wrote:
> OGAWA Hirofumi<hirofumi@mail.parknet.co.jp>  writes:
>
>> Kai Meyer<kai@gnukai.com>  writes:
>>
>>> Thanks for the helpful response. I'm not entirely sure I understand the
>>> next part though. I hacked a dirty entry dumper tool:
>>>
>>> #include<stdio.h>
>>> #include<linux/msdos_fs.h>
>>> #include<sys/types.h>
>>> #include<sys/stat.h>
>>> #include<fcntl.h>
>>> #include<unistd.h>
>>> #include<string.h>
>>>
>>> int main(int argc, char** argv)
>>> {
>>>           off_t pos = atoi(argv[2]);
>>>           unsigned long block;
>>>           off_t sector;
>>>           unsigned int offset;
>>>           int fd = open(argv[1], O_RDONLY);
>>>           char buf[512];
>>>           struct msdos_dir_entry dirent;
>>>           block = pos / (4096 / 32);
>>>           sector = block * 8;
>>>           offset = pos % (4096 / 32);
>>>           printf("block %lu, sector %lu, offset %u\n", block, sector,
>>> offset);
>>>           lseek(fd, sector * 512, SEEK_SET);
>>>           if (read(fd, buf, 512)<  0) {
>>>                   fprintf(stderr, "Unable to read from device %s\n",
>>> argv[1]);
>>>                   return -1;
>>>           }
>>>           memcpy(&dirent, buf + offset, sizeof(dirent));
>>>           printf("name      %s\n", dirent.name);
>>>           printf("attr      %u\n", dirent.attr);
>>>           printf("lcase     %u\n", dirent.lcase);
>>>           printf("ctime_cs  %u\n", dirent.ctime_cs);
>>>           printf("ctime     %u\n", dirent.ctime);
>>>           printf("cdate     %u\n", dirent.cdate);
>>>           printf("adate     %u\n", dirent.adate);
>>>           printf("starthi   %u\n", dirent.starthi);
>>>           printf("time      %u\n", dirent.time);
>>>           printf("date      %u\n", dirent.date);
>>>           printf("start     %u\n", dirent.start);
>>>           printf("size      %u\n", dirent.size);
>>> }
>>>
>>> Here's what it outputs:
>>>
>>> ./vfat_entry /dev/sblsnap0 523793
>>> block 4092, sector 32736, offset 17
>>> name
>>> attr      255
>>> lcase     255
>>> ctime_cs  255
>>> ctime     12799
>>> cdate     12670
>>> adate     8224
>>> starthi   8224
>>> time      23072
>>> date      21061
>>> start     32
>>> size      2171155456
>>>
>>> So, I take starthi, and shift 16 bits left, then and in the start value.
>>> That should give me the byte address of the first cluster of the file,
>>> correct?
>>>
>>> Then I need to follow the cluster chain until I get a bad value.
>> It looks like wrong as dirent. Did you use 523793 really? If so, I think
>> 523791 is correct value. :)
> And I didn't mention about offset correctly. offset means number of
> entries, not bytes offset. So, bytes offset is "buf + offset * 32".
> (32 == sizeof(struct msdos_dir_entry))
>
> Thanks.
Ok, I fixed the buf + offset * 32. I have a new volume, so the error is now:
fat_get_cluster: invalid cluster chain (i_pos 523781)

I added a few lines at the end to print the start value:
         pos = dirent.starthi << 16;
         pos |= dirent.start;
         printf("next pos: %u\n", sector);

[root at dev1 sblsnap]# ./vfat_entry /dev/sblsnap0 523781
block 4092, sector 32736, offset 5
name      3~1     ZER
attr      32
lcase     0
ctime_cs  100
ctime     29092
cdate     16264
adate     16264
starthi   4
time      29092
date      16264
start     7427
size      37748736
next pos: 32736
[root@dev1 sblsnap]# ./vfat_entry /dev/sblsnap0 32736
block 255, sector 2040, offset 96
name
attr      0
lcase     0
ctime_cs  0
ctime     0
cdate     0
adate     0
starthi   0
time      0
date      0
start     0
size      0
next pos: 2040

Does that look like what would be causing my error? meaning, sector 2040 
has bad data?

^ permalink raw reply	[flat|nested] 10+ messages in thread

* VFAT i_pos value
  2011-12-08 21:35             ` Kai Meyer
@ 2011-12-09 11:01               ` OGAWA Hirofumi
  0 siblings, 0 replies; 10+ messages in thread
From: OGAWA Hirofumi @ 2011-12-09 11:01 UTC (permalink / raw)
  To: kernelnewbies

Kai Meyer <kai@gnukai.com> writes:

> [root at dev1 sblsnap]# ./vfat_entry /dev/sblsnap0 523781
> block 4092, sector 32736, offset 5
> name      3~1     ZER
> attr      32
> lcase     0
> ctime_cs  100
> ctime     29092
> cdate     16264
> adate     16264
> starthi   4
> time      29092
> date      16264
> start     7427
> size      37748736
> next pos: 32736

Looks like sane entry.

> [root at dev1 sblsnap]# ./vfat_entry /dev/sblsnap0 32736
> block 255, sector 2040, offset 96
> name
> attr      0
> lcase     0
> ctime_cs  0
> ctime     0
> cdate     0
> adate     0
> starthi   0
> time      0
> date      0
> start     0
> size      0
> next pos: 2040
>
> Does that look like what would be causing my error? meaning, sector 2040 
> has bad data?

The next pos means the position of data cluster (i.e that entry is using
the cluster of this position to store data). You have to walk the
cluster position chain on FAT table, not directory entry.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-12-09 11:01 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-30 22:33 VFAT i_pos value Kai Meyer
2011-11-30 23:22 ` Abhijit Hoskeri
2011-12-01 14:38 ` OGAWA Hirofumi
2011-12-01 16:38   ` Kai Meyer
2011-12-01 19:20     ` OGAWA Hirofumi
2011-12-01 20:46       ` Kai Meyer
2011-12-03  6:20         ` OGAWA Hirofumi
2011-12-03  6:23           ` OGAWA Hirofumi
2011-12-08 21:35             ` Kai Meyer
2011-12-09 11:01               ` OGAWA Hirofumi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.