I've actually been reading up on this recently, and although it was specifically about ext2, I believe ext3 and ext4 are similar if not the same.
Let's call your physical hard disk
sda. At the highest level, your disk is first broken up into separate partitions. Each partition gets its own filesystem that decides how to manage files on that partition. For example, you might have Windows on
sda1 using the NTFS filesystem, Ubuntu on
sda2 using the ext4 filesystem, and Swap on
sda3 that doesn't use a filesystem. Near the beginning of
sda, before the partitions start, are two things. First, the boot sector, which your BIOS loads at startup and probably contains grub. Second, the partition table, which lists the details about where all the partitions begin and end on the disk. You can find out details about you partitions using
sudo fdisk -l.
Inside the ext4 partition on
sda2, the partition is further divided into block groups. Inside a block group is first the superblock, which gives important information about the filesystem and free space. After a few more areas used by the filesystem, are the inodes. Every inode includes a list of the locations of up to 12 data blocks. Each inode can also have a reference to up to three other inodes. The final area in the block group is for actual data, and is divided into blocks (typically 4KB each).
Every directory, file, and link has a unique inode. The data in files is contained in many different disk blocks that could be anywhere on the disk. The file's inode lists where to find all of the potentially scattered data blocks. Likewise, the contents of every directory are stored as data in the same way.
When you open a file, for example
/home/user/contacts.txt first the computer finds the inode for the root directory, which it always knows where to find. The inode lists the locations of all the data blocks that describe the contents of the directory. Then the computer searches the data blocks for an entry called "home". The entry for the
home directory tells it where to find the inode for
home on the disk. It then looks in that inode, searches the specified blocks for
user, and repeats the process to find the file
contacts.txt, whose inode lists the blocks that contain the file's contents.
If you want to move
/home, first you have to do everything described above to find the file's inode. Then the computer has to navigate to the inode for
/home (which will be fast because Linux maintains a cache of the inodes of recently accessed directories called the dentry cache), and adds
contacts.txt to the directory's data blocks. Then it has to navigate to the inode of
user and search its data blocks for
contacts.txt and delete its entry.
Therefore, if both locations are on the same partition, the file's data blocks are never actually moved. The inode reference for the file will simply be moved from the origin directory's data blocks to the destination directory's data blocks. If one location is on a different partition, which counts as an entirely separate file system, the file's inode entry will be deleted, its data blocks copied, and a new inode entry created in the relevant directory's data blocks.
There's also one more thing that goes on in the background on
ext4. It's called journaling, and it helps ensure filesystem integrity despite crashes. Any time a file operation occurs, the filesystem write an entry in the journal describing what it's going to do. The entry is only deleted once every operation it describes has been completed. In this way, when a computer starts up after a crash in the middle of file operations, it immediately sees outstanding entries in the journal and can attempt to fix the problems.
Source: Modern Operating Systems 3e by Andrew S. Tanenbaum