import qualified Data.ByteString.Char8 as B
import Data.List
import qualified Data.Vector.Unboxed as V
import qualified Data.Vector.Unboxed.Mutable as MV
import Data.Monoid((<>))
import Data.Function hiding ((&))
import Data.Graph as G
import Data.Array
import Debug.Trace

(&) :: a -> (a -> b) -> b
(&) a b = b a

infixl 1 &

readIntPair :: B.ByteString -> (Int,Int)
readIntPair s = p
    where
    Just p = do
        (n1, s') <- B.readInt s
        (n2, _ ) <- B.readInt (B.tail s')
        return (n1,n2)

main :: IO ()
main = do
    (n,m) <- fmap readIntPair B.getLine
    es <- fmap (map readIntPair . B.lines) B.getContents
    let g = G.buildG (1, n) es
    dp <- MV.replicate n (-1)
    let go :: Int -> IO Int
        go v = memoize (v-1) $ do
                let nexts = g ! v
                ds <- mapM go (g ! v) 
                pure $ 1 + maximum (-1:ds)
        memoize key action = do
            d <- MV.read dp key
            if d >= 0 
                then pure d
                else do 
                    r <- action
                    MV.write dp key r
                    pure r
    ans <- fmap maximum $ mapM go [1..n]
    print ans
    
